From 4c2a6dd0915eeb17272859063bc11005e272b70a Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Wed, 29 Jul 2026 14:34:43 +0200 Subject: [PATCH] feat(host,api): the host knows what OS it runs, and says so MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clients want to show which OS/distro a host runs. The host now detects it once per process (new osinfo module: compile-time on Windows/macOS, os-release on Linux) and advertises an icon-friendly specificity chain, generic → specific — `windows`, `macos`, `linux[/][/]`, e.g. `linux/fedora/bazzite`, `linux/arch/steamos`. A client walks the chain most-specific-first and shows the first token it has art for, so an unknown distro degrades to its family's mark and finally to plain Tux — the host emits the full chain precisely so clients need zero distro→parent knowledge. The middle token is the first recognized ID_LIKE ancestor (the spec orders them most-similar-first); the leaf is ID verbatim, sanitized to TXT-safe `[a-z0-9._-]` because it feeds a DNS record. Two carriers, both additive: a new advisory mDNS `os=` TXT key (same trust posture as `mac` — unauthenticated, a wrong value only draws a wrong icon), and `HostInfo.os` + `HostInfo.os_name` on the mgmt API (`os_name` is the os-release PRETTY_NAME, REST-only so the TXT stays small). GameStream serverinfo and the QUIC Welcome are untouched. api/openapi.json regenerated (drift test green on Linux) and the TS SDK gen refreshed from it — which also catches the committed gen up with earlier spec changes it had missed (monitors, native_paired_clients, encoder_backend). assets/os-icons/ gains the ten master SVG marks every client derives its per-platform art from (Font Awesome Free brands CC BY 4.0 + Simple Icons CC0 — provenance in its README), with attribution folded into THIRD-PARTY-NOTICES.txt via the generator (regenerating also catches the stale crate manifest up with the current lockfile). Co-Authored-By: Claude Fable 5 --- THIRD-PARTY-NOTICES.txt | 1475 ++++++++--------- api/openapi.json | 12 + .../os-icons/LICENSES/font-awesome-brands.txt | 17 + assets/os-icons/LICENSES/simple-icons.txt | 10 + assets/os-icons/README.md | 30 + assets/os-icons/apple.svg | 2 + assets/os-icons/arch.svg | 2 + assets/os-icons/debian.svg | 2 + assets/os-icons/fedora.svg | 2 + assets/os-icons/linux.svg | 2 + assets/os-icons/nixos.svg | 2 + assets/os-icons/opensuse.svg | 2 + assets/os-icons/steam.svg | 2 + assets/os-icons/ubuntu.svg | 2 + assets/os-icons/windows.svg | 2 + crates/punktfunk-host/src/discovery.rs | 11 + crates/punktfunk-host/src/gamestream/mod.rs | 10 + .../punktfunk-host/src/gamestream/nvhttp.rs | 2 + .../src/gamestream/serverinfo.rs | 2 + crates/punktfunk-host/src/main.rs | 1 + crates/punktfunk-host/src/mgmt/host.rs | 10 + crates/punktfunk-host/src/mgmt/tests.rs | 6 + crates/punktfunk-host/src/native.rs | 1 + crates/punktfunk-host/src/osinfo.rs | 265 +++ scripts/gen-third-party-notices.py | 8 + sdk/src/gen/punktfunk.ts | 44 +- 26 files changed, 1119 insertions(+), 805 deletions(-) create mode 100644 assets/os-icons/LICENSES/font-awesome-brands.txt create mode 100644 assets/os-icons/LICENSES/simple-icons.txt create mode 100644 assets/os-icons/README.md create mode 100644 assets/os-icons/apple.svg create mode 100644 assets/os-icons/arch.svg create mode 100644 assets/os-icons/debian.svg create mode 100644 assets/os-icons/fedora.svg create mode 100644 assets/os-icons/linux.svg create mode 100644 assets/os-icons/nixos.svg create mode 100644 assets/os-icons/opensuse.svg create mode 100644 assets/os-icons/steam.svg create mode 100644 assets/os-icons/ubuntu.svg create mode 100644 assets/os-icons/windows.svg create mode 100644 crates/punktfunk-host/src/osinfo.rs diff --git a/THIRD-PARTY-NOTICES.txt b/THIRD-PARTY-NOTICES.txt index d1af6419..1420ab34 100644 --- a/THIRD-PARTY-NOTICES.txt +++ b/THIRD-PARTY-NOTICES.txt @@ -7,7 +7,7 @@ below. Each is distributed under its own permissive license; the full license te follow the manifest. This file is generated by scripts/gen-third-party-notices.py (or `cargo about`, see about.toml) — do not edit by hand. -Total third-party crates: 548 +Total third-party crates: 561 ---------------------------------------------------------------------------- VENDORED THIRD-PARTY SOURCE (inside first-party crates) @@ -16,6 +16,8 @@ VENDORED THIRD-PARTY SOURCE (inside first-party crates) Granite subset (vendored, crates/pyrowave-sys) — https://github.com/Themaister/Granite volk (vendored, crates/pyrowave-sys) — https://github.com/zeux/volk Vulkan-Headers (vendored, crates/pyrowave-sys) — https://github.com/KhronosGroup/Vulkan-Headers + Font Awesome Free brand icons (vendored, assets/os-icons) — https://fontawesome.com + Simple Icons (vendored, assets/os-icons) — https://simpleicons.org ---------------------------------------------------------------------------- MANIFEST (crate version — SPDX license — source) @@ -53,8 +55,6 @@ MANIFEST (crate version — SPDX license — source) atomic-waker 1.1.2 — Apache-2.0 OR MIT — https://github.com/smol-rs/atomic-waker audiopus_sys 0.2.2 — ISC — https://github.com/lakelezz/audiopus_sys.git autocfg 1.5.1 — Apache-2.0 OR MIT — https://github.com/cuviper/autocfg - aws-lc-rs 1.17.0 — ISC AND (Apache-2.0 OR ISC) — https://github.com/aws/aws-lc-rs - aws-lc-sys 0.41.0 — ISC AND (Apache-2.0 OR ISC) AND Apache-2.0 AND MIT AND BSD-3-Clause AND (Apache-2.0 OR ISC OR MIT) AND (Apache-2.0 OR ISC OR MIT-0) — https://github.com/aws/aws-lc-rs axum 0.8.9 — MIT — https://github.com/tokio-rs/axum axum-core 0.5.6 — MIT — https://github.com/tokio-rs/axum axum-server 0.8.0 — MIT — https://github.com/programatik29/axum-server @@ -70,6 +70,7 @@ MANIFEST (crate version — SPDX license — source) bumpalo 3.20.3 — MIT OR Apache-2.0 — https://github.com/fitzgen/bumpalo bytemuck 1.25.0 — Zlib OR Apache-2.0 OR MIT — https://github.com/Lokathor/bytemuck bytemuck_derive 1.10.2 — Zlib OR Apache-2.0 OR MIT — https://github.com/Lokathor/bytemuck + byteorder-lite 0.1.0 — Unlicense OR MIT — https://github.com/image-rs/byteorder-lite bytes 1.12.0 — MIT — https://github.com/tokio-rs/bytes cairo-rs 0.22.0 — MIT — https://github.com/gtk-rs/gtk-rs-core cairo-sys-rs 0.22.0 — MIT — https://github.com/gtk-rs/gtk-rs-core @@ -82,6 +83,8 @@ MANIFEST (crate version — SPDX license — source) cfg-expr 0.20.8 — MIT OR Apache-2.0 — https://github.com/EmbarkStudios/cfg-expr cfg-if 1.0.4 — MIT OR Apache-2.0 — https://github.com/rust-lang/cfg-if cfg_aliases 0.2.1 — MIT — https://github.com/katharostech/cfg_aliases + chacha20 0.9.1 — Apache-2.0 OR MIT — https://github.com/RustCrypto/stream-ciphers + chacha20poly1305 0.10.1 — Apache-2.0 OR MIT — https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305 ciborium 0.2.2 — Apache-2.0 — https://github.com/enarx/ciborium ciborium-io 0.2.2 — Apache-2.0 — https://github.com/enarx/ciborium ciborium-ll 0.2.2 — Apache-2.0 — https://github.com/enarx/ciborium @@ -91,6 +94,7 @@ MANIFEST (crate version — SPDX license — source) clap_builder 4.6.0 — MIT OR Apache-2.0 — https://github.com/clap-rs/clap clap_lex 1.1.0 — MIT OR Apache-2.0 — https://github.com/clap-rs/clap cmake 0.1.58 — MIT OR Apache-2.0 — https://github.com/rust-lang/cmake-rs + color_quant 1.1.0 — MIT — https://github.com/image-rs/color_quant.git colorchoice 1.0.5 — MIT OR Apache-2.0 — https://github.com/rust-cli/anstyle.git combine 4.6.7 — MIT — https://github.com/Marwes/combine concurrent-queue 2.5.0 — Apache-2.0 OR MIT — https://github.com/smol-rs/concurrent-queue @@ -116,7 +120,6 @@ MANIFEST (crate version — SPDX license — source) digest 0.10.7 — MIT OR Apache-2.0 — https://github.com/RustCrypto/traits displaydoc 0.2.6 — MIT OR Apache-2.0 — https://github.com/yaahc/displaydoc downcast-rs 1.2.1 — MIT/Apache-2.0 — https://github.com/marcianx/downcast-rs - dunce 1.0.5 — CC0-1.0 OR MIT-0 OR Apache-2.0 — https://gitlab.com/kornelski/dunce either 1.16.0 — MIT OR Apache-2.0 — https://github.com/rayon-rs/either endi 1.1.1 — MIT — https://github.com/zeenix/endi enumflags2 0.7.12 — MIT OR Apache-2.0 — https://github.com/meithecatte/enumflags2 @@ -130,6 +133,7 @@ MANIFEST (crate version — SPDX license — source) fallible-streaming-iterator 0.1.9 — MIT/Apache-2.0 — https://github.com/sfackler/fallible-streaming-iterator fastbloom 0.14.1 — MIT OR Apache-2.0 — https://github.com/tomtomwombat/fastbloom/ fastrand 2.4.1 — Apache-2.0 OR MIT — https://github.com/smol-rs/fastrand + fdeflate 0.3.7 — MIT OR Apache-2.0 — https://github.com/image-rs/fdeflate ffmpeg-next 8.1.0 — WTFPL — https://github.com/zmwangx/rust-ffmpeg ffmpeg-sys-next 8.1.0 — WTFPL — https://github.com/zmwangx/rust-ffmpeg-sys fiat-crypto 0.2.9 — MIT OR Apache-2.0 OR BSD-1-Clause — https://github.com/mit-plv/fiat-crypto @@ -144,7 +148,6 @@ MANIFEST (crate version — SPDX license — source) form_urlencoded 1.2.2 — MIT OR Apache-2.0 — https://github.com/servo/rust-url fragile 2.1.0 — Apache-2.0 — https://github.com/mitsuhiko/fragile fs-err 3.3.0 — MIT OR Apache-2.0 — https://github.com/andrewhickman/fs-err - fs_extra 1.3.0 — MIT — https://github.com/webdesus/fs_extra futures 0.3.32 — MIT OR Apache-2.0 — https://github.com/rust-lang/futures-rs futures-channel 0.3.32 — MIT OR Apache-2.0 — https://github.com/rust-lang/futures-rs futures-core 0.3.32 — MIT OR Apache-2.0 — https://github.com/rust-lang/futures-rs @@ -160,10 +163,12 @@ MANIFEST (crate version — SPDX license — source) gdk4 0.11.2 — MIT — https://github.com/gtk-rs/gtk4-rs gdk4-sys 0.11.2 — MIT — https://github.com/gtk-rs/gtk4-rs generic-array 0.14.7 — MIT — https://github.com/fizyk20/generic-array.git + gethostname 1.1.0 — Apache-2.0 — https://codeberg.org/swsnr/gethostname.rs.git getrandom 0.2.17 — MIT OR Apache-2.0 — https://github.com/rust-random/getrandom getrandom 0.3.4 — MIT OR Apache-2.0 — https://github.com/rust-random/getrandom getrandom 0.4.3 — MIT OR Apache-2.0 — https://github.com/rust-random/getrandom ghash 0.5.1 — Apache-2.0 OR MIT — https://github.com/RustCrypto/universal-hashes + gif 0.14.2 — MIT OR Apache-2.0 — https://github.com/image-rs/image-gif gio 0.22.6 — MIT — https://github.com/gtk-rs/gtk-rs-core gio-sys 0.22.0 — MIT — https://github.com/gtk-rs/gtk-rs-core glib 0.22.7 — MIT — https://github.com/gtk-rs/gtk-rs-core @@ -206,6 +211,7 @@ MANIFEST (crate version — SPDX license — source) idna_adapter 1.2.2 — Apache-2.0 OR MIT — https://github.com/hsivonen/idna_adapter if-addrs 0.13.4 — MIT OR BSD-3-Clause — https://github.com/messense/if-addrs if-addrs 0.15.0 — MIT OR BSD-3-Clause — https://github.com/messense/if-addrs + image 0.25.10 — MIT OR Apache-2.0 — https://github.com/image-rs/image indexmap 2.14.0 — Apache-2.0 OR MIT — https://github.com/indexmap-rs/indexmap inout 0.1.4 — MIT OR Apache-2.0 — https://github.com/RustCrypto/utils is-terminal 0.4.17 — MIT — https://github.com/sunfishcode/is-terminal @@ -246,6 +252,7 @@ MANIFEST (crate version — SPDX license — source) minimal-lexical 0.2.1 — MIT/Apache-2.0 — https://github.com/Alexhuszagh/minimal-lexical miniz_oxide 0.8.9 — MIT OR Zlib OR Apache-2.0 — https://github.com/Frommi/miniz_oxide/tree/master/miniz_oxide mio 1.2.1 — MIT — https://github.com/tokio-rs/mio + moxcms 0.8.1 — BSD-3-Clause OR Apache-2.0 — https://github.com/awxkee/moxcms.git nasm-rs 0.3.2 — MIT OR Apache-2.0 — https://github.com/medek/nasm-rs ndk 0.9.0 — MIT OR Apache-2.0 — https://github.com/rust-mobile/ndk ndk-sys 0.6.0+11769913 — MIT OR Apache-2.0 — https://github.com/rust-mobile/ndk @@ -291,7 +298,9 @@ MANIFEST (crate version — SPDX license — source) pkcs1 0.7.5 — Apache-2.0 OR MIT — https://github.com/RustCrypto/formats/tree/master/pkcs1 pkcs8 0.10.2 — Apache-2.0 OR MIT — https://github.com/RustCrypto/formats/tree/master/pkcs8 pkg-config 0.3.33 — MIT OR Apache-2.0 — https://github.com/rust-lang/pkg-config-rs + png 0.18.1 — MIT OR Apache-2.0 — https://github.com/image-rs/image-png polling 3.11.0 — Apache-2.0 OR MIT — https://github.com/smol-rs/polling + poly1305 0.8.0 — Apache-2.0 OR MIT — https://github.com/RustCrypto/universal-hashes polyval 0.6.2 — Apache-2.0 OR MIT — https://github.com/RustCrypto/universal-hashes potential_utf 0.1.5 — Unicode-3.0 — https://github.com/unicode-org/icu4x powerfmt 0.2.0 — MIT OR Apache-2.0 — https://github.com/jhpratt/powerfmt @@ -300,6 +309,7 @@ MANIFEST (crate version — SPDX license — source) proc-macro-crate 3.5.0 — MIT OR Apache-2.0 — https://github.com/bkchr/proc-macro-crate proc-macro2 1.0.106 — MIT OR Apache-2.0 — https://github.com/dtolnay/proc-macro2 proptest 1.11.0 — MIT OR Apache-2.0 — https://github.com/proptest-rs/proptest + pxfm 0.1.30 — BSD-3-Clause OR Apache-2.0 — https://github.com/awxkee/pxfm quick-error 1.2.3 — MIT/Apache-2.0 — http://github.com/tailhook/quick-error quick-xml 0.39.4 — MIT — https://github.com/tafia/quick-xml quinn 0.11.11 — MIT OR Apache-2.0 — https://github.com/quinn-rs/quinn @@ -476,6 +486,7 @@ MANIFEST (crate version — SPDX license — source) webpki-root-certs 1.0.8 — CDLA-Permissive-2.0 — https://github.com/rustls/webpki-roots webpki-roots 0.26.11 — CDLA-Permissive-2.0 — https://github.com/rustls/webpki-roots webpki-roots 1.0.8 — CDLA-Permissive-2.0 — https://github.com/rustls/webpki-roots + weezl 0.1.12 — MIT OR Apache-2.0 — https://github.com/image-rs/weezl wide 0.7.33 — Zlib OR Apache-2.0 OR MIT — https://github.com/Lokathor/wide widestring 1.2.1 — MIT OR Apache-2.0 — https://github.com/VoidStarKat/widestring-rs winapi 0.3.9 — MIT/Apache-2.0 — https://github.com/retep998/winapi-rs @@ -546,6 +557,8 @@ MANIFEST (crate version — SPDX license — source) winresource 0.1.31 — MIT — https://github.com/BenjaminRi/winresource wit-bindgen 0.57.1 — Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT — https://github.com/bytecodealliance/wit-bindgen writeable 0.6.3 — Unicode-3.0 — https://github.com/unicode-org/icu4x + x11rb 0.13.2 — MIT OR Apache-2.0 — https://github.com/psychon/x11rb + x11rb-protocol 0.13.2 — MIT OR Apache-2.0 — https://github.com/psychon/x11rb x509-parser 0.16.0 — MIT OR Apache-2.0 — https://github.com/rusticata/x509-parser.git xattr 1.6.1 — MIT OR Apache-2.0 — https://github.com/Stebalien/xattr xkbcommon 0.8.0 — MIT — https://github.com/rust-x-bindings/xkbcommon-rs @@ -565,6 +578,8 @@ MANIFEST (crate version — SPDX license — source) zerovec 0.11.6 — Unicode-3.0 — https://github.com/unicode-org/icu4x zerovec-derive 0.11.3 — Unicode-3.0 — https://github.com/unicode-org/icu4x zmij 1.0.21 — MIT — https://github.com/dtolnay/zmij + zune-core 0.5.1 — MIT OR Apache-2.0 OR Zlib — https://github.com/etemesi254/zune-image + zune-jpeg 0.5.15 — MIT OR Apache-2.0 OR Zlib — https://github.com/etemesi254/zune-image/tree/dev/crates/zune-jpeg zvariant 5.12.0 — MIT — https://github.com/z-galaxy/zbus/ zvariant_derive 5.12.0 — MIT — https://github.com/z-galaxy/zbus/ zvariant_utils 3.4.0 — MIT — https://github.com/z-galaxy/zbus/ @@ -851,7 +866,7 @@ DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: aead 0.5.2, aes 0.8.4, aes-gcm 0.10.3, base64ct 1.8.3, block-buffer 0.10.4, block-padding 0.3.3, cbc 0.1.2, cipher 0.4.4, const-oid 0.9.6, cpufeatures 0.2.17, crypto-common 0.1.7, ctr 0.9.2, der 0.7.10, digest 0.10.7, ghash 0.5.1, hkdf 0.12.4, hmac 0.12.1, inout 0.1.4, opaque-debug 0.3.1, pem-rfc7468 0.7.0, pkcs1 0.7.5, pkcs8 0.10.2, polyval 0.6.2, sha2 0.10.9, signature 2.2.0, spake2 0.4.0, spki 0.7.3, universal-hash 0.5.1 +The following license (LICENSE-APACHE) applies to: aead 0.5.2, aes 0.8.4, aes-gcm 0.10.3, base64ct 1.8.3, block-buffer 0.10.4, block-padding 0.3.3, cbc 0.1.2, chacha20 0.9.1, chacha20poly1305 0.10.1, cipher 0.4.4, const-oid 0.9.6, cpufeatures 0.2.17, crypto-common 0.1.7, ctr 0.9.2, der 0.7.10, digest 0.10.7, ghash 0.5.1, hkdf 0.12.4, hmac 0.12.1, inout 0.1.4, opaque-debug 0.3.1, pem-rfc7468 0.7.0, pkcs1 0.7.5, pkcs8 0.10.2, poly1305 0.8.0, polyval 0.6.2, sha2 0.10.9, signature 2.2.0, spake2 0.4.0, spki 0.7.3, universal-hash 0.5.1 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -1118,7 +1133,7 @@ DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: aes-gcm 0.10.3 +The following license (LICENSE-MIT) applies to: aes-gcm 0.10.3, chacha20poly1305 0.10.1 ---------------------------------------------------------------------------- Copyright (c) 2019 The RustCrypto Project Developers @@ -1156,7 +1171,7 @@ You may use this code under the terms of either license. ---------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: aho-corasick 1.1.4, memchr 2.8.2, walkdir 2.5.0 +The following license (LICENSE-MIT) applies to: aho-corasick 1.1.4, byteorder-lite 0.1.0, memchr 2.8.2, walkdir 2.5.0 ---------------------------------------------------------------------------- The MIT License (MIT) @@ -1182,7 +1197,7 @@ THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (UNLICENSE) applies to: aho-corasick 1.1.4, ksni 0.3.5, memchr 2.8.2, same-file 1.0.6, walkdir 2.5.0, winapi-util 0.1.11 +The following license (UNLICENSE) applies to: aho-corasick 1.1.4, byteorder-lite 0.1.0, ksni 0.3.5, memchr 2.8.2, same-file 1.0.6, walkdir 2.5.0, winapi-util 0.1.11 ---------------------------------------------------------------------------- This is free and unencumbered software released into the public domain. @@ -2210,7 +2225,7 @@ SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: asn1-rs 0.6.2, asn1-rs-derive 0.5.1, async-channel 2.5.0, async-executor 1.14.0, async-io 2.6.0, async-lock 3.4.2, async-process 2.5.0, async-recursion 1.1.1, async-signal 0.2.14, async-task 4.7.1, atomic-waker 1.1.2, autocfg 1.5.1, base64 0.22.1, bitflags 2.13.0, blocking 1.6.2, bumpalo 3.20.3, cast 0.3.0, cc 1.2.65, cexpr 0.6.0, cfg-if 1.0.4, cmake 0.1.58, concurrent-queue 2.5.0, core-foundation 0.10.1, core-foundation-sys 0.8.7, criterion 0.5.1, criterion-plot 0.5.0, crossbeam-utils 0.8.21, curve25519-dalek-derive 0.1.1, der-parser 9.0.0, displaydoc 0.2.6, either 1.16.0, equivalent 1.0.2, errno 0.3.14, event-listener 5.4.1, event-listener-strategy 0.5.4, fastrand 2.4.1, filetime 0.2.29, find-msvc-tools 0.1.9, fixedbitset 0.5.7, flate2 1.1.9, fnv 1.0.7, form_urlencoded 1.2.2, fs-err 3.3.0, futures-lite 2.6.1, glob 0.3.3, hashbrown 0.16.1, hashbrown 0.17.1, heck 0.5.0, hermit-abi 0.5.2, httparse 1.10.1, idna 1.1.0, idna_adapter 1.2.2, indexmap 2.14.0, itertools 0.10.5, itertools 0.13.0, jni 0.21.1, jobserver 0.1.34, js-sys 0.3.103, khronos-egl 6.0.0, lazy_static 1.5.0, linux-raw-sys 0.12.1, lock_api 0.4.14, log 0.4.33, mime 0.3.17, nasm-rs 0.3.2, num-bigint 0.4.6, num-bigint-dig 0.8.6, num-derive 0.4.2, num-integer 0.1.46, num-iter 0.1.45, num-traits 0.2.19, num_cpus 1.17.0, oid-registry 0.7.1, once_cell 1.21.4, openssl-probe 0.2.1, opus 0.3.1, ordered-stream 0.2.0, parking 2.2.1, parking_lot 0.12.5, parking_lot_core 0.9.12, percent-encoding 2.3.2, piper 0.2.5, pkg-config 0.3.33, polling 3.11.0, proptest 1.11.0, regex 1.12.4, regex-automata 0.4.14, regex-syntax 0.8.11, roxmltree 0.21.1, rsa 0.9.10, rustc_version 0.4.1, rusticata-macros 4.1.0, rustix 1.1.4, rustls 0.23.41, rustls-native-certs 0.8.4, rusty-fork 0.3.1, scopeguard 1.2.0, security-framework 3.7.0, security-framework-sys 2.17.0, signal-hook-registry 1.4.8, smallvec 1.15.2, socket2 0.6.4, stable_deref_trait 1.2.1, system-deps 7.0.8, tar 0.4.46, tempfile 3.27.0, thread_local 1.1.9, tinytemplate 1.2.1, unicode-segmentation 1.13.3, unicode-width 0.2.2, url 2.5.8, uuid 1.23.4, vcpkg 0.2.15, version_check 0.9.5, wait-timeout 0.2.1, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wasm-bindgen 0.2.126, wasm-bindgen-macro 0.2.126, wasm-bindgen-macro-support 0.2.126, wasm-bindgen-shared 0.2.126, wit-bindgen 0.57.1, x509-parser 0.16.0, xattr 1.6.1 +The following license (LICENSE-APACHE) applies to: asn1-rs 0.6.2, asn1-rs-derive 0.5.1, async-channel 2.5.0, async-executor 1.14.0, async-io 2.6.0, async-lock 3.4.2, async-process 2.5.0, async-recursion 1.1.1, async-signal 0.2.14, async-task 4.7.1, atomic-waker 1.1.2, autocfg 1.5.1, base64 0.22.1, bitflags 2.13.0, blocking 1.6.2, bumpalo 3.20.3, cast 0.3.0, cc 1.2.65, cexpr 0.6.0, cfg-if 1.0.4, cmake 0.1.58, concurrent-queue 2.5.0, core-foundation 0.10.1, core-foundation-sys 0.8.7, criterion 0.5.1, criterion-plot 0.5.0, crossbeam-utils 0.8.21, curve25519-dalek-derive 0.1.1, der-parser 9.0.0, displaydoc 0.2.6, either 1.16.0, equivalent 1.0.2, errno 0.3.14, event-listener 5.4.1, event-listener-strategy 0.5.4, fastrand 2.4.1, filetime 0.2.29, find-msvc-tools 0.1.9, fixedbitset 0.5.7, flate2 1.1.9, fnv 1.0.7, form_urlencoded 1.2.2, fs-err 3.3.0, futures-lite 2.6.1, gethostname 1.1.0, gif 0.14.2, glob 0.3.3, hashbrown 0.16.1, hashbrown 0.17.1, heck 0.5.0, hermit-abi 0.5.2, httparse 1.10.1, idna 1.1.0, idna_adapter 1.2.2, indexmap 2.14.0, itertools 0.10.5, itertools 0.13.0, jni 0.21.1, jobserver 0.1.34, js-sys 0.3.103, khronos-egl 6.0.0, lazy_static 1.5.0, linux-raw-sys 0.12.1, lock_api 0.4.14, log 0.4.33, mime 0.3.17, nasm-rs 0.3.2, num-bigint 0.4.6, num-bigint-dig 0.8.6, num-derive 0.4.2, num-integer 0.1.46, num-iter 0.1.45, num-traits 0.2.19, num_cpus 1.17.0, oid-registry 0.7.1, once_cell 1.21.4, openssl-probe 0.2.1, opus 0.3.1, ordered-stream 0.2.0, parking 2.2.1, parking_lot 0.12.5, parking_lot_core 0.9.12, percent-encoding 2.3.2, piper 0.2.5, pkg-config 0.3.33, png 0.18.1, polling 3.11.0, proptest 1.11.0, regex 1.12.4, regex-automata 0.4.14, regex-syntax 0.8.11, roxmltree 0.21.1, rsa 0.9.10, rustc_version 0.4.1, rusticata-macros 4.1.0, rustix 1.1.4, rustls 0.23.41, rustls-native-certs 0.8.4, rusty-fork 0.3.1, scopeguard 1.2.0, security-framework 3.7.0, security-framework-sys 2.17.0, signal-hook-registry 1.4.8, smallvec 1.15.2, socket2 0.6.4, stable_deref_trait 1.2.1, system-deps 7.0.8, tar 0.4.46, tempfile 3.27.0, thread_local 1.1.9, tinytemplate 1.2.1, unicode-segmentation 1.13.3, unicode-width 0.2.2, url 2.5.8, uuid 1.23.4, vcpkg 0.2.15, version_check 0.9.5, wait-timeout 0.2.1, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wasm-bindgen 0.2.126, wasm-bindgen-macro 0.2.126, wasm-bindgen-macro-support 0.2.126, wasm-bindgen-shared 0.2.126, weezl 0.1.12, wit-bindgen 0.57.1, x509-parser 0.16.0, xattr 1.6.1 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -2766,534 +2781,6 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------------- -The following license (LICENSE) applies to: aws-lc-rs 1.17.0 ----------------------------------------------------------------------------- -SPDX-License-Identifier: ISC AND (Apache-2.0 OR ISC) - - -Apache 2.0 license -------------------------------------- - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - -ISC license -------------------------------------- - - -Copyright Amazon.com, Inc. or its affiliates. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ----------------------------------------------------------------------------- -The following license (LICENSE) applies to: aws-lc-sys 0.41.0 ----------------------------------------------------------------------------- -AWS Libcrypto (AWS-LC) - -AWS-LC is a fork of BoringSSL, which is itself a fork of OpenSSL. -Content from these and other sources retains their original licensing, -as described below. New files from AWS-LC are made available under the Apache-2.0 license OR the ISC -license. These licenses are reproduced at the bottom of this file. - -``` -Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -SPDX-License-Identifier: Apache-2.0 OR ISC -``` - - -================================================================================ -BoringSSL -================================================================================ - -BoringSSL is a Google-maintained fork of OpenSSL. Historically, code -authored by Google for BoringSSL was licensed under the ISC License. -BoringSSL has since relicensed upstream to Apache License 2.0. Existing -AWS-LC code originating from BoringSSL retains its ISC license, while -newer code taken from BoringSSL is licensed under Apache License 2.0. - -``` -Copyright (c) 2014-2024 Google Inc. -SPDX-License-Identifier: ISC -``` - -Additional individual contributions to BoringSSL-derived code are -covered under the ISC license: - - - Brian Smith (Copyright 2016) - - Robert Nagy (Copyright 2022) - - Arm Ltd (Copyright 2020) - -``` -Copyright (c) 2025-2026 Google Inc. -SPDX-License-Identifier: Apache-2.0 -``` - -================================================================================ -OpenSSL -================================================================================ - -Code derived from the OpenSSL project is licensed under the -Apache License, Version 2.0. - -``` -Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. -SPDX-License-Identifier: Apache-2.0 -``` - -Some OpenSSL-derived files also carry the original SSLeay copyright: - -``` -Copyright (c) 1995-1998 Eric Young (eay@cryptsoft.com). All rights reserved. -SPDX-License-Identifier: Apache-2.0 -``` - -Portions of OpenSSL-derived code include contributions from: - - - Sun Microsystems, Inc. (Copyright 2002) - - Nokia (Copyright 2005) - - Intel Corporation (Copyright 2012-2021) - -These contributions are covered under the Apache-2.0 license. - -================================================================================ -mlkem-native -================================================================================ - -Code from the mlkem-native project is licensed under Apache License 2.0 or MIT or ISC. - -``` -Copyright (c) The mlkem-native project authors. -SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT -``` - -================================================================================ -mldsa-native -================================================================================ - -Code from the mldsa-native project is licensed under Apache License 2.0 or MIT or ISC - -``` -Copyright (c) The mldsa-native project authors. -SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT -``` - -================================================================================ -Third-Party Libraries (compiled into libcrypto/libssl) -================================================================================ - -Fiat Cryptography ------------------ -Synthesizing Correct-by-Construction Code for Cryptographic Primitives. -See third_party/fiat/LICENSE. - -``` -Copyright (c) 2015-2020 the fiat-crypto authors. -SPDX-License-Identifier: MIT -``` - -s2n-bignum ----------- -Integer arithmetic routines for cryptography. -See third_party/s2n-bignum/s2n-bignum-imported/LICENSE. - -``` -Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 -``` - -Note: ML-KEM/SHA3 code within s2n-bignum is licensed as -Apache-2.0 OR ISC OR MIT (with attribution), sourced from the -mlkem-native project. - -Jitter Entropy RNG -------------------- -CPU Jitter Random Number Generator Library. -See third_party/jitterentropy/jitterentropy-library/LICENSE. - -The Jitter Entropy library is dual-licensed under a BSD-style license -and the GNU General Public License Version 2. Amazon expressly elects -to distribute the package under the 3-Clause BSD License and NOT under -GNU General Public License Version 2. - -``` -Copyright (C) 2017 - 2025, Stephan Mueller . -SPDX-License-Identifier: BSD-3-Clause -``` - -Keccak / AES Reference Implementations ---------------------------------------- -Public domain (CC0) contributions. -https://creativecommons.org/public-domain/cc0 - -Code from sources and by authors listed in comments on top of the respective files. - - -================================================================================ -Third-Party Libraries (NOT compiled into libcrypto/libssl) -================================================================================ - -The following are used for testing and build tooling only. Distributing -code linked against AWS-LC (libcrypto/libssl) does NOT trigger these -license obligations. - -Google Test ------------ -See third_party/googletest/LICENSE. - -``` -Copyright 2008 Google Inc. -SPDX-License-Identifier: BSD-3-Clause -``` - -Go Standard Library -------------------- -Code in ssl/test/runner/ is derived from the Go standard library. - -``` -Copyright (c) The Go Authors. All rights reserved. -SPDX-License-Identifier: BSD-3-Clause -``` - -Wycheproof Test Vectors ------------------------- -Project Wycheproof is a community managed repository of test vectors that can be used by cryptography library -developers to test against known attacks, specification inconsistencies, and other various implementation bugs. - -See third_party/wycheproof_testvectors/LICENSE. - -``` -SPDX-License-Identifier: Apache-2.0 -``` - - -================================================================================ -Full License Texts -================================================================================ - -Apache License 2.0 ------------------- -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - - "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -ISC License ------------ -Permission to use, copy, modify, and/or distribute this software for -any purpose with or without fee is hereby granted, provided that the -above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL -WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE -AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL -DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR -PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. - -MIT License ------------ -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -BSD 3-Clause License --------------------- -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -MIT No Attribution (MIT-0) --------------------------- -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - ---------------------------------------------------------------------------- The following license (LICENSE) applies to: axum 0.8.9 ---------------------------------------------------------------------------- @@ -4966,7 +4453,37 @@ The `cfg_aliases!` macro uses a lot of the code from [`tectonic_cfg_support::tar ---------------------------------------------------------------------------- -The following license (LICENSE) applies to: ciborium 0.2.2, ciborium-io 0.2.2, ciborium-ll 0.2.2, clang-sys 1.8.1, flume 0.12.0, fragile 2.1.0, lru-slab 0.1.2, quinn 0.11.11, quinn-proto 0.11.15, quinn-udp 0.5.14, rpkg-config 0.1.2, rustls-platform-verifier 0.6.2, tinyvec 1.11.0, unarray 0.1.4, ureq 2.12.1, utf8_iter 1.0.4, utoipa 5.5.0, utoipa-axum 0.2.0, utoipa-gen 5.5.0, utoipa-scalar 0.3.0, zeroize 1.9.0 +The following license (LICENSE-MIT) applies to: chacha20 0.9.1 +---------------------------------------------------------------------------- +Copyright (c) 2019-2023 The RustCrypto Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + + +---------------------------------------------------------------------------- +The following license (LICENSE) applies to: ciborium 0.2.2, ciborium-io 0.2.2, ciborium-ll 0.2.2, clang-sys 1.8.1, flume 0.12.0, fragile 2.1.0, lru-slab 0.1.2, quinn 0.11.11, quinn-proto 0.11.15, quinn-udp 0.5.14, rpkg-config 0.1.2, rustls-platform-verifier 0.6.2, tinyvec 1.11.0, unarray 0.1.4, ureq 2.12.1, utf8_iter 1.0.4, utoipa 5.5.0, utoipa-axum 0.2.0, utoipa-gen 5.5.0, utoipa-scalar 0.3.0, x11rb 0.13.2, x11rb-protocol 0.13.2, zeroize 1.9.0, zune-core 0.5.1, zune-jpeg 0.5.15 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -5201,6 +4718,32 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE) applies to: color_quant 1.1.0 +---------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2016 PistonDevelopers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + ---------------------------------------------------------------------------- The following license (LICENSE) applies to: combine 4.6.7 ---------------------------------------------------------------------------- @@ -5904,132 +5447,6 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------------- -The following license (LICENSE) applies to: dunce 1.0.5 ----------------------------------------------------------------------------- -Creative Commons Legal Code - -CC0 1.0 Universal - - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator -and subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for -the purpose of contributing to a commons of creative, cultural and -scientific works ("Commons") that the public can reliably and without fear -of later claims of infringement build upon, modify, incorporate in other -works, reuse and redistribute as freely as possible in any form whatsoever -and for any purposes, including without limitation commercial purposes. -These owners may contribute to the Commons to promote the ideal of a free -culture and the further production of creative, cultural and scientific -works, or to gain reputation or greater distribution for their Work in -part through the use and efforts of others. - -For these and/or other purposes and motivations, and without any -expectation of additional consideration or compensation, the person -associating CC0 with a Work (the "Affirmer"), to the extent that he or she -is an owner of Copyright and Related Rights in the Work, voluntarily -elects to apply CC0 to the Work and publicly distribute the Work under its -terms, with knowledge of his or her Copyright and Related Rights in the -Work and the meaning and intended legal effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not -limited to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); -iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and -vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention -of, applicable law, Affirmer hereby overtly, fully, permanently, -irrevocably and unconditionally waives, abandons, and surrenders all of -Affirmer's Copyright and Related Rights and associated claims and causes -of action, whether now known or unknown (including existing as well as -future claims and causes of action), in the Work (i) in all territories -worldwide, (ii) for the maximum duration provided by applicable law or -treaty (including future time extensions), (iii) in any current or future -medium and for any number of copies, and (iv) for any purpose whatsoever, -including without limitation commercial, advertising or promotional -purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each -member of the public at large and to the detriment of Affirmer's heirs and -successors, fully intending that such Waiver shall not be subject to -revocation, rescission, cancellation, termination, or any other legal or -equitable action to disrupt the quiet enjoyment of the Work by the public -as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason -be judged legally invalid or ineffective under applicable law, then the -Waiver shall be preserved to the maximum extent permitted taking into -account Affirmer's express Statement of Purpose. In addition, to the -extent the Waiver is so judged Affirmer hereby grants to each affected -person a royalty-free, non transferable, non sublicensable, non exclusive, -irrevocable and unconditional license to exercise Affirmer's Copyright and -Related Rights in the Work (i) in all territories worldwide, (ii) for the -maximum duration provided by applicable law or treaty (including future -time extensions), (iii) in any current or future medium and for any number -of copies, and (iv) for any purpose whatsoever, including without -limitation commercial, advertising or promotional purposes (the -"License"). The License shall be deemed effective as of the date CC0 was -applied by Affirmer to the Work. Should any part of the License for any -reason be judged legally invalid or ineffective under applicable law, such -partial invalidity or ineffectiveness shall not invalidate the remainder -of the License, and in such case Affirmer hereby affirms that he or she -will not (i) exercise any of his or her remaining Copyright and Related -Rights in the Work or (ii) assert any associated claims and causes of -action with respect to the Work, in either case contrary to Affirmer's -express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. - - ---------------------------------------------------------------------------- The following license (LICENSE-MIT) applies to: either 1.16.0, itertools 0.10.5, itertools 0.13.0 ---------------------------------------------------------------------------- @@ -6405,109 +5822,7 @@ DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- -The following license (LICENSE) applies to: ffmpeg-next 8.1.0 ----------------------------------------------------------------------------- -DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - Version 2, December 2004 - - Everyone is permitted to copy and distribute verbatim or modified - copies of this license document, and changing it is allowed as long - as the name is changed. - - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. You just DO WHAT THE FUCK YOU WANT TO. - - ----------------------------------------------------------------------------- -The following license (COPYRIGHT) applies to: fiat-crypto 0.2.9 ----------------------------------------------------------------------------- -SPDX-License-Identifier: MIT OR Apache-2.0 OR BSD-1-Clause - -Fiat Cryptography is licensed under the MIT License or -, the Apache License, Version 2.0 - or , or -the BSD 1-Clause License or -, at your option. - - ----------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: fiat-crypto 0.2.9 ----------------------------------------------------------------------------- -The Apache License, Version 2.0 (Apache-2.0) - -Copyright 2015-2020 the fiat-crypto authors (see the AUTHORS file) - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - - ----------------------------------------------------------------------------- -The following license (LICENSE-BSD-1) applies to: fiat-crypto 0.2.9 ----------------------------------------------------------------------------- -The BSD 1-Clause License (BSD-1-Clause) - -Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file) -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, -Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ----------------------------------------------------------------------------- -The following license (LICENSE-MIT) applies to: fiat-crypto 0.2.9 ----------------------------------------------------------------------------- -The MIT License (MIT) - -Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file). - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ----------------------------------------------------------------------------- -The following license (LICENSE-APACHE) applies to: field-offset 0.3.6, half 2.7.1, miniz_oxide 0.8.9, num-conv 0.2.2, pin-project-lite 0.2.17, raw-window-handle 0.6.2, sync_wrapper 1.0.2, time 0.3.51, time-core 0.1.9, time-macros 0.2.30, widestring 1.2.1 +The following license (LICENSE-APACHE) applies to: fdeflate 0.3.7, field-offset 0.3.6, half 2.7.1, image 0.25.10, miniz_oxide 0.8.9, num-conv 0.2.2, pin-project-lite 0.2.17, raw-window-handle 0.6.2, sync_wrapper 1.0.2, time 0.3.51, time-core 0.1.9, time-macros 0.2.30, widestring 1.2.1 ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 @@ -6687,6 +6002,138 @@ Apache License END OF TERMS AND CONDITIONS +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: fdeflate 0.3.7, image 0.25.10 +---------------------------------------------------------------------------- +MIT License + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + + +---------------------------------------------------------------------------- +The following license (LICENSE) applies to: ffmpeg-next 8.1.0 +---------------------------------------------------------------------------- +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. + + +---------------------------------------------------------------------------- +The following license (COPYRIGHT) applies to: fiat-crypto 0.2.9 +---------------------------------------------------------------------------- +SPDX-License-Identifier: MIT OR Apache-2.0 OR BSD-1-Clause + +Fiat Cryptography is licensed under the MIT License or +, the Apache License, Version 2.0 + or , or +the BSD 1-Clause License or +, at your option. + + +---------------------------------------------------------------------------- +The following license (LICENSE-APACHE) applies to: fiat-crypto 0.2.9 +---------------------------------------------------------------------------- +The Apache License, Version 2.0 (Apache-2.0) + +Copyright 2015-2020 the fiat-crypto authors (see the AUTHORS file) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +---------------------------------------------------------------------------- +The following license (LICENSE-BSD-1) applies to: fiat-crypto 0.2.9 +---------------------------------------------------------------------------- +The BSD 1-Clause License (BSD-1-Clause) + +Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, +Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: fiat-crypto 0.2.9 +---------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file). + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + ---------------------------------------------------------------------------- The following license (LICENSE-MIT) applies to: field-offset 0.3.6 ---------------------------------------------------------------------------- @@ -6827,6 +6274,28 @@ the following restrictions: 3. This notice may not be removed or altered from any source distribution. +---------------------------------------------------------------------------- +The following license (font-awesome-brands.txt) applies to: Font Awesome Free brand icons (vendored, assets/os-icons) +---------------------------------------------------------------------------- +Font Awesome Free — brand icons (windows, apple, linux, steam, ubuntu, fedora, +opensuse in assets/os-icons/) are from Font Awesome Free. + +Copyright (c) Fonticons, Inc. (https://fontawesome.com) + +Font Awesome Free icons are licensed under the Creative Commons Attribution 4.0 +International license (CC BY 4.0), https://creativecommons.org/licenses/by/4.0/. +The icons are redistributed here as monochrome SVG path data with no +modifications beyond color normalization (fill="currentColor"). + +Per the Font Awesome Free license (https://fontawesome.com/license/free): +"Font Awesome Free is free, open source, and GPL friendly. You can use it for +commercial projects, open source projects, or really almost whatever you want. +Attribution is required by MIT, SIL OFL, and CC BY licenses." + +Brand icons are trademarks of their respective owners and are used for +identification purposes only; their use does not imply endorsement. + + ---------------------------------------------------------------------------- The following license (LICENSE-MIT) applies to: form_urlencoded 1.2.2 ---------------------------------------------------------------------------- @@ -6857,32 +6326,6 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------------- -The following license (LICENSE) applies to: fs_extra 1.3.0 ----------------------------------------------------------------------------- -MIT License - -Copyright (c) 2017 Denis Kurilenko - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ---------------------------------------------------------------------------- The following license (LICENSE-APACHE) applies to: futures 0.3.32, futures-channel 0.3.32, futures-core 0.3.32, futures-executor 0.3.32, futures-io 0.3.32, futures-macro 0.3.32, futures-sink 0.3.32, futures-task 0.3.32, futures-util 0.3.32 ---------------------------------------------------------------------------- @@ -7476,6 +6919,32 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: gif 0.14.2 +---------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2015 nwin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + ---------------------------------------------------------------------------- The following license (LICENSE) applies to: Granite subset (vendored, crates/pyrowave-sys) ---------------------------------------------------------------------------- @@ -10255,6 +9724,243 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE-APACHE.md) applies to: moxcms 0.8.1, pxfm 0.1.30 +---------------------------------------------------------------------------- +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2024 Radzivon Bartoshyk + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +---------------------------------------------------------------------------- +The following license (LICENSE.md) applies to: moxcms 0.8.1, pxfm 0.1.30 +---------------------------------------------------------------------------- +Copyright (c) Radzivon Bartoshyk. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ---------------------------------------------------------------------------- The following license (LICENSE) applies to: nix 0.29.0, nix 0.30.1 ---------------------------------------------------------------------------- @@ -10569,6 +10275,66 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: png 0.18.1 +---------------------------------------------------------------------------- +Copyright (c) 2015 nwin + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + + +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: poly1305 0.8.0 +---------------------------------------------------------------------------- +Copyright (c) 2015-2019 RustCrypto Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + + ---------------------------------------------------------------------------- The following license (LICENSE-MIT) applies to: polyval 0.6.2 ---------------------------------------------------------------------------- @@ -13222,6 +12988,21 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (simple-icons.txt) applies to: Simple Icons (vendored, assets/os-icons) +---------------------------------------------------------------------------- +Simple Icons — brand icons (arch, nixos, debian in assets/os-icons/) are from +Simple Icons (https://simpleicons.org, https://github.com/simple-icons/simple-icons). + +The Simple Icons SVG path data is released under CC0 1.0 Universal (public domain +dedication), https://creativecommons.org/publicdomain/zero/1.0/ — no attribution +required; this notice is provided for provenance. + +Brand icons are trademarks of their respective owners and are used for +identification purposes only; their use does not imply endorsement. See +https://github.com/simple-icons/simple-icons/blob/develop/DISCLAIMER.md. + + ---------------------------------------------------------------------------- The following license (COPYING) applies to: siphasher 1.0.3 ---------------------------------------------------------------------------- @@ -15365,6 +15146,32 @@ of Data, including for example machine learning models and models' insights. +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: weezl 0.1.12 +---------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) HeroicKatora 2020 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + ---------------------------------------------------------------------------- The following license (LICENSE-MIT) applies to: winapi 0.3.9 ---------------------------------------------------------------------------- @@ -15934,6 +15741,36 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: x11rb 0.13.2, x11rb-protocol 0.13.2 +---------------------------------------------------------------------------- +Copyright 2019 x11rb Contributers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + + ---------------------------------------------------------------------------- The following license (LICENSE) applies to: xkbcommon 0.8.0 ---------------------------------------------------------------------------- @@ -16534,3 +16371,53 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +---------------------------------------------------------------------------- +The following license (LICENSE-MIT) applies to: zune-core 0.5.1, zune-jpeg 0.5.15 +---------------------------------------------------------------------------- +MIT License + +Copyright (c) zune-image developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +---------------------------------------------------------------------------- +The following license (LICENSE-ZLIB) applies to: zune-core 0.5.1, zune-jpeg 0.5.15 +---------------------------------------------------------------------------- +zlib License + +(C) zune-image developers + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + diff --git a/api/openapi.json b/api/openapi.json index 5bc4acd4..9248692c 100644 --- a/api/openapi.json +++ b/api/openapi.json @@ -5335,6 +5335,8 @@ "abi_version", "app_version", "gfe_version", + "os", + "os_name", "codecs", "gamestream", "ports" @@ -5372,6 +5374,16 @@ "type": "string", "description": "Best-effort primary LAN IP." }, + "os": { + "type": "string", + "description": "OS identity chain, generic → most specific, slash-separated (`windows` | `macos` |\n`linux[/][/]`). A client walks it most-specific-first and shows the first\ntoken it has an icon for, so an unknown distro still degrades to its family's mark.", + "example": "linux/fedora/bazzite" + }, + "os_name": { + "type": "string", + "description": "Human-readable OS name (os-release `PRETTY_NAME`; `\"Windows\"`/`\"macOS\"` elsewhere).", + "example": "Bazzite 42 (Kinoite)" + }, "ports": { "$ref": "#/components/schemas/PortMap" }, diff --git a/assets/os-icons/LICENSES/font-awesome-brands.txt b/assets/os-icons/LICENSES/font-awesome-brands.txt new file mode 100644 index 00000000..5159bcf0 --- /dev/null +++ b/assets/os-icons/LICENSES/font-awesome-brands.txt @@ -0,0 +1,17 @@ +Font Awesome Free — brand icons (windows, apple, linux, steam, ubuntu, fedora, +opensuse in assets/os-icons/) are from Font Awesome Free. + +Copyright (c) Fonticons, Inc. (https://fontawesome.com) + +Font Awesome Free icons are licensed under the Creative Commons Attribution 4.0 +International license (CC BY 4.0), https://creativecommons.org/licenses/by/4.0/. +The icons are redistributed here as monochrome SVG path data with no +modifications beyond color normalization (fill="currentColor"). + +Per the Font Awesome Free license (https://fontawesome.com/license/free): +"Font Awesome Free is free, open source, and GPL friendly. You can use it for +commercial projects, open source projects, or really almost whatever you want. +Attribution is required by MIT, SIL OFL, and CC BY licenses." + +Brand icons are trademarks of their respective owners and are used for +identification purposes only; their use does not imply endorsement. diff --git a/assets/os-icons/LICENSES/simple-icons.txt b/assets/os-icons/LICENSES/simple-icons.txt new file mode 100644 index 00000000..4b1cea40 --- /dev/null +++ b/assets/os-icons/LICENSES/simple-icons.txt @@ -0,0 +1,10 @@ +Simple Icons — brand icons (arch, nixos, debian in assets/os-icons/) are from +Simple Icons (https://simpleicons.org, https://github.com/simple-icons/simple-icons). + +The Simple Icons SVG path data is released under CC0 1.0 Universal (public domain +dedication), https://creativecommons.org/publicdomain/zero/1.0/ — no attribution +required; this notice is provided for provenance. + +Brand icons are trademarks of their respective owners and are used for +identification purposes only; their use does not imply endorsement. See +https://github.com/simple-icons/simple-icons/blob/develop/DISCLAIMER.md. diff --git a/assets/os-icons/README.md b/assets/os-icons/README.md new file mode 100644 index 00000000..f1e34bd5 --- /dev/null +++ b/assets/os-icons/README.md @@ -0,0 +1,30 @@ +# OS icon masters + +The canonical OS/distro brand marks every client derives its host-card OS icon from +(web console inline SVGs, GTK symbolic icons, Windows PNGs, Apple template imagesets, +Android `ImageVector`s). One file per **icon token** of the host's OS-identity chain +(see `crates/punktfunk-host/src/osinfo.rs` and `crates/pf-client-core/src/os.rs`): + +| token | mark | source | +|---|---|---| +| `windows` | Windows | Font Awesome Free brands (CC BY 4.0) | +| `apple` | Apple (also `macos` via alias) | Font Awesome Free brands (CC BY 4.0) | +| `linux` | Tux | Font Awesome Free brands (CC BY 4.0) | +| `steam` | Steam (also `steamos` via alias) | Font Awesome Free brands (CC BY 4.0) | +| `ubuntu` | Ubuntu | Font Awesome Free brands (CC BY 4.0) | +| `fedora` | Fedora | Font Awesome Free brands (CC BY 4.0) | +| `opensuse` | SUSE | Font Awesome Free brands (CC BY 4.0) | +| `arch` | Arch Linux | Simple Icons (CC0 1.0) | +| `nixos` | NixOS | Simple Icons (CC0 1.0) | +| `debian` | Debian | Simple Icons (CC0 1.0) | + +Distros with no file here (Bazzite, CachyOS, Nobara, Pop!_OS, Mint, …) are intentional: +the host advertises the full chain (`linux/fedora/bazzite`), and clients walk it +most-specific-first, so they degrade to the family mark and finally to Tux. + +All files are monochrome (`fill="currentColor"`), original per-icon viewBoxes preserved. +Licensing: attribution notices live in `LICENSES/` and are folded into +`THIRD-PARTY-NOTICES.txt` by `scripts/gen-third-party-notices.py`. The marks are +trademarks of their respective owners; they are used here nominatively — to *identify* +the operating system a host runs, the standard practice in this ecosystem — and imply no +affiliation or endorsement. diff --git a/assets/os-icons/apple.svg b/assets/os-icons/apple.svg new file mode 100644 index 00000000..eb165da2 --- /dev/null +++ b/assets/os-icons/apple.svg @@ -0,0 +1,2 @@ + + diff --git a/assets/os-icons/arch.svg b/assets/os-icons/arch.svg new file mode 100644 index 00000000..d551ca17 --- /dev/null +++ b/assets/os-icons/arch.svg @@ -0,0 +1,2 @@ + + diff --git a/assets/os-icons/debian.svg b/assets/os-icons/debian.svg new file mode 100644 index 00000000..9c5725da --- /dev/null +++ b/assets/os-icons/debian.svg @@ -0,0 +1,2 @@ + + diff --git a/assets/os-icons/fedora.svg b/assets/os-icons/fedora.svg new file mode 100644 index 00000000..ce100199 --- /dev/null +++ b/assets/os-icons/fedora.svg @@ -0,0 +1,2 @@ + + diff --git a/assets/os-icons/linux.svg b/assets/os-icons/linux.svg new file mode 100644 index 00000000..b33dde95 --- /dev/null +++ b/assets/os-icons/linux.svg @@ -0,0 +1,2 @@ + + diff --git a/assets/os-icons/nixos.svg b/assets/os-icons/nixos.svg new file mode 100644 index 00000000..838a9fe9 --- /dev/null +++ b/assets/os-icons/nixos.svg @@ -0,0 +1,2 @@ + + diff --git a/assets/os-icons/opensuse.svg b/assets/os-icons/opensuse.svg new file mode 100644 index 00000000..563f3b95 --- /dev/null +++ b/assets/os-icons/opensuse.svg @@ -0,0 +1,2 @@ + + diff --git a/assets/os-icons/steam.svg b/assets/os-icons/steam.svg new file mode 100644 index 00000000..7de6ae2c --- /dev/null +++ b/assets/os-icons/steam.svg @@ -0,0 +1,2 @@ + + diff --git a/assets/os-icons/ubuntu.svg b/assets/os-icons/ubuntu.svg new file mode 100644 index 00000000..7aba304f --- /dev/null +++ b/assets/os-icons/ubuntu.svg @@ -0,0 +1,2 @@ + + diff --git a/assets/os-icons/windows.svg b/assets/os-icons/windows.svg new file mode 100644 index 00000000..3899dc4e --- /dev/null +++ b/assets/os-icons/windows.svg @@ -0,0 +1,2 @@ + + diff --git a/crates/punktfunk-host/src/discovery.rs b/crates/punktfunk-host/src/discovery.rs index 7484871e..a96d867e 100644 --- a/crates/punktfunk-host/src/discovery.rs +++ b/crates/punktfunk-host/src/discovery.rs @@ -18,6 +18,9 @@ //! - `mac` — the host's wake-capable NIC MAC(s) (comma-separated, routed NIC first), which a client //! persists so it can Wake-on-LAN this host after it sleeps. Advisory/unauthenticated (a wrong //! MAC only makes a wake fail). Omitted when none can be read. +//! - `os` — the host's OS identity chain (`windows` | `macos` | `linux[/][/]`, e.g. +//! `linux/fedora/bazzite` — see [`crate::osinfo`]), so a client can show an OS icon on the host +//! card. Advisory/unauthenticated like `mac`: a wrong value only draws a wrong icon. use anyhow::{Context, Result}; use mdns_sd::{ServiceDaemon, ServiceInfo}; @@ -87,6 +90,9 @@ pub struct Advert { /// `require_pairing` tells a discovering client whether it must pair before it can stream; /// `mgmt_port` is the management API's port (`Some` when this host serves one — the client browses /// the library there over mTLS on the advertised IP), `None` for a host with no mgmt API. +// One parameter per TXT key, single call site — a params struct would just restate the +// module doc's key list with extra ceremony. +#[allow(clippy::too_many_arguments)] pub fn advertise_native( hostname: &str, ip: IpAddr, @@ -95,6 +101,7 @@ pub fn advertise_native( require_pairing: bool, uniqueid: &str, mgmt_port: Option, + os_chain: &str, ) -> Result { let daemon = ServiceDaemon::new().context("create mDNS daemon")?; // `hostname` is the DISPLAY name (the instance label clients read back); the A-record target @@ -116,6 +123,10 @@ pub fn advertise_native( if let Some(mgmt) = mgmt_port { props.insert("mgmt".into(), mgmt.to_string()); } + // `os` — advisory OS-identity chain for the client's host-card icon (see module doc). + if !os_chain.is_empty() { + props.insert("os".into(), os_chain.to_string()); + } // `mac` — the host's wake-capable NIC MAC(s), comma-separated `aa:bb:cc:dd:ee:ff`, routed NIC // first. A client persists these while the host is awake so it can send a Wake-on-LAN magic // packet to wake it later (when it's asleep and no longer advertising). Unauthenticated like diff --git a/crates/punktfunk-host/src/gamestream/mod.rs b/crates/punktfunk-host/src/gamestream/mod.rs index 7c03d852..f7f304d2 100644 --- a/crates/punktfunk-host/src/gamestream/mod.rs +++ b/crates/punktfunk-host/src/gamestream/mod.rs @@ -119,17 +119,25 @@ pub struct Host { pub local_ip: IpAddr, pub http_port: u16, pub https_port: u16, + /// OS identity chain (`windows` | `macos` | `linux[/][/]`), advertised in the + /// mDNS `os=` TXT record and `HostInfo.os` so clients can show an OS icon. + pub os_chain: String, + /// Human-readable OS name (os-release `PRETTY_NAME`), surfaced as `HostInfo.os_name` only. + pub os_name: String, // Pairing state (server cert, paired client certs) lands in the next P1.1 slice. } impl Host { pub fn detect() -> Result { + let os = crate::osinfo::detect(); Ok(Host { hostname: hostname_string(), uniqueid: load_or_create_uniqueid()?, local_ip: primary_local_ip().unwrap_or(IpAddr::V4(Ipv4Addr::LOCALHOST)), http_port: HTTP_PORT, https_port: HTTPS_PORT, + os_chain: os.chain.clone(), + os_name: os.pretty.clone(), }) } } @@ -578,6 +586,8 @@ mod session_tests { local_ip: IpAddr::V4(Ipv4Addr::LOCALHOST), http_port: HTTP_PORT, https_port: HTTPS_PORT, + os_chain: "linux".into(), + os_name: "Linux".into(), }; let identity = cert::ServerIdentity::ephemeral().expect("ephemeral identity"); let stats = crate::stats_recorder::StatsRecorder::new(std::env::temp_dir().join(format!( diff --git a/crates/punktfunk-host/src/gamestream/nvhttp.rs b/crates/punktfunk-host/src/gamestream/nvhttp.rs index 9b13986b..4c0e4af2 100644 --- a/crates/punktfunk-host/src/gamestream/nvhttp.rs +++ b/crates/punktfunk-host/src/gamestream/nvhttp.rs @@ -427,6 +427,8 @@ mod tests { local_ip: IpAddr::V4(Ipv4Addr::LOCALHOST), http_port: HTTP_PORT, https_port: HTTPS_PORT, + os_chain: "linux".into(), + os_name: "Linux".into(), }; let identity = super::super::cert::ServerIdentity::ephemeral().expect("ephemeral identity"); let stats = crate::stats_recorder::StatsRecorder::new( diff --git a/crates/punktfunk-host/src/gamestream/serverinfo.rs b/crates/punktfunk-host/src/gamestream/serverinfo.rs index fc62994d..f7e4e4b4 100644 --- a/crates/punktfunk-host/src/gamestream/serverinfo.rs +++ b/crates/punktfunk-host/src/gamestream/serverinfo.rs @@ -208,6 +208,8 @@ mod tests { local_ip: std::net::IpAddr::V4(std::net::Ipv4Addr::LOCALHOST), http_port: 47989, https_port: 47984, + os_chain: "linux".into(), + os_name: "Linux".into(), }; let xml = serverinfo_xml(&host, false, false); // The mask is the GPU-aware value (NVENC/no-GPU → the static 65793; a VAAPI host → diff --git a/crates/punktfunk-host/src/main.rs b/crates/punktfunk-host/src/main.rs index 7a9b72b9..dcea7120 100644 --- a/crates/punktfunk-host/src/main.rs +++ b/crates/punktfunk-host/src/main.rs @@ -77,6 +77,7 @@ mod mgmt; mod mgmt_token; mod native; mod native_pairing; +mod osinfo; mod pipeline; mod plugins; // Finding a launched game's processes from its store's detect signals — the read side of the diff --git a/crates/punktfunk-host/src/mgmt/host.rs b/crates/punktfunk-host/src/mgmt/host.rs index ae0cb91d..0d03acee 100644 --- a/crates/punktfunk-host/src/mgmt/host.rs +++ b/crates/punktfunk-host/src/mgmt/host.rs @@ -39,6 +39,14 @@ pub(crate) struct HostInfo { app_version: String, /// GFE version advertised to Moonlight clients. gfe_version: String, + /// OS identity chain, generic → most specific, slash-separated (`windows` | `macos` | + /// `linux[/][/]`). A client walks it most-specific-first and shows the first + /// token it has an icon for, so an unknown distro still degrades to its family's mark. + #[schema(example = "linux/fedora/bazzite")] + os: String, + /// Human-readable OS name (os-release `PRETTY_NAME`; `"Windows"`/`"macOS"` elsewhere). + #[schema(example = "Bazzite 42 (Kinoite)")] + os_name: String, /// Codecs the host can encode (NVENC). codecs: Vec, /// Whether the GameStream/Moonlight-compat planes are running (`--gamestream`). `false` on the @@ -262,6 +270,8 @@ pub(crate) async fn get_host_info(State(st): State>) -> Json Arc { local_ip: IpAddr::V4(Ipv4Addr::LOCALHOST), http_port: HTTP_PORT, https_port: HTTPS_PORT, + os_chain: "linux/arch/steamos".into(), + os_name: "SteamOS".into(), }; let identity = ServerIdentity::ephemeral().expect("ephemeral identity"); Arc::new(AppState::new(host, identity, test_stats())) @@ -623,6 +625,10 @@ async fn host_info_reports_identity_and_ports() { assert_eq!(status, StatusCode::OK); assert_eq!(body["hostname"], "test-host"); assert_eq!(body["uniqueid"], "deadbeef"); + // OS identity rides along verbatim from the detected Host (chain for the icon walk, + // pretty name for the human label). + assert_eq!(body["os"], "linux/arch/steamos"); + assert_eq!(body["os_name"], "SteamOS"); assert_eq!(body["ports"]["http"], HTTP_PORT); assert_eq!(body["ports"]["mgmt"], DEFAULT_PORT); // Codecs are GPU-aware (derived from `Codec::host_wire_caps`), so assert against that mask diff --git a/crates/punktfunk-host/src/native.rs b/crates/punktfunk-host/src/native.rs index 7918e34b..0080f2a5 100644 --- a/crates/punktfunk-host/src/native.rs +++ b/crates/punktfunk-host/src/native.rs @@ -318,6 +318,7 @@ pub(crate) async fn serve( &h.uniqueid, // 0 = standalone `punktfunk1-host` (no mgmt API) → don't advertise an `mgmt` port. (mgmt_port != 0).then_some(mgmt_port), + &h.os_chain, ) .map_err(|e| tracing::warn!(error = %format!("{e:#}"), "native mDNS advertise failed (continuing)")) .ok(), diff --git a/crates/punktfunk-host/src/osinfo.rs b/crates/punktfunk-host/src/osinfo.rs new file mode 100644 index 00000000..67ef876a --- /dev/null +++ b/crates/punktfunk-host/src/osinfo.rs @@ -0,0 +1,265 @@ +//! Host OS identity for client-facing surfaces: an icon-friendly **specificity chain** plus a +//! human-readable name. +//! +//! The chain is slash-separated, generic → specific, `family[/like][/id]`: +//! `windows`, `macos`, `linux`, `linux/debian/ubuntu`, `linux/fedora/bazzite`, +//! `linux/arch/steamos`. Clients walk it most-specific-first and show the first token they have +//! art for — a client with no Bazzite mark lands on `fedora`, then generic `linux` — so the host +//! always emits the *full* chain and clients need zero distro→parent knowledge. On Linux the +//! middle token is the first `ID_LIKE` ancestor we recognize ([`FAMILIES`]; `ID_LIKE` is ordered +//! most-similar-first per the os-release spec) and the leaf is `ID` verbatim, so even a distro we +//! never heard of still degrades to its family's icon. +//! +//! The chain rides the mDNS `os=` TXT record ([`crate::discovery`]) and the mgmt API's +//! `HostInfo.os`; the pretty name (`PRETTY_NAME`) is REST-only — TXT stays small. Both values are +//! advisory identity, same trust posture as the `mac` TXT key: unauthenticated, and a wrong value +//! only draws a wrong icon. + +use std::sync::OnceLock; + +/// The host's OS identity, detected once per process (os-release is static for its lifetime). +pub struct OsInfo { + /// `windows` | `macos` | `linux[/][/]` — see the module doc for the grammar. + pub chain: String, + /// Human-readable OS name (os-release `PRETTY_NAME`; `"Windows"`/`"macOS"` elsewhere). + pub pretty: String, +} + +/// Detect (once) and return the host's OS identity. +pub fn detect() -> &'static OsInfo { + static OS: OnceLock = OnceLock::new(); + OS.get_or_init(|| { + if cfg!(target_os = "windows") { + OsInfo { + chain: "windows".into(), + pretty: "Windows".into(), + } + } else if cfg!(target_os = "macos") { + // The host only runs on Windows/Linux; macOS is the dev-build platform. + OsInfo { + chain: "macos".into(), + pretty: "macOS".into(), + } + } else { + linux_os_info() + } + }) +} + +/// `ID_LIKE` ancestors worth keeping as the chain's middle token — the distros clients plausibly +/// have icon art for. Anything else (or no `ID_LIKE` at all) yields a two-segment chain and the +/// leaf still identifies the distro exactly. +const FAMILIES: &[&str] = &[ + "debian", "ubuntu", "fedora", "rhel", "arch", "opensuse", "suse", "gentoo", "alpine", "nixos", +]; + +/// Read os-release from its two spec'd locations (`/etc` overrides the `/usr/lib` fallback); +/// a host with neither (or unreadable) is simply `linux`. +fn linux_os_info() -> OsInfo { + ["/etc/os-release", "/usr/lib/os-release"] + .iter() + .find_map(|p| std::fs::read_to_string(p).ok()) + .map(|s| parse_os_release(&s)) + .unwrap_or_else(|| OsInfo { + chain: "linux".into(), + pretty: "Linux".into(), + }) +} + +/// Pure os-release parser (compiled on every target so the tests run on any dev box). +/// +/// Grammar per the freedesktop spec subset we need: `KEY=value` lines, values optionally +/// `"`/`'`-quoted. `ID`/`ID_LIKE` tokens are lowercased and sanitized before they feed a DNS TXT +/// record; `PRETTY_NAME` falls back `NAME` → capitalized `ID` → `"Linux"`. +fn parse_os_release(contents: &str) -> OsInfo { + let (mut id, mut id_like, mut pretty, mut name) = (None, None, None, None); + for line in contents.lines() { + let line = line.trim(); + if let Some(v) = line.strip_prefix("ID=") { + id = Some(unquote(v)); + } else if let Some(v) = line.strip_prefix("ID_LIKE=") { + id_like = Some(unquote(v)); + } else if let Some(v) = line.strip_prefix("PRETTY_NAME=") { + pretty = Some(unquote(v)); + } else if let Some(v) = line.strip_prefix("NAME=") { + name = Some(unquote(v)); + } + } + + let id_tok = id.as_deref().and_then(sanitize_token); + // First *recognized* ID_LIKE ancestor wins (the list is ordered most-similar-first), skipping + // a token that merely repeats ID (some distros write `ID_LIKE` reflexively). + let like_tok = id_like + .as_deref() + .unwrap_or("") + .split_whitespace() + .filter_map(sanitize_token) + .find(|t| FAMILIES.contains(&t.as_str()) && Some(t) != id_tok.as_ref()); + + let mut chain = String::from("linux"); + for tok in [&like_tok, &id_tok].into_iter().flatten() { + chain.push('/'); + chain.push_str(tok); + } + + let pretty = [pretty, name] + .into_iter() + .flatten() + .map(|s| s.trim().to_string()) + .find(|s| !s.is_empty()) + .or_else(|| id_tok.as_deref().map(capitalize)) + .unwrap_or_else(|| "Linux".into()); + + OsInfo { chain, pretty } +} + +/// Strip one matching pair of surrounding `"` or `'` quotes. +fn unquote(v: &str) -> String { + let v = v.trim(); + for q in ['"', '\''] { + if let Some(inner) = v.strip_prefix(q).and_then(|s| s.strip_suffix(q)) { + return inner.to_string(); + } + } + v.to_string() +} + +/// Lowercase and reduce an `ID`/`ID_LIKE` token to TXT-safe `[a-z0-9._-]`, capped at 32 chars; +/// `None` when nothing survives (a hostile or garbage value must not reach the advert). +fn sanitize_token(raw: &str) -> Option { + let tok: String = raw + .to_lowercase() + .chars() + .filter(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || matches!(c, '.' | '_' | '-')) + .take(32) + .collect(); + (!tok.is_empty()).then_some(tok) +} + +/// `ubuntu` → `Ubuntu` (ASCII-only; the fallback label when os-release names are absent). +fn capitalize(s: &str) -> String { + let mut chars = s.chars(); + match chars.next() { + Some(c) => c.to_ascii_uppercase().to_string() + chars.as_str(), + None => String::new(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn parsed(contents: &str) -> (String, String) { + let info = parse_os_release(contents); + (info.chain, info.pretty) + } + + #[test] + fn ubuntu_chains_through_debian() { + let (chain, pretty) = parsed( + "PRETTY_NAME=\"Ubuntu 24.04.2 LTS\"\nNAME=\"Ubuntu\"\nID=ubuntu\nID_LIKE=debian\n", + ); + assert_eq!(chain, "linux/debian/ubuntu"); + assert_eq!(pretty, "Ubuntu 24.04.2 LTS"); + } + + #[test] + fn bazzite_quoted_id_like() { + let (chain, pretty) = + parsed("ID=bazzite\nID_LIKE=\"fedora\"\nPRETTY_NAME=\"Bazzite 42 (Kinoite)\"\n"); + assert_eq!(chain, "linux/fedora/bazzite"); + assert_eq!(pretty, "Bazzite 42 (Kinoite)"); + } + + #[test] + fn steamos_is_arch_family() { + let (chain, _) = parsed("ID=steamos\nID_LIKE=arch\nPRETTY_NAME=\"SteamOS\"\n"); + assert_eq!(chain, "linux/arch/steamos"); + } + + #[test] + fn cachyos_is_arch_family() { + let (chain, _) = parsed("ID=cachyos\nID_LIKE=\"arch\"\nNAME=\"CachyOS Linux\"\n"); + assert_eq!(chain, "linux/arch/cachyos"); + } + + #[test] + fn nixos_without_id_like_is_two_segments() { + let (chain, _) = parsed("ID=nixos\nPRETTY_NAME=\"NixOS 25.05 (Warbler)\"\n"); + assert_eq!(chain, "linux/nixos"); + } + + #[test] + fn plain_root_distro() { + let (chain, _) = parsed("ID=arch\nNAME=\"Arch Linux\"\n"); + assert_eq!(chain, "linux/arch"); + } + + #[test] + fn multi_ancestor_id_like_takes_first_recognized() { + // centos: ID_LIKE is most-similar-first — rhel wins over fedora. + let (chain, _) = parsed("ID=\"centos\"\nID_LIKE=\"rhel fedora\"\n"); + assert_eq!(chain, "linux/rhel/centos"); + } + + #[test] + fn pop_takes_ubuntu_over_debian() { + let (chain, _) = parsed("ID=pop\nID_LIKE=\"ubuntu debian\"\n"); + assert_eq!(chain, "linux/ubuntu/pop"); + } + + #[test] + fn reflexive_id_like_is_skipped() { + let (chain, _) = parsed("ID=fedora\nID_LIKE=fedora\n"); + assert_eq!(chain, "linux/fedora"); + } + + #[test] + fn unrecognized_id_like_is_dropped_leaf_kept() { + let (chain, _) = parsed("ID=chimera\nID_LIKE=frontier\n"); + assert_eq!(chain, "linux/chimera"); + } + + #[test] + fn garbage_and_empty_fall_back_to_linux() { + assert_eq!(parsed("").0, "linux"); + assert_eq!(parsed("not an os-release file at all\n===\n").0, "linux"); + assert_eq!(parsed("").1, "Linux"); + } + + #[test] + fn hostile_id_is_sanitized_for_txt() { + // Quotes/spaces/slashes must never reach the TXT record or split the chain. + let (chain, _) = parsed("ID=\"Ubu ntu/EVIL=1\"\n"); + assert_eq!(chain, "linux/ubuntuevil1"); + } + + #[test] + fn overlong_id_is_capped() { + let long = "x".repeat(80); + let (chain, _) = parsed(&format!("ID={long}\n")); + assert_eq!(chain, format!("linux/{}", "x".repeat(32))); + } + + #[test] + fn pretty_falls_back_name_then_id() { + assert_eq!( + parsed("ID=debian\nNAME=\"Debian GNU/Linux\"\n").1, + "Debian GNU/Linux" + ); + assert_eq!(parsed("ID=debian\n").1, "Debian"); + } + + #[test] + fn single_quoted_values() { + let (chain, pretty) = parsed("ID='opensuse-tumbleweed'\nID_LIKE='opensuse suse'\nPRETTY_NAME='openSUSE Tumbleweed'\n"); + assert_eq!(chain, "linux/opensuse/opensuse-tumbleweed"); + assert_eq!(pretty, "openSUSE Tumbleweed"); + } + + #[test] + fn crlf_and_padding_tolerated() { + let (chain, _) = parsed(" ID=ubuntu \r\n\tID_LIKE=debian\r\n"); + assert_eq!(chain, "linux/debian/ubuntu"); + } +} diff --git a/scripts/gen-third-party-notices.py b/scripts/gen-third-party-notices.py index ca66923e..e99e5211 100755 --- a/scripts/gen-third-party-notices.py +++ b/scripts/gen-third-party-notices.py @@ -61,6 +61,14 @@ VENDORED_TREES = [ ("Vulkan-Headers (vendored, crates/pyrowave-sys)", "crates/pyrowave-sys/vendor/pyrowave/Granite/third_party/khronos/vulkan-headers/LICENSE.md", "https://github.com/KhronosGroup/Vulkan-Headers"), + # OS brand marks for the host-card OS icon (assets/os-icons/, CC BY 4.0 / CC0 — + # see assets/os-icons/README.md; clients embed per-platform derivatives). + ("Font Awesome Free brand icons (vendored, assets/os-icons)", + "assets/os-icons/LICENSES/font-awesome-brands.txt", + "https://fontawesome.com"), + ("Simple Icons (vendored, assets/os-icons)", + "assets/os-icons/LICENSES/simple-icons.txt", + "https://simpleicons.org"), ] diff --git a/sdk/src/gen/punktfunk.ts b/sdk/src/gen/punktfunk.ts index ac6896cb..d9997d39 100644 --- a/sdk/src/gen/punktfunk.ts +++ b/sdk/src/gen/punktfunk.ts @@ -19,6 +19,8 @@ export type ApiError = { readonly "error": string } export const ApiError = Schema.Struct({ "error": Schema.String }).annotate({ "description": "Error envelope for every non-2xx response." }) export type ApiGpu = { readonly "id": string, readonly "name": string, readonly "vendor": string, readonly "vram_mb": number } export const ApiGpu = Schema.Struct({ "id": Schema.String.annotate({ "description": "Stable identifier (`vendorid-deviceid-occurrence`, hex PCI ids) — pass to `setGpuPreference`.\nStable across reboots and driver updates, unlike an adapter index or LUID." }), "name": Schema.String.annotate({ "description": "Adapter/marketing name." }), "vendor": Schema.String.annotate({ "description": "`nvidia` | `amd` | `intel` | `other`." }), "vram_mb": Schema.Number.annotate({ "description": "Dedicated VRAM in MiB (0 where the platform doesn't expose it).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "One hardware GPU on the host (software/WARP adapters are never listed)." }) +export type ApiMonitorInfo = { readonly "connector": string, readonly "description": string, readonly "enabled": boolean, readonly "managed": boolean, readonly "mode": string, readonly "primary": boolean, readonly "scale": number, readonly "selected": boolean, readonly "x": number, readonly "y": number } +export const ApiMonitorInfo = Schema.Struct({ "connector": Schema.String.annotate({ "description": "Connector name (`DP-1`, `HDMI-A-2`) — the value `PUNKTFUNK_CAPTURE_MONITOR` takes." }), "description": Schema.String.annotate({ "description": "Human label for a picker (`make model`, else the connector)." }), "enabled": Schema.Boolean.annotate({ "description": "Driven right now. A disabled head is still listed, so it can be explained rather than missing." }), "managed": Schema.Boolean.annotate({ "description": "Best-effort: this is one of OUR virtual displays, not a real head (reliable on KWin only)." }), "mode": Schema.String.annotate({ "description": "`WIDTHxHEIGHT@HZ` of the current mode (size only when the refresh is unknown)." }), "primary": Schema.Boolean.annotate({ "description": "The compositor's primary/focused head." }), "scale": Schema.Number.annotate({ "description": "Logical scale factor.", "format": "double" }).check(Schema.isFinite()), "selected": Schema.Boolean.annotate({ "description": "True when `PUNKTFUNK_CAPTURE_MONITOR` currently names this monitor." }), "x": Schema.Number.annotate({ "description": "Desktop-space top-left — what makes a head identifiable when two share a size.", "format": "int32" }).check(Schema.isInt()), "y": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()) }).annotate({ "description": "One physical monitor this host has, as the compositor reports it." }) export type ApprovePending = { readonly "name"?: string | null } export const ApprovePending = Schema.Struct({ "name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Operator-chosen label for the device (defaults to the name it knocked with)." })) }).annotate({ "description": "Approve-pending-device request body. Send `{}` to keep the device's own name." }) export type ArmNativePairing = { readonly "fingerprint"?: string | null, readonly "ttl_secs"?: never } @@ -27,8 +29,8 @@ export type Artwork = { readonly "header"?: string | null, readonly "hero"?: str export const Artwork = Schema.Struct({ "header": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Horizontal header (Steam `header.jpg`) — the universal fallback." })), "hero": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Wide background (Steam `library_hero.jpg`)." })), "logo": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Transparent title logo (Steam `logo.png`)." })), "portrait": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Vertical capsule / poster (Steam `library_600x900.jpg`). Best for a grid." })) }).annotate({ "description": "Cover art for a title. All fields are URLs (the Steam CDN for Steam titles, user-supplied for\ncustom). The client prefers `portrait` for a grid and falls back to `header` when a title has\nno 600×900 capsule (common for older Steam apps)." }) export type AvailableCompositor = { readonly "available": boolean, readonly "default": boolean, readonly "id": string, readonly "label": string } export const AvailableCompositor = Schema.Struct({ "available": Schema.Boolean.annotate({ "description": "Usable on this host right now: the live session's own compositor, or gamescope wherever\nits binary is installed." }), "default": Schema.Boolean.annotate({ "description": "True for the backend an `Auto` (unspecified) request resolves to right now." }), "id": Schema.String.annotate({ "description": "Stable identifier (`\"kwin\"` | `\"wlroots\"` | `\"mutter\"` | `\"gamescope\"`) — pass this to a\nclient's `--compositor` flag." }), "label": Schema.String.annotate({ "description": "Human-readable label for UIs." }) }).annotate({ "description": "A compositor backend the host can drive a virtual output on, and whether it's usable now." }) -export type CaptureMeta = { readonly "client": string, readonly "codec": string, readonly "duration_ms": number, readonly "fps": number, readonly "height": number, readonly "id": string, readonly "kind": string, readonly "sample_count": number, readonly "started_unix_ms": number, readonly "width": number } -export const CaptureMeta = Schema.Struct({ "client": Schema.String.annotate({ "description": "Short label / fingerprint prefix, or `\"\"` if unknown." }), "codec": Schema.String.annotate({ "description": "`\"h264\" | \"hevc\" | \"av1\"`." }), "duration_ms": Schema.Number.annotate({ "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "fps": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "height": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "id": Schema.String.annotate({ "description": "e.g. `\"2026-06-26T20-14-03Z_5120x1440\"` — also the filename stem." }), "kind": Schema.String.annotate({ "description": "`\"native\" | \"gamestream\"`." }), "sample_count": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "started_unix_ms": Schema.Number.annotate({ "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "width": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "Capture summary — the filename stem plus the negotiated mode/codec/client. Stored at the head\nof each on-disk recording and listed standalone (without the sample body) by\n[`StatsRecorder::list`]." }) +export type CaptureMeta = { readonly "client": string, readonly "codec": string, readonly "duration_ms": number, readonly "encoder_backend"?: string, readonly "fps": number, readonly "gpu"?: string, readonly "height": number, readonly "id": string, readonly "kind": string, readonly "sample_count": number, readonly "started_unix_ms": number, readonly "width": number } +export const CaptureMeta = Schema.Struct({ "client": Schema.String.annotate({ "description": "Short label / fingerprint prefix, or `\"\"` if unknown." }), "codec": Schema.String.annotate({ "description": "`\"h264\" | \"hevc\" | \"av1\"`." }), "duration_ms": Schema.Number.annotate({ "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "encoder_backend": Schema.optionalKey(Schema.String.annotate({ "description": "The encode backend that ACTUALLY opened for this session — `\"nvenc\"`, `\"vaapi\"`,\n`\"vulkan\"`, `\"amf\"`, `\"qsv\"`, `\"software\"`, … — and the GPU it runs on.\n\nRecorded because the stage split alone can't be read without them. A p50 `submit` of 10 ms\nmeans \"the GPU's CSC+encode throughput is the ceiling\" on one backend and something else\nentirely on another, and every fps-shortfall report so far has cost a round-trip asking\nwhich one it was. Both come from `pf_gpu::active()`, the record the encoder open itself\nwrites, so they name the branch that really opened rather than a re-derived guess.\n\n`\"\"` when nothing was streaming at registration (or on a build without the record)." })), "fps": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "gpu": Schema.optionalKey(Schema.String.annotate({ "description": "Human-readable GPU name (`\"NVIDIA GeForce RTX 4090\"`, `\"CPU (openh264)\"`), or `\"\"`." })), "height": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "id": Schema.String.annotate({ "description": "e.g. `\"2026-06-26T20-14-03Z_5120x1440\"` — also the filename stem." }), "kind": Schema.String.annotate({ "description": "`\"native\" | \"gamestream\"`." }), "sample_count": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "started_unix_ms": Schema.Number.annotate({ "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "width": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "Capture summary — the filename stem plus the negotiated mode/codec/client. Stored at the head\nof each on-disk recording and listed standalone (without the sample body) by\n[`StatsRecorder::list`]." }) export type CatalogEntry = { readonly "author": string, readonly "blocked"?: string | null, readonly "compatible": boolean, readonly "description": string, readonly "homepage"?: string | null, readonly "icon"?: string | null, readonly "id": string, readonly "incompatible_reason"?: string | null, readonly "installed_version"?: string | null, readonly "license"?: string | null, readonly "min_host"?: string | null, readonly "pkg": string, readonly "platforms": ReadonlyArray, readonly "reviewed_at"?: string | null, readonly "source": string, readonly "tier": string, readonly "title": string, readonly "update_available": boolean, readonly "version": string } export const CatalogEntry = Schema.Struct({ "author": Schema.String, "blocked": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "A revocation covering the catalogued version — do not offer this without shouting." })), "compatible": Schema.Boolean.annotate({ "description": "Can this host install it?" }), "description": Schema.String, "homepage": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), "icon": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), "id": Schema.String, "incompatible_reason": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), "installed_version": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The version installed right now, if any." })), "license": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), "min_host": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), "pkg": Schema.String, "platforms": Schema.Array(Schema.String), "reviewed_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "When unom reviewed this exact tarball (built-in source only)." })), "source": Schema.String.annotate({ "description": "Which source listed it." }), "tier": Schema.String.annotate({ "description": "`verified` (built-in source) or `external` (an operator-added source). Never `unverified`:\nunverified installs come from a raw spec and are never listed (D7)." }), "title": Schema.String, "update_available": Schema.Boolean.annotate({ "description": "Installed, but at a different version than the catalog pins." }), "version": Schema.String.annotate({ "description": "The one installable version this entry pins." }) }).annotate({ "description": "One row on the shelf." }) export type DisconnectReason = "quit" | "timeout" | "error" @@ -131,12 +133,14 @@ export type UiCredential = { readonly "port": number, readonly "secret": string export const UiCredential = Schema.Struct({ "port": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "secret": Schema.String }).annotate({ "description": "`GET /plugins/{id}/ui-credential` — the console proxy's server-side lookup (bearer + loopback).\nThis is the only endpoint that returns a secret; the console BFF denylists it from the browser." }) export type UninstallRequest = { readonly "pkg": string } export const UninstallRequest = Schema.Struct({ "pkg": Schema.String }) -export type RuntimeStatus = { readonly "active_sessions": number, readonly "audio_streaming": boolean, readonly "games": ReadonlyArray, readonly "paired_clients": number, readonly "pin_pending": boolean, readonly "session"?: null | { readonly "fps": number, readonly "height": number, readonly "width": number }, readonly "stream"?: null | { readonly "bitrate_kbps": number, readonly "codec": ApiCodec, readonly "fps": number, readonly "height": number, readonly "last_resize_ms"?: never, readonly "min_fec": number, readonly "packet_size": number, readonly "time_to_first_frame_ms"?: never, readonly "width": number }, readonly "video_streaming": boolean } -export const RuntimeStatus = Schema.Struct({ "active_sessions": Schema.Number.annotate({ "description": "Number of live streaming sessions across BOTH planes (GameStream + native punktfunk/1). The\nnative server admits concurrent sessions, so this can exceed 1; `session`/`stream` below\ndescribe a single representative session for the detail card.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "audio_streaming": Schema.Boolean.annotate({ "description": "True while the audio stream thread is running." }), "games": Schema.Array(ActiveGame).annotate({ "description": "Every launched game the host is tracking: one row per live session that launched a title, plus\nany game whose session has ended and which is waiting out its reconnect window before being\nended (`state: \"grace\"`). Empty when nothing was launched — a plain desktop stream has no game." }), "paired_clients": Schema.Number.annotate({ "description": "Number of pinned (paired) client certificates.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "pin_pending": Schema.Boolean.annotate({ "description": "True while a pairing handshake is parked waiting for the user's PIN\n(submit it via `POST /api/v1/pair/pin`)." }), "session": Schema.optionalKey(Schema.Union([Schema.Null, Schema.Struct({ "fps": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "height": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "width": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "A representative active session. GameStream's launch (Moonlight `/launch`) when present, else\nthe first live native session. `null` when nothing is streaming." })], { mode: "oneOf" })), "stream": Schema.optionalKey(Schema.Union([Schema.Null, Schema.Struct({ "bitrate_kbps": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "codec": ApiCodec, "fps": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "height": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "last_resize_ms": Schema.optionalKey(Schema.Never), "min_fec": Schema.Number.annotate({ "description": "Client's parity floor per FEC block (`minRequiredFecPackets`).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "packet_size": Schema.Number.annotate({ "description": "Video payload size per packet (bytes).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "time_to_first_frame_ms": Schema.optionalKey(Schema.Never), "width": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "The active stream's parameters — RTSP-negotiated for GameStream, or the live native session's\nmode/codec/bitrate. `null` when nothing is streaming." })], { mode: "oneOf" })), "video_streaming": Schema.Boolean.annotate({ "description": "True while the video stream thread is running." }) }).annotate({ "description": "Live host status (changes as clients launch/end sessions)." }) +export type RuntimeStatus = { readonly "active_sessions": number, readonly "audio_streaming": boolean, readonly "games": ReadonlyArray, readonly "native_paired_clients": number, readonly "paired_clients": number, readonly "pin_pending": boolean, readonly "session"?: null | { readonly "fps": number, readonly "height": number, readonly "width": number }, readonly "stream"?: null | { readonly "bitrate_kbps": number, readonly "codec": ApiCodec, readonly "fps": number, readonly "height": number, readonly "last_resize_ms"?: never, readonly "min_fec": number, readonly "packet_size": number, readonly "time_to_first_frame_ms"?: never, readonly "width": number }, readonly "video_streaming": boolean } +export const RuntimeStatus = Schema.Struct({ "active_sessions": Schema.Number.annotate({ "description": "Number of live streaming sessions across BOTH planes (GameStream + native punktfunk/1). The\nnative server admits concurrent sessions, so this can exceed 1; `session`/`stream` below\ndescribe a single representative session for the detail card.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "audio_streaming": Schema.Boolean.annotate({ "description": "True while the audio stream thread is running." }), "games": Schema.Array(ActiveGame).annotate({ "description": "Every launched game the host is tracking: one row per live session that launched a title, plus\nany game whose session has ended and which is waiting out its reconnect window before being\nended (`state: \"grace\"`). Empty when nothing was launched — a plain desktop stream has no game." }), "native_paired_clients": Schema.Number.annotate({ "description": "Number of paired native (punktfunk/1) devices — the default plane, so on a host that has\nnever been touched by Moonlight this is the only non-zero one of the pair.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "paired_clients": Schema.Number.annotate({ "description": "Number of pinned (paired) GameStream client certificates. Native (punktfunk/1) devices pair\nagainst a separate store and are counted in `native_paired_clients` — sum the two for\n\"how many clients are paired with this host\".", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "pin_pending": Schema.Boolean.annotate({ "description": "True while a pairing handshake is parked waiting for the user's PIN\n(submit it via `POST /api/v1/pair/pin`)." }), "session": Schema.optionalKey(Schema.Union([Schema.Null, Schema.Struct({ "fps": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "height": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "width": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "A representative active session. GameStream's launch (Moonlight `/launch`) when present, else\nthe first live native session. `null` when nothing is streaming." })], { mode: "oneOf" })), "stream": Schema.optionalKey(Schema.Union([Schema.Null, Schema.Struct({ "bitrate_kbps": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "codec": ApiCodec, "fps": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "height": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "last_resize_ms": Schema.optionalKey(Schema.Never), "min_fec": Schema.Number.annotate({ "description": "Client's parity floor per FEC block (`minRequiredFecPackets`).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "packet_size": Schema.Number.annotate({ "description": "Video payload size per packet (bytes).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "time_to_first_frame_ms": Schema.optionalKey(Schema.Never), "width": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "The active stream's parameters — RTSP-negotiated for GameStream, or the live native session's\nmode/codec/bitrate. `null` when nothing is streaming." })], { mode: "oneOf" })), "video_streaming": Schema.Boolean.annotate({ "description": "True while the video stream thread is running." }) }).annotate({ "description": "Live host status (changes as clients launch/end sessions)." }) export type DisplayStateResponse = { readonly "displays": ReadonlyArray } export const DisplayStateResponse = Schema.Struct({ "displays": Schema.Array(ApiDisplayInfo) }).annotate({ "description": "The host's managed virtual displays right now." }) export type GpuState = { readonly "active"?: null | { readonly "backend": string, readonly "id": string, readonly "name": string, readonly "sessions": number, readonly "vendor": string }, readonly "encoder_pin"?: string | null, readonly "env_override"?: string | null, readonly "gpus": ReadonlyArray, readonly "mode": string, readonly "preferred_available": boolean, readonly "preferred_id"?: string | null, readonly "preferred_name"?: string | null, readonly "selected"?: null | { readonly "id": string, readonly "name": string, readonly "source": string, readonly "vendor": string } } export const GpuState = Schema.Struct({ "active": Schema.optionalKey(Schema.Union([Schema.Null, Schema.Struct({ "backend": Schema.String.annotate({ "description": "The encode backend in use (`nvenc` | `amf` | `qsv` | `vaapi` | `software`)." }), "id": Schema.String.annotate({ "description": "Stable id matching an entry of `gpus` (empty for the CPU/software encoder)." }), "name": Schema.String, "sessions": Schema.Number.annotate({ "description": "Number of live encode sessions on it.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "vendor": Schema.String.annotate({ "description": "`nvidia` | `amd` | `intel` | `other`." }) }).annotate({ "description": "The GPU live sessions use right now (absent while nothing is streaming)." })], { mode: "oneOf" })), "encoder_pin": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "`PUNKTFUNK_ENCODER` (the host.env encoder pin), when set to something other than `auto`\n(e.g. `qsv`, `nvenc`, `amf`, `software`). A pin whose vendor contradicts the selected\nGPU is overridden at session open — the adapter wins — so the console can warn that the\npin is stale rather than letting the selection look broken." })), "env_override": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "`PUNKTFUNK_RENDER_ADAPTER` (the host.env pin), when set — it applies while `mode` is\n`auto`; a manual preference overrides it." })), "gpus": Schema.Array(ApiGpu).annotate({ "description": "The host's hardware GPUs." }), "mode": Schema.String.annotate({ "description": "`auto` or `manual`." }), "preferred_available": Schema.Boolean.annotate({ "description": "Whether the preferred GPU is currently present." }), "preferred_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The manually preferred GPU's stable id, when one is stored (kept while `mode` is `auto` so\na console can offer returning to it). May reference a GPU that is currently absent." })), "preferred_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The stored name of the preferred GPU (a usable label even when it is absent)." })), "selected": Schema.optionalKey(Schema.Union([Schema.Null, Schema.Struct({ "id": Schema.String, "name": Schema.String, "source": Schema.String.annotate({ "description": "Why this GPU was selected: `preference` (the manual choice), `env`\n(`PUNKTFUNK_RENDER_ADAPTER`), `auto` (max dedicated VRAM / platform default), or\n`preference_missing` (a manual choice is set but that GPU is absent — auto-selected\ninstead so the host keeps streaming)." }), "vendor": Schema.String.annotate({ "description": "`nvidia` | `amd` | `intel` | `other`." }) }).annotate({ "description": "The GPU the next session will use." })], { mode: "oneOf" })) }).annotate({ "description": "Full GPU-selection state for the console: inventory, the persisted preference, what the next\nsession will use, and what is in use right now." }) +export type MonitorsResponse = { readonly "compositor"?: string | null, readonly "error"?: string | null, readonly "monitors": ReadonlyArray, readonly "pin_supported": boolean, readonly "pinned"?: string | null } +export const MonitorsResponse = Schema.Struct({ "compositor": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Compositor backend the enumeration came from (`kwin`, `mutter`, …), when one was resolved." })), "error": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Why the list is empty, when enumeration failed (compositor unreachable, unsupported\nplatform). `None` with an empty list means \"asked, and there are none\"." })), "monitors": Schema.Array(ApiMonitorInfo).annotate({ "description": "The heads, ordered left-to-right by desktop position." }), "pin_supported": Schema.Boolean.annotate({ "description": "Whether this build can actually STREAM one of these monitors.\n\nEnumeration and capture are separate capabilities, and on Windows only the first exists: the\nheads below are real and worth showing (they explain the topology, and `/display/state`\ncross-references them), but `pf-capture`'s sole Windows entry point is `open_idd_push` — a\nframe channel pushed by our OWN IddCx virtual display. There is no desktop-duplication\ncapturer to point at a chosen head (DXGI Desktop Duplication was deliberately removed), so\n`vdisplay::open` has no mirror arm outside Linux and a pin could not be honored.\n\nThe console renders the picker read-only on `false`. Reported as a capability rather than\nsniffed client-side from the OS so the answer comes from the build that would have to honor\nit — when a Windows mirror backend lands, this flips and the UI needs no change." }), "pinned": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The configured `PUNKTFUNK_CAPTURE_MONITOR`, if any — reported even when it matches nothing,\nso the console can show \"pinned to DP-2, which this host doesn't have\"." })) }).annotate({ "description": "The host's physical monitors + which one capture is pinned to." }) export type GameEntry = { readonly "description"?: string | null, readonly "developer"?: string | null, readonly "genres"?: ReadonlyArray, readonly "platform"?: string | null, readonly "players"?: never, readonly "publisher"?: string | null, readonly "region"?: string | null, readonly "release_year"?: never, readonly "tags"?: ReadonlyArray, readonly "art": Artwork, readonly "id": string, readonly "launch"?: null | { readonly "kind": string, readonly "value": string }, readonly "provider"?: string | null, readonly "store": string, readonly "title": string } export const GameEntry = Schema.Struct({ "description": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Short blurb for a details pane." })), "developer": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), "genres": Schema.optionalKey(Schema.Array(Schema.String).annotate({ "description": "Genre taxonomy from the metadata source (`\"RPG\"`, `\"Platformer\"`, …)." })), "platform": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The system the title runs on — `\"PS2\"`, `\"Xbox 360\"`, `\"SNES\"`, … Installed-store\nscanners stamp `\"PC\"`; `GET /library?platform=` filters on it (case-insensitive)." })), "players": Schema.optionalKey(Schema.Never), "publisher": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), "region": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Release region — emulation-relevant (`\"NTSC-U\"`, `\"PAL\"`, `\"NTSC-J\"`)." })), "release_year": Schema.optionalKey(Schema.Never), "tags": Schema.optionalKey(Schema.Array(Schema.String).annotate({ "description": "Free-form organizational labels (`\"co-op\"`, `\"kids\"`, `\"finished\"`, …)." })), "art": Artwork, "id": Schema.String.annotate({ "description": "Stable, store-qualified id: `steam:` or `custom:`." }), "launch": Schema.optionalKey(Schema.Union([Schema.Null, Schema.Struct({ "kind": Schema.String.annotate({ "description": "`\"steam_appid\"` or `\"command\"`." }), "value": Schema.String.annotate({ "description": "The appid (for `steam_appid`) or the shell command (for `command`)." }) }).annotate({ "description": "How the host would launch it, when known." })], { mode: "oneOf" })), "provider": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The external provider owning this entry (custom-store entries synced by a provider\nplugin, RFC §8) — `None` for installed-store titles and manual custom entries. The\nconsole uses it for attribution; `GET /library?provider=` filters on it." })), "store": Schema.String.annotate({ "description": "Which store surfaced it: `\"steam\"` or `\"custom\"`." }), "title": Schema.String }).annotate({ "description": "Descriptive metadata, flattened — see [`GameMeta`]." }) export type HooksConfig = { readonly "hooks"?: ReadonlyArray } @@ -153,8 +157,8 @@ export type StreamRef = { readonly "app"?: string | null, readonly "client": str export const StreamRef = Schema.Struct({ "app": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The launched app/title for this stream, when one was requested (store-qualified id on\nthe native plane, app title on the GameStream plane)." })), "client": Schema.String.annotate({ "description": "Client-supplied device name; may be empty." }), "hdr": Schema.Boolean, "mode": Schema.String.annotate({ "description": "Negotiated mode, `WxH@Hz`." }), "plane": Plane }).annotate({ "description": "A live video stream (what the stream marker file reflects)." }) export type PluginSummary = { readonly "id": string, readonly "title": string, readonly "ui"?: null | PluginUiPublic, readonly "version"?: string | null } export const PluginSummary = Schema.Struct({ "id": Schema.String, "title": Schema.String, "ui": Schema.optionalKey(Schema.Union([Schema.Null, PluginUiPublic], { mode: "oneOf" })), "version": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) }).annotate({ "description": "One entry in `GET /plugins`. **Never carries the secret** — the browser learns a plugin exists\nand has a UI, nothing that lets it reach the plugin directly (it goes through the console proxy)." }) -export type HostInfo = { readonly "abi_version": number, readonly "app_version": string, readonly "codecs": ReadonlyArray, readonly "gamestream": boolean, readonly "gfe_version": string, readonly "hostname": string, readonly "local_ip": string, readonly "ports": PortMap, readonly "uniqueid": string, readonly "version": string } -export const HostInfo = Schema.Struct({ "abi_version": Schema.Number.annotate({ "description": "`punktfunk-core` C ABI version.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "app_version": Schema.String.annotate({ "description": "GameStream host version advertised to Moonlight clients." }), "codecs": Schema.Array(ApiCodec).annotate({ "description": "Codecs the host can encode (NVENC)." }), "gamestream": Schema.Boolean.annotate({ "description": "Whether the GameStream/Moonlight-compat planes are running (`--gamestream`). `false` on the\nsecure default (native punktfunk/1 only) — a console can hide Moonlight-only UI (e.g. the\nMoonlight PIN pairing card, which could never receive a PIN when this is `false`)." }), "gfe_version": Schema.String.annotate({ "description": "GFE version advertised to Moonlight clients." }), "hostname": Schema.String, "local_ip": Schema.String.annotate({ "description": "Best-effort primary LAN IP." }), "ports": PortMap, "uniqueid": Schema.String.annotate({ "description": "Stable per-host id (persisted across restarts), matched on pairing." }), "version": Schema.String.annotate({ "description": "`punktfunk-host` crate version." }) }).annotate({ "description": "Host identity and advertised capabilities (static for the life of the process)." }) +export type HostInfo = { readonly "abi_version": number, readonly "app_version": string, readonly "codecs": ReadonlyArray, readonly "gamestream": boolean, readonly "gfe_version": string, readonly "hostname": string, readonly "local_ip": string, readonly "os": string, readonly "os_name": string, readonly "ports": PortMap, readonly "uniqueid": string, readonly "version": string } +export const HostInfo = Schema.Struct({ "abi_version": Schema.Number.annotate({ "description": "`punktfunk-core` C ABI version.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "app_version": Schema.String.annotate({ "description": "GameStream host version advertised to Moonlight clients." }), "codecs": Schema.Array(ApiCodec).annotate({ "description": "Codecs the host can encode (NVENC)." }), "gamestream": Schema.Boolean.annotate({ "description": "Whether the GameStream/Moonlight-compat planes are running (`--gamestream`). `false` on the\nsecure default (native punktfunk/1 only) — a console can hide Moonlight-only UI (e.g. the\nMoonlight PIN pairing card, which could never receive a PIN when this is `false`)." }), "gfe_version": Schema.String.annotate({ "description": "GFE version advertised to Moonlight clients." }), "hostname": Schema.String, "local_ip": Schema.String.annotate({ "description": "Best-effort primary LAN IP." }), "os": Schema.String.annotate({ "description": "OS identity chain, generic → most specific, slash-separated (`windows` | `macos` |\n`linux[/][/]`). A client walks it most-specific-first and shows the first\ntoken it has an icon for, so an unknown distro still degrades to its family's mark." }), "os_name": Schema.String.annotate({ "description": "Human-readable OS name (os-release `PRETTY_NAME`; `\"Windows\"`/`\"macOS\"` elsewhere)." }), "ports": PortMap, "uniqueid": Schema.String.annotate({ "description": "Stable per-host id (persisted across restarts), matched on pairing." }), "version": Schema.String.annotate({ "description": "`punktfunk-host` crate version." }) }).annotate({ "description": "Host identity and advertised capabilities (static for the life of the process)." }) export type DisplayLayoutRequest = { readonly "positions"?: { readonly [x: string]: Position } } export const DisplayLayoutRequest = Schema.Struct({ "positions": Schema.optionalKey(Schema.Record(Schema.String, Position).annotate({ "description": "`{\"\": {\"x\": …, \"y\": …}}` — where each arranged display's top-left sits." }).check(Schema.isPropertyNames(Schema.String))) }).annotate({ "description": "Request body for `setDisplayLayout`: per-identity-slot desktop offsets, keyed by the identity-slot\nid as a string (the same id `/display/state` reports as `identity_slot`)." }) export type Layout = { readonly "mode"?: LayoutMode, readonly "positions"?: { readonly [x: string]: Position } } @@ -168,15 +172,15 @@ export const ProviderEntryInput = Schema.Struct({ "description": Schema.optional export type CatalogResponse = { readonly "busy": boolean, readonly "host": HostFacts, readonly "plugins": ReadonlyArray, readonly "sources": ReadonlyArray } export const CatalogResponse = Schema.Struct({ "busy": Schema.Boolean.annotate({ "description": "True while a package operation is in flight — the console disables install buttons." }), "host": HostFacts, "plugins": Schema.Array(CatalogEntry), "sources": Schema.Array(SourceView) }) export type StatsSample = { readonly "bitrate_kbps": number, readonly "fec_recovered": number, readonly "fps": number, readonly "frames_dropped": number, readonly "mbps": number, readonly "packets_dropped": number, readonly "repeat_fps": number, readonly "send_dropped": number, readonly "session_id": number, readonly "stages": ReadonlyArray, readonly "t_ms": number } -export const StatsSample = Schema.Struct({ "bitrate_kbps": Schema.Number.annotate({ "description": "Configured target bitrate.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "fec_recovered": Schema.Number.annotate({ "description": "FEC shards recovered this window (delta).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "fps": Schema.Number.annotate({ "description": "Genuine NEW frames/s from the source.", "format": "float" }).check(Schema.isFinite()), "frames_dropped": Schema.Number.annotate({ "description": "Frames dropped this window (delta).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "mbps": Schema.Number.annotate({ "description": "Transmit goodput (Mb/s).", "format": "float" }).check(Schema.isFinite()), "packets_dropped": Schema.Number.annotate({ "description": "Packets dropped this window (receiver-side / reassembler, where known).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "repeat_fps": Schema.Number.annotate({ "description": "Re-encoded holds/s (source-starvation indicator).", "format": "float" }).check(Schema.isFinite()), "send_dropped": Schema.Number.annotate({ "description": "Host send-buffer overflow / EAGAIN this window (delta).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "session_id": Schema.Number.annotate({ "description": "Disambiguates concurrent sessions (usually constant).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "stages": Schema.Array(StageTiming).annotate({ "description": "Ordered pipeline stages for this path." }), "t_ms": Schema.Number.annotate({ "description": "Milliseconds since capture start (monotonic; stamped by [`StatsRecorder::push_sample`]).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "One aggregated sample (~ every 2 s native, ~ every 1 s GameStream)." }) +export const StatsSample = Schema.Struct({ "bitrate_kbps": Schema.Number.annotate({ "description": "Configured target bitrate.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "fec_recovered": Schema.Number.annotate({ "description": "FEC shards recovered this window (delta).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "fps": Schema.Number.annotate({ "description": "Genuine NEW frames/s from the source.", "format": "float" }).check(Schema.isFinite()), "frames_dropped": Schema.Number.annotate({ "description": "Frames dropped this window (delta).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "mbps": Schema.Number.annotate({ "description": "Attempted sealed wire bytes/s (Mb/s): full UDP payloads at seal time — video AU bytes\nplus shard framing (header + AEAD) plus FEC parity, and for PyroWave's datagram-aligned\nmode the zero-padded window tails. NOT goodput, and NOT reduced by socket send drops.", "format": "float" }).check(Schema.isFinite()), "packets_dropped": Schema.Number.annotate({ "description": "Packets dropped this window (receiver-side / reassembler, where known).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "repeat_fps": Schema.Number.annotate({ "description": "Re-encoded holds/s (source-starvation indicator).", "format": "float" }).check(Schema.isFinite()), "send_dropped": Schema.Number.annotate({ "description": "Host send-buffer overflow / EAGAIN this window (delta).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "session_id": Schema.Number.annotate({ "description": "Disambiguates concurrent sessions (usually constant).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "stages": Schema.Array(StageTiming).annotate({ "description": "Ordered pipeline stages for this path." }), "t_ms": Schema.Number.annotate({ "description": "Milliseconds since capture start (monotonic; stamped by [`StatsRecorder::push_sample`]).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "One aggregated sample (~ every 2 s native, ~ every 1 s GameStream)." }) export type Job = { readonly "error"?: string | null, readonly "finished_at"?: never, readonly "id": string, readonly "kind": string, readonly "log": ReadonlyArray, readonly "phase": string, readonly "started_at": number, readonly "state": State, readonly "target": string } export const Job = Schema.Struct({ "error": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), "finished_at": Schema.optionalKey(Schema.Never), "id": Schema.String, "kind": Schema.String.annotate({ "description": "`install` or `uninstall`." }), "log": Schema.Array(Schema.String).annotate({ "description": "Tail of the runner's combined stdout/stderr." }), "phase": Schema.String.annotate({ "description": "Coarse step name, for a progress line the operator can read." }), "started_at": Schema.Number.annotate({ "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "state": State, "target": Schema.String.annotate({ "description": "What the operator asked for — a package name, or the raw spec they typed." }) }).annotate({ "description": "A job as the console sees it. Field names are snake_case like the rest of the management API\n(the *file* formats — index, sources, manifest — follow npm's camelCase instead)." }) export type HostEvent = { readonly "client": ClientRef, readonly "kind": "client.connected", readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "client": ClientRef, readonly "kind": "client.disconnected", readonly "reason": DisconnectReason, readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "kind": "session.started", readonly "session": SessionRef, readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "kind": "session.ended", readonly "session": SessionRef, readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "kind": "stream.started", readonly "stream": StreamRef, readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "kind": "stream.stopped", readonly "stream": StreamRef, readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "game": GameRefPayload, readonly "kind": "game.running", readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "game": GameRefPayload, readonly "kind": "game.exited", readonly "reason": GameEndReason, readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "device": DeviceRef, readonly "kind": "pairing.pending", readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "device": DeviceRef, readonly "kind": "pairing.completed", readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "device": DeviceRef, readonly "kind": "pairing.denied", readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "backend": string, readonly "kind": "display.created", readonly "mode": string, readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "count": number, readonly "kind": "display.released", readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "kind": "library.changed", readonly "source": string, readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "id": string, readonly "kind": "plugins.changed", readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "kind": "store.changed", readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "gamestream": boolean, readonly "kind": "host.started", readonly "version": string, readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } | { readonly "kind": "host.stopping", readonly "schema": number, readonly "seq": number, readonly "ts_ms": number } export const HostEvent = Schema.Union([Schema.Struct({ "client": ClientRef, "kind": Schema.Literal("client.connected"), "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }), Schema.Struct({ "client": ClientRef, "kind": Schema.Literal("client.disconnected"), "reason": DisconnectReason, "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }), Schema.Struct({ "kind": Schema.Literal("session.started"), "session": SessionRef, "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }), Schema.Struct({ "kind": Schema.Literal("session.ended"), "session": SessionRef, "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }), Schema.Struct({ "kind": Schema.Literal("stream.started"), "stream": StreamRef, "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }), Schema.Struct({ "kind": Schema.Literal("stream.stopped"), "stream": StreamRef, "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }), Schema.Struct({ "game": GameRefPayload, "kind": Schema.Literal("game.running"), "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "A launched game was confirmed running — fires once per launch, after the host has actually\nseen the game's process (not merely spawned its launcher)." }), Schema.Struct({ "game": GameRefPayload, "kind": Schema.Literal("game.exited"), "reason": GameEndReason, "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "A launched game is gone. `reason` distinguishes the player quitting from the host ending it\nper the lifetime policy." }), Schema.Struct({ "device": DeviceRef, "kind": Schema.Literal("pairing.pending"), "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }), Schema.Struct({ "device": DeviceRef, "kind": Schema.Literal("pairing.completed"), "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }), Schema.Struct({ "device": DeviceRef, "kind": Schema.Literal("pairing.denied"), "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }), Schema.Struct({ "backend": Schema.String.annotate({ "description": "The virtual-display backend that minted it (`VirtualDisplay::name`)." }), "kind": Schema.Literal("display.created"), "mode": Schema.String.annotate({ "description": "`WxH@Hz`." }), "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }), Schema.Struct({ "count": Schema.Number.annotate({ "description": "How many kept displays this release retired.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "kind": Schema.Literal("display.released"), "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }), Schema.Struct({ "kind": Schema.Literal("library.changed"), "source": Schema.String.annotate({ "description": "What mutated the library: `\"manual\"` today; a provider id once the provider\nAPI (RFC §8) lands." }), "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }), Schema.Struct({ "id": Schema.String.annotate({ "description": "The plugin whose registration changed (registered, restarted, deregistered, or\nlease-expired). A consumer re-reads `GET /api/v1/plugins` for the new set." }), "kind": Schema.Literal("plugins.changed"), "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }), Schema.Struct({ "kind": Schema.Literal("store.changed"), "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "The set of installed plugins, or what the store knows about them, changed — an install or\nuninstall finished, or a catalog refresh brought in new rows. A consumer re-reads\n`GET /api/v1/store/catalog` / `…/installed`. Deliberately payload-free: the store's answer\nis a join over several sources of truth, so \"go look again\" is the only honest signal." }), Schema.Struct({ "gamestream": Schema.Boolean.annotate({ "description": "Whether the GameStream/Moonlight compat plane is enabled." }), "kind": Schema.Literal("host.started"), "version": Schema.String, "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }), Schema.Struct({ "kind": Schema.Literal("host.stopping"), "schema": Schema.Number.annotate({ "description": "Wire-shape version ([`SCHEMA_VERSION`]).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — a consumer resumes with `since = last seen`.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds (the [`crate::log_capture::LogEntry`] convention).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) })], { mode: "oneOf" }).annotate({ "description": "The event kind + payload, flattened: `\"kind\": \"stream.started\", …payload…`." }) export type CustomPreset = { readonly "fields": { readonly "identity": Identity, readonly "keep_alive": KeepAlive, readonly "layout": Layout, readonly "max_displays": number, readonly "mode_conflict": ModeConflict, readonly "topology": Topology }, readonly "game_session"?: "auto" | "dedicated", readonly "id": string, readonly "name": string } export const CustomPreset = Schema.Struct({ "fields": Schema.Struct({ "identity": Identity, "keep_alive": KeepAlive, "layout": Layout, "max_displays": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "mode_conflict": ModeConflict, "topology": Topology }).annotate({ "description": "The six display-behavior axes this preset applies (the same shape a built-in preset expands to)." }), "game_session": Schema.optionalKey(Schema.Literals(["auto", "dedicated"]).annotate({ "description": "The game-session routing this preset applies (orthogonal to the six axes; see [`GameSession`]).\nA custom preset captures the operator's *full* setup, so — unlike a built-in preset — applying\none does set this axis." })), "id": Schema.String.annotate({ "description": "Host-assigned, stable for the life of the entry (the `{id}` in the CRUD path)." }), "name": Schema.String.annotate({ "description": "User-facing name shown on the preset card; editable." }) }).annotate({ "description": "A user-defined named preset: a saved bundle of the six display-behavior axes (exactly what a\nbuilt-in [`Preset`] expands to) plus the orthogonal game-session axis, that the operator names\nand applies from the console.\n\nUnlike the built-in [`Preset`]s (a closed enum), custom presets are **data** — a catalog stored in\n`/display-presets.json`. Applying one writes a `Custom` [`DisplayPolicy`] carrying these\nfields (the console reuses `PUT /display/settings`), so [`DisplayPolicy::effective`] stays pure and\nthe built-in set is never touched. The catalog is decoupled from the active `display-settings.json`:\nediting or deleting a preset never mutates the running policy (re-apply to adopt a change)." }) -export type DisplayPolicy = { readonly "ddc_power_off"?: boolean, readonly "game_session"?: "auto" | "dedicated", readonly "identity"?: Identity, readonly "keep_alive"?: KeepAlive, readonly "layout"?: Layout, readonly "max_displays"?: number, readonly "mode_conflict"?: ModeConflict, readonly "pnp_disable_monitors"?: boolean, readonly "preset"?: Preset, readonly "topology"?: Topology, readonly "version"?: number } -export const DisplayPolicy = Schema.Struct({ "ddc_power_off": Schema.optionalKey(Schema.Boolean.annotate({ "description": "EXPERIMENTAL (Windows): command physical monitors' panels off over DDC/CI (VCP 0xD6 →\nDPMS off) right before an `Exclusive` isolate deactivates them, and back on at restore.\nTargets the \"connected-but-dark head\" periodic-stutter class (monitor standby\nauto-input-scan / DP link churn while the virtual display is the sole active display) at\nthe monitor-firmware level. Best-effort — monitors without DDC/CI (or with it disabled in\nthe OSD) are skipped. Orthogonal to `preset` (like `game_session`): preserved across\npreset changes; `#[serde(default)]` = off so existing `display-settings.json` files are\nuntouched." })), "game_session": Schema.optionalKey(Schema.Literals(["auto", "dedicated"]).annotate({ "description": "How a game-launching session is served (`design/gamemode-and-dedicated-sessions.md` §5.2).\nOrthogonal to `preset`/lifecycle — preserved across preset changes; `#[serde(default)]` = `Auto`\nso existing `display-settings.json` files are untouched." })), "identity": Schema.optionalKey(Identity), "keep_alive": Schema.optionalKey(KeepAlive), "layout": Schema.optionalKey(Layout), "max_displays": Schema.optionalKey(Schema.Number.annotate({ "description": "Upper bound on simultaneously-live virtual displays (clamped to `1..=16` on write).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))), "mode_conflict": Schema.optionalKey(ModeConflict), "pnp_disable_monitors": Schema.optionalKey(Schema.Boolean.annotate({ "description": "EXPERIMENTAL (Windows): DISABLE physical monitors' PnP device nodes for the stream's\nduration (persistently, so a standby monitor/TV whose hot-plug events re-arrive stays\ndisabled) and re-enable them at teardown. Two selectors: the monitors an `Exclusive`\nisolate deactivated, plus — in ANY topology — external monitors that are connected but not\npart of the desktop (the standby TV that was never active, whose input auto-scan /\ninstant-on HPD cycling re-probes the link every few seconds). Targets the same\n\"connected-but-dark head\" periodic-stutter class as [`Self::ddc_power_off`], but at the\nWindows-reaction level: a disabled devnode's wake events trigger no PnP arrival, no CCD\nre-evaluation, no DWM invalidation. A crash-recovery journal re-enables leftovers on host\nstartup. Orthogonal to `preset` (like `game_session`); `#[serde(default)]` = off." })), "preset": Schema.optionalKey(Preset), "topology": Schema.optionalKey(Topology), "version": Schema.optionalKey(Schema.Number.annotate({ "description": "Schema version (currently 1) — lets a future field addition migrate rather than reject.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))) }).annotate({ "description": "The user-facing display-management policy — what `display-settings.json` holds and what the mgmt\nAPI GETs/PUTs. When [`preset`](Self::preset) is not [`Preset::Custom`] the explicit fields are\nignored (the console writes one or the other); [`effective`](Self::effective) resolves both to a\nsingle [`EffectivePolicy`]." }) +export type DisplayPolicy = { readonly "capture_monitor"?: string | null, readonly "ddc_power_off"?: boolean, readonly "game_session"?: "auto" | "dedicated", readonly "identity"?: Identity, readonly "keep_alive"?: KeepAlive, readonly "layout"?: Layout, readonly "max_displays"?: number, readonly "mode_conflict"?: ModeConflict, readonly "pnp_disable_monitors"?: boolean, readonly "preset"?: Preset, readonly "topology"?: Topology, readonly "version"?: number } +export const DisplayPolicy = Schema.Struct({ "capture_monitor": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "**Mirror a physical monitor instead of creating a virtual display**: the connector name\n(`DP-1`, `HDMI-A-2`) sessions should stream, or `None` for the normal virtual-display path.\n\nOrthogonal to `preset`/lifecycle (like `game_session`): a preset change never clears it, and\n`#[serde(default)]` leaves existing `display-settings.json` files untouched. It is a\n**host-wide** setting, not per-client — the host-pinned decision of record in\n`design/per-monitor-portal-capture.md` §5.3. `PUNKTFUNK_CAPTURE_MONITOR` overrides it (see\n[`capture_monitor`]), so an appliance can pin in `host.env` without the console fighting it." })), "ddc_power_off": Schema.optionalKey(Schema.Boolean.annotate({ "description": "EXPERIMENTAL (Windows): command physical monitors' panels off over DDC/CI (VCP 0xD6 →\nDPMS off) right before an `Exclusive` isolate deactivates them, and back on at restore.\nTargets the \"connected-but-dark head\" periodic-stutter class (monitor standby\nauto-input-scan / DP link churn while the virtual display is the sole active display) at\nthe monitor-firmware level. Best-effort — monitors without DDC/CI (or with it disabled in\nthe OSD) are skipped. Orthogonal to `preset` (like `game_session`): preserved across\npreset changes; `#[serde(default)]` = off so existing `display-settings.json` files are\nuntouched." })), "game_session": Schema.optionalKey(Schema.Literals(["auto", "dedicated"]).annotate({ "description": "How a game-launching session is served (`design/gamemode-and-dedicated-sessions.md` §5.2).\nOrthogonal to `preset`/lifecycle — preserved across preset changes; `#[serde(default)]` = `Auto`\nso existing `display-settings.json` files are untouched." })), "identity": Schema.optionalKey(Identity), "keep_alive": Schema.optionalKey(KeepAlive), "layout": Schema.optionalKey(Layout), "max_displays": Schema.optionalKey(Schema.Number.annotate({ "description": "Upper bound on simultaneously-live virtual displays (clamped to `1..=16` on write).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))), "mode_conflict": Schema.optionalKey(ModeConflict), "pnp_disable_monitors": Schema.optionalKey(Schema.Boolean.annotate({ "description": "EXPERIMENTAL (Windows): DISABLE physical monitors' PnP device nodes for the stream's\nduration (persistently, so a standby monitor/TV whose hot-plug events re-arrive stays\ndisabled) and re-enable them at teardown. Two selectors: the monitors an `Exclusive`\nisolate deactivated, plus — in ANY topology — external monitors that are connected but not\npart of the desktop (the standby TV that was never active, whose input auto-scan /\ninstant-on HPD cycling re-probes the link every few seconds). Targets the same\n\"connected-but-dark head\" periodic-stutter class as [`Self::ddc_power_off`], but at the\nWindows-reaction level: a disabled devnode's wake events trigger no PnP arrival, no CCD\nre-evaluation, no DWM invalidation. A crash-recovery journal re-enables leftovers on host\nstartup. Orthogonal to `preset` (like `game_session`); `#[serde(default)]` = off." })), "preset": Schema.optionalKey(Preset), "topology": Schema.optionalKey(Topology), "version": Schema.optionalKey(Schema.Number.annotate({ "description": "Schema version (currently 1) — lets a future field addition migrate rather than reject.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))) }).annotate({ "description": "The user-facing display-management policy — what `display-settings.json` holds and what the mgmt\nAPI GETs/PUTs. When [`preset`](Self::preset) is not [`Preset::Custom`] the explicit fields are\nignored (the console writes one or the other); [`effective`](Self::effective) resolves both to a\nsingle [`EffectivePolicy`]." }) export type EffectivePolicy = { readonly "identity": Identity, readonly "keep_alive": KeepAlive, readonly "layout": Layout, readonly "max_displays": number, readonly "mode_conflict": ModeConflict, readonly "topology": Topology } export const EffectivePolicy = Schema.Struct({ "identity": Identity, "keep_alive": KeepAlive, "layout": Layout, "max_displays": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "mode_conflict": ModeConflict, "topology": Topology }).annotate({ "description": "The six resolved fields after preset expansion — what the lifecycle/registry and the Stage-0 call\nsites read, and what the mgmt API echoes as the \"currently in force\" policy. Pure output of\n[`DisplayPolicy::effective`]." }) export type PresetInfo = { readonly "fields": { readonly "identity": Identity, readonly "keep_alive": KeepAlive, readonly "layout": Layout, readonly "max_displays": number, readonly "mode_conflict": ModeConflict, readonly "topology": Topology }, readonly "id": string, readonly "summary": string } @@ -185,8 +189,8 @@ export type Capture = { readonly "meta": CaptureMeta, readonly "samples": Readon export const Capture = Schema.Struct({ "meta": CaptureMeta, "samples": Schema.Array(StatsSample) }).annotate({ "description": "A full capture: summary + the sample time-series. The wire + on-disk shape." }) export type CustomPresetInput = { readonly "fields": EffectivePolicy, readonly "game_session"?: GameSession, readonly "name": string } export const CustomPresetInput = Schema.Struct({ "fields": EffectivePolicy, "game_session": Schema.optionalKey(GameSession), "name": Schema.String }).annotate({ "description": "Request body to create or replace a custom preset (no `id` — the host owns it)." }) -export type DisplaySettingsState = { readonly "configured": boolean, readonly "custom_presets": ReadonlyArray, readonly "effective": { readonly "identity": Identity, readonly "keep_alive": KeepAlive, readonly "layout": Layout, readonly "max_displays": number, readonly "mode_conflict": ModeConflict, readonly "topology": Topology }, readonly "enforced": ReadonlyArray, readonly "presets": ReadonlyArray, readonly "settings": { readonly "ddc_power_off"?: boolean, readonly "game_session"?: "auto" | "dedicated", readonly "identity"?: Identity, readonly "keep_alive"?: KeepAlive, readonly "layout"?: Layout, readonly "max_displays"?: number, readonly "mode_conflict"?: ModeConflict, readonly "pnp_disable_monitors"?: boolean, readonly "preset"?: Preset, readonly "topology"?: Topology, readonly "version"?: number } } -export const DisplaySettingsState = Schema.Struct({ "configured": Schema.Boolean.annotate({ "description": "True once a `display-settings.json` exists (the console has configured this host)." }), "custom_presets": Schema.Array(CustomPreset).annotate({ "description": "The operator's saved custom presets (`display-presets.json`) — named field-bundles rendered\nalongside the built-ins. Managed via `POST/PUT/DELETE /display/presets`; applied by writing a\n`Custom` policy carrying the preset's fields." }), "effective": Schema.Struct({ "identity": Identity, "keep_alive": KeepAlive, "layout": Layout, "max_displays": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "mode_conflict": ModeConflict, "topology": Topology }).annotate({ "description": "The effective (preset-expanded) policy currently in force." }), "enforced": Schema.Array(Schema.String).annotate({ "description": "Option names this build enforces right now. All five axes are now acted on (keep_alive +\ntopology since Stage 0-2, identity Stage 3, mode_conflict Stage 4, layout Stage 5) — the console\nreads this to know which controls are live vs. \"coming soon\" (per-backend nuance, e.g. layout\nposition apply being KWin-only, is reported per display in `/display/state`)." }), "presets": Schema.Array(PresetInfo).annotate({ "description": "Every named preset and what it expands to (for the picker's preview)." }), "settings": Schema.Struct({ "ddc_power_off": Schema.optionalKey(Schema.Boolean.annotate({ "description": "EXPERIMENTAL (Windows): command physical monitors' panels off over DDC/CI (VCP 0xD6 →\nDPMS off) right before an `Exclusive` isolate deactivates them, and back on at restore.\nTargets the \"connected-but-dark head\" periodic-stutter class (monitor standby\nauto-input-scan / DP link churn while the virtual display is the sole active display) at\nthe monitor-firmware level. Best-effort — monitors without DDC/CI (or with it disabled in\nthe OSD) are skipped. Orthogonal to `preset` (like `game_session`): preserved across\npreset changes; `#[serde(default)]` = off so existing `display-settings.json` files are\nuntouched." })), "game_session": Schema.optionalKey(Schema.Literals(["auto", "dedicated"]).annotate({ "description": "How a game-launching session is served (`design/gamemode-and-dedicated-sessions.md` §5.2).\nOrthogonal to `preset`/lifecycle — preserved across preset changes; `#[serde(default)]` = `Auto`\nso existing `display-settings.json` files are untouched." })), "identity": Schema.optionalKey(Identity), "keep_alive": Schema.optionalKey(KeepAlive), "layout": Schema.optionalKey(Layout), "max_displays": Schema.optionalKey(Schema.Number.annotate({ "description": "Upper bound on simultaneously-live virtual displays (clamped to `1..=16` on write).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))), "mode_conflict": Schema.optionalKey(ModeConflict), "pnp_disable_monitors": Schema.optionalKey(Schema.Boolean.annotate({ "description": "EXPERIMENTAL (Windows): DISABLE physical monitors' PnP device nodes for the stream's\nduration (persistently, so a standby monitor/TV whose hot-plug events re-arrive stays\ndisabled) and re-enable them at teardown. Two selectors: the monitors an `Exclusive`\nisolate deactivated, plus — in ANY topology — external monitors that are connected but not\npart of the desktop (the standby TV that was never active, whose input auto-scan /\ninstant-on HPD cycling re-probes the link every few seconds). Targets the same\n\"connected-but-dark head\" periodic-stutter class as [`Self::ddc_power_off`], but at the\nWindows-reaction level: a disabled devnode's wake events trigger no PnP arrival, no CCD\nre-evaluation, no DWM invalidation. A crash-recovery journal re-enables leftovers on host\nstartup. Orthogonal to `preset` (like `game_session`); `#[serde(default)]` = off." })), "preset": Schema.optionalKey(Preset), "topology": Schema.optionalKey(Topology), "version": Schema.optionalKey(Schema.Number.annotate({ "description": "Schema version (currently 1) — lets a future field addition migrate rather than reject.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))) }).annotate({ "description": "The stored policy (preset + custom fields), or the built-in default when unconfigured." }) }).annotate({ "description": "Full display-management state for the console: the stored policy, every preset's expansion, the\nresolved effective policy, and which options this build actually enforces yet (Stage 0 wires\nkeep-alive linger + topology; the rest are stored but not yet acted on)." }) +export type DisplaySettingsState = { readonly "configured": boolean, readonly "custom_presets": ReadonlyArray, readonly "effective": { readonly "identity": Identity, readonly "keep_alive": KeepAlive, readonly "layout": Layout, readonly "max_displays": number, readonly "mode_conflict": ModeConflict, readonly "topology": Topology }, readonly "enforced": ReadonlyArray, readonly "presets": ReadonlyArray, readonly "settings": { readonly "capture_monitor"?: string | null, readonly "ddc_power_off"?: boolean, readonly "game_session"?: "auto" | "dedicated", readonly "identity"?: Identity, readonly "keep_alive"?: KeepAlive, readonly "layout"?: Layout, readonly "max_displays"?: number, readonly "mode_conflict"?: ModeConflict, readonly "pnp_disable_monitors"?: boolean, readonly "preset"?: Preset, readonly "topology"?: Topology, readonly "version"?: number } } +export const DisplaySettingsState = Schema.Struct({ "configured": Schema.Boolean.annotate({ "description": "True once a `display-settings.json` exists (the console has configured this host)." }), "custom_presets": Schema.Array(CustomPreset).annotate({ "description": "The operator's saved custom presets (`display-presets.json`) — named field-bundles rendered\nalongside the built-ins. Managed via `POST/PUT/DELETE /display/presets`; applied by writing a\n`Custom` policy carrying the preset's fields." }), "effective": Schema.Struct({ "identity": Identity, "keep_alive": KeepAlive, "layout": Layout, "max_displays": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "mode_conflict": ModeConflict, "topology": Topology }).annotate({ "description": "The effective (preset-expanded) policy currently in force." }), "enforced": Schema.Array(Schema.String).annotate({ "description": "Option names this build enforces right now. All five axes are now acted on (keep_alive +\ntopology since Stage 0-2, identity Stage 3, mode_conflict Stage 4, layout Stage 5) — the console\nreads this to know which controls are live vs. \"coming soon\" (per-backend nuance, e.g. layout\nposition apply being KWin-only, is reported per display in `/display/state`)." }), "presets": Schema.Array(PresetInfo).annotate({ "description": "Every named preset and what it expands to (for the picker's preview)." }), "settings": Schema.Struct({ "capture_monitor": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "**Mirror a physical monitor instead of creating a virtual display**: the connector name\n(`DP-1`, `HDMI-A-2`) sessions should stream, or `None` for the normal virtual-display path.\n\nOrthogonal to `preset`/lifecycle (like `game_session`): a preset change never clears it, and\n`#[serde(default)]` leaves existing `display-settings.json` files untouched. It is a\n**host-wide** setting, not per-client — the host-pinned decision of record in\n`design/per-monitor-portal-capture.md` §5.3. `PUNKTFUNK_CAPTURE_MONITOR` overrides it (see\n[`capture_monitor`]), so an appliance can pin in `host.env` without the console fighting it." })), "ddc_power_off": Schema.optionalKey(Schema.Boolean.annotate({ "description": "EXPERIMENTAL (Windows): command physical monitors' panels off over DDC/CI (VCP 0xD6 →\nDPMS off) right before an `Exclusive` isolate deactivates them, and back on at restore.\nTargets the \"connected-but-dark head\" periodic-stutter class (monitor standby\nauto-input-scan / DP link churn while the virtual display is the sole active display) at\nthe monitor-firmware level. Best-effort — monitors without DDC/CI (or with it disabled in\nthe OSD) are skipped. Orthogonal to `preset` (like `game_session`): preserved across\npreset changes; `#[serde(default)]` = off so existing `display-settings.json` files are\nuntouched." })), "game_session": Schema.optionalKey(Schema.Literals(["auto", "dedicated"]).annotate({ "description": "How a game-launching session is served (`design/gamemode-and-dedicated-sessions.md` §5.2).\nOrthogonal to `preset`/lifecycle — preserved across preset changes; `#[serde(default)]` = `Auto`\nso existing `display-settings.json` files are untouched." })), "identity": Schema.optionalKey(Identity), "keep_alive": Schema.optionalKey(KeepAlive), "layout": Schema.optionalKey(Layout), "max_displays": Schema.optionalKey(Schema.Number.annotate({ "description": "Upper bound on simultaneously-live virtual displays (clamped to `1..=16` on write).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))), "mode_conflict": Schema.optionalKey(ModeConflict), "pnp_disable_monitors": Schema.optionalKey(Schema.Boolean.annotate({ "description": "EXPERIMENTAL (Windows): DISABLE physical monitors' PnP device nodes for the stream's\nduration (persistently, so a standby monitor/TV whose hot-plug events re-arrive stays\ndisabled) and re-enable them at teardown. Two selectors: the monitors an `Exclusive`\nisolate deactivated, plus — in ANY topology — external monitors that are connected but not\npart of the desktop (the standby TV that was never active, whose input auto-scan /\ninstant-on HPD cycling re-probes the link every few seconds). Targets the same\n\"connected-but-dark head\" periodic-stutter class as [`Self::ddc_power_off`], but at the\nWindows-reaction level: a disabled devnode's wake events trigger no PnP arrival, no CCD\nre-evaluation, no DWM invalidation. A crash-recovery journal re-enables leftovers on host\nstartup. Orthogonal to `preset` (like `game_session`); `#[serde(default)]` = off." })), "preset": Schema.optionalKey(Preset), "topology": Schema.optionalKey(Topology), "version": Schema.optionalKey(Schema.Number.annotate({ "description": "Schema version (currently 1) — lets a future field addition migrate rather than reject.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))) }).annotate({ "description": "The stored policy (preset + custom fields), or the built-in default when unconfigured." }) }).annotate({ "description": "Full display-management state for the console: the stored policy, every preset's expansion, the\nresolved effective policy, and which options this build actually enforces yet (Stage 0 wires\nkeep-alive linger + topology; the rest are stored but not yet acted on)." }) // schemas export type ListPairedClients200 = ReadonlyArray export const ListPairedClients200 = Schema.Array(PairedClient) @@ -210,6 +214,10 @@ export type SetDisplayLayout401 = ApiError export const SetDisplayLayout401 = ApiError export type SetDisplayLayout500 = ApiError export const SetDisplayLayout500 = ApiError +export type GetDisplayMonitors200 = MonitorsResponse +export const GetDisplayMonitors200 = MonitorsResponse +export type GetDisplayMonitors401 = ApiError +export const GetDisplayMonitors401 = ApiError export type ListCustomPresets200 = ReadonlyArray export const ListCustomPresets200 = Schema.Array(CustomPreset) export type ListCustomPresets401 = ApiError @@ -752,6 +760,13 @@ export const make = ( "500": decodeError("SetDisplayLayout500", SetDisplayLayout500), orElse: unexpectedStatus })) + ), + "getDisplayMonitors": (options) => HttpClientRequest.get(`/api/v1/display/monitors`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetDisplayMonitors200), + "401": decodeError("GetDisplayMonitors401", GetDisplayMonitors401), + orElse: unexpectedStatus + })) ), "listCustomPresets": (options) => HttpClientRequest.get(`/api/v1/display/presets`).pipe( withResponse(options?.config)(HttpClientResponse.matchStatus({ @@ -1338,6 +1353,13 @@ readonly "listCompositors": (options: { readonly */ readonly "setDisplayLayout": (options: { readonly payload: typeof SetDisplayLayoutRequestJson.Encoded; readonly config?: Config | undefined }) => Effect.Effect, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"SetDisplayLayout401", typeof SetDisplayLayout401.Type> | PunktfunkError<"SetDisplayLayout500", typeof SetDisplayLayout500.Type>> /** +* The heads this host actually has — for pinning capture at one (`PUNKTFUNK_CAPTURE_MONITOR`) and +* for rendering a picker. Read-only: this never creates, moves or disables anything. Note these +* are *not* the managed virtual displays — those are `/display/state`. See +* `design/per-monitor-portal-capture.md` §5.1. +*/ +readonly "getDisplayMonitors": (options: { readonly config?: Config | undefined } | undefined) => Effect.Effect, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"GetDisplayMonitors401", typeof GetDisplayMonitors401.Type>> + /** * The operator's named field-bundles (`display-presets.json`). These also ride the * `GET /display/settings` response (`custom_presets`), so the console rarely needs this directly. */