Files
punktfunk/sdk/src/gen/punktfunk.ts
T
enricobuehler 2c0aee3979
ci / web (push) Successful in 1m11s
ci / docs-site (push) Successful in 1m13s
apple / swift (push) Successful in 1m22s
decky / build-publish (push) Successful in 32s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 44s
ci / bench (push) Successful in 6m40s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 11s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 15s
apple / screenshots (push) Successful in 6m26s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 9m52s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 8m57s
deb / build-publish (push) Successful in 13m13s
windows-host / package (push) Successful in 15m54s
arch / build-publish (push) Successful in 17m25s
android / android (push) Successful in 18m9s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 15m26s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 19m50s
ci / rust (push) Successful in 27m22s
docker / deploy-docs (push) Successful in 23s
chore(plugins): regenerate OpenAPI spec + SDK client for /api/v1/plugins
Regenerated api/openapi.json (host built on Linux) with the plugins tag —
registerPlugin/listPlugins/deregisterPlugin/getPluginUiCredential + the
PluginRegistration/PluginSummary/PluginUi/PluginUiPublic/UiCredential schemas —
and the SDK's generated client. Drift test + 44 mgmt/events host tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 09:48:37 +02:00

1317 lines
153 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import * as Data from "effect/Data"
import * as Effect from "effect/Effect"
import type { SchemaError } from "effect/Schema"
import * as Schema from "effect/Schema"
import * as Stream from "effect/Stream"
import * as Sse from "effect/unstable/encoding/Sse"
import * as HttpClient from "effect/unstable/http/HttpClient"
import * as HttpClientError from "effect/unstable/http/HttpClientError"
import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest"
import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse"
// non-recursive definitions
export type ApiCodec = "h264" | "hevc" | "av1" | "pyrowave"
export const ApiCodec = Schema.Literals(["h264", "hevc", "av1", "pyrowave"]).annotate({ "description": "Video codec identifier. The wire token matches the codec's canonical name used across the\nstack (SDP/GameStream advertisement, the stats-capture `CaptureMeta.codec`, and the encoder's\n[`Codec::label`]) — notably `H.265` serializes as `\"hevc\"`, not `\"h265\"`, so the same codec\nreads identically on every console page." })
export type ApiDisplayInfo = { readonly "backend": string, readonly "client"?: string | null, readonly "display_index": number, readonly "expires_in_ms"?: never, readonly "group": number, readonly "identity_slot"?: never, readonly "mode": string, readonly "sessions": number, readonly "slot": number, readonly "state": string, readonly "topology": string, readonly "x": number, readonly "y": number }
export const ApiDisplayInfo = Schema.Struct({ "backend": Schema.String.annotate({ "description": "Backend name (`pf-vdisplay`, `kwin`, …)." }), "client": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Short client label, when the owner tracks it." })), "display_index": Schema.Number.annotate({ "description": "This display's ordinal within its group, in acquire order (0-based).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "expires_in_ms": Schema.optionalKey(Schema.Never), "group": Schema.Number.annotate({ "description": "Display group (shared desktop) id — several displays with the same group form one desktop (§6A).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "identity_slot": Schema.optionalKey(Schema.Never), "mode": Schema.String.annotate({ "description": "`WIDTHxHEIGHT@HZ`." }), "sessions": Schema.Number.annotate({ "description": "Live sessions holding the display.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "slot": Schema.Number.annotate({ "description": "Stable-enough id for the `/display/release` `slot` argument.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "state": Schema.String.annotate({ "description": "`active` | `lingering` | `pinned`." }), "topology": Schema.String.annotate({ "description": "Effective topology for this display's group (`extend` | `primary` | `exclusive`)." }), "x": Schema.Number.annotate({ "description": "Desktop-space top-left `x` (auto-row or the console's manual arrangement, §6.2).", "format": "int32" }).check(Schema.isInt()), "y": Schema.Number.annotate({ "description": "Desktop-space top-left `y`.", "format": "int32" }).check(Schema.isInt()) }).annotate({ "description": "One live or kept virtual display." })
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 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 }
export const ArmNativePairing = Schema.Struct({ "fingerprint": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Optional: bind the window to ONE device fingerprint (hex SHA-256, e.g. from a pending knock).\nWhen set, only a pairing attempt from that fingerprint consumes the window — so an unpaired\nLAN peer can neither pair nor burn a window armed for a specific device (security-review #9).\nOmit for an unbound window (any device may use the PIN — trusted-LAN only)." })), "ttl_secs": Schema.optionalKey(Schema.Never) }).annotate({ "description": "Arm-native-pairing request body." })
export type Artwork = { readonly "header"?: string | null, readonly "hero"?: string | null, readonly "logo"?: string | null, readonly "portrait"?: string | null }
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 DisconnectReason = "quit" | "timeout" | "error"
export const DisconnectReason = Schema.Literals(["quit", "timeout", "error"]).annotate({ "description": "Why a client went away. `Quit` is a deliberate user \"stop\" (the typed close code);\n`Timeout` is a transport idle timeout (the client vanished); `Error` is everything else." })
export type GameSession = "auto" | "dedicated"
export const GameSession = Schema.Literals(["auto", "dedicated"]).annotate({ "description": "How a session that **launches a game** (a library id on the Hello / apps.json / Decky pin) is\nserved (`design/gamemode-and-dedicated-sessions.md` §5.2). Orthogonal to the preset/lifecycle axes\n— a top-level [`DisplayPolicy`] field, NOT part of [`EffectivePolicy`], so a preset never clobbers\nit. Linux-only in effect (a launching Windows session opens into the one desktop)." })
export type Health = { readonly "abi_version": number, readonly "status": string, readonly "version": string }
export const Health = Schema.Struct({ "abi_version": Schema.Number.annotate({ "description": "`punktfunk-core` C ABI version.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "status": Schema.String.annotate({ "description": "Always `\"ok\"` when the host responds." }), "version": Schema.String.annotate({ "description": "`punktfunk-host` crate version." }) }).annotate({ "description": "Liveness + version probe." })
export type HookEntry = { readonly "debounce_ms"?: number, readonly "filter"?: null | { readonly "app"?: string | null, readonly "client"?: string | null, readonly "fingerprint"?: string | null, readonly "plane"?: null | "native" | "gamestream" }, readonly "hmac_secret_file"?: string | null, readonly "on": string, readonly "run"?: string | null, readonly "timeout_s"?: number, readonly "webhook"?: string | null }
export const HookEntry = Schema.Struct({ "debounce_ms": Schema.optionalKey(Schema.Number.annotate({ "description": "Minimum interval between firings of this hook, in milliseconds. 0 = fire every time.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))), "filter": Schema.optionalKey(Schema.Union([Schema.Null, Schema.Struct({ "app": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Launched app id/title (`stream.*` events)." })), "client": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Client/device name (for `session.*`: the short client label the Dashboard shows)." })), "fingerprint": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Certificate fingerprint (hex, case-insensitive)." })), "plane": Schema.optionalKey(Schema.Union([Schema.Null, Schema.Literals(["native", "gamestream"]).annotate({ "description": "Protocol plane (`native` / `gamestream`)." })], { mode: "oneOf" })) }).annotate({ "description": "Exact-match constraints on the event's fields; every present field must match." })], { mode: "oneOf" })), "hmac_secret_file": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "File holding the webhook HMAC secret (`X-Punktfunk-Signature: sha256=<hex>`). The file\nshould be operator-owned and private; a world-readable secret is warned about." })), "on": Schema.String.annotate({ "description": "Which events fire this hook: an exact kind (`stream.started`) or a `domain.*` prefix\n(`pairing.*`) — the same vocabulary as the SSE `?kinds=` filter." }), "run": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Shell command to execute (detached, event JSON on stdin + `PF_EVENT_*` env)." })), "timeout_s": Schema.optionalKey(Schema.Number.annotate({ "description": "Exec timeout in seconds (1600, default 30); the process group is killed on expiry.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))), "webhook": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "URL to POST the event JSON to." })) }).annotate({ "description": "One hook: fire `run` and/or `webhook` when an event matching `on` (+ `filter`) occurs." })
export type Identity = "shared" | "per-client" | "per-client-mode"
export const Identity = Schema.Literals(["shared", "per-client", "per-client-mode"]).annotate({ "description": "Stable display identity, so desktop environments persist per-display config (KDE scaling). Stored\nat Stage 0; carriers wired from the identity stage." })
export type KeepAlive = { readonly "mode": "off" } | { readonly "mode": "duration", readonly "seconds": number } | { readonly "mode": "forever" }
export const KeepAlive = Schema.Union([Schema.Struct({ "mode": Schema.Literal("off") }).annotate({ "description": "Tear the display down at session end (today's default on every backend but Windows, which\nlingers 10 s)." }), Schema.Struct({ "mode": Schema.Literal("duration"), "seconds": Schema.Number.annotate({ "description": "Linger window in seconds.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "Keep the display for `seconds` after the last session leaves, then tear it down; a reconnect\ninside the window reuses it." }), Schema.Struct({ "mode": Schema.Literal("forever") }).annotate({ "description": "Keep the display until host shutdown or an explicit release (the `Pinned` lifecycle state).\n**Not honored until the display-lifecycle stage** — rejected by the mgmt PUT at Stage 0." })], { mode: "oneOf" }).annotate({ "description": "How long a virtual display (and, on gamescope's bare spawn, the nested session + its game)\nsurvives after the last client session detaches. Serialized as an object tagged on `mode`\n(`{\"mode\":\"off\"}` / `{\"mode\":\"duration\",\"seconds\":300}` / `{\"mode\":\"forever\"}`) so the web form\nand the OpenAPI schema stay simple." })
export type LaunchSpec = { readonly "kind": string, readonly "value": string }
export const LaunchSpec = 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 a title (consumed by the session launcher in a later step). Kept\nopen-ended so new stores slot in: `steam_appid` → `steam steam://rungameid/<value>`;\n`command` → run `<value>` nested in a gamescope session." })
export type LayoutMode = "auto-row" | "manual"
export const LayoutMode = Schema.Literals(["auto-row", "manual"]).annotate({ "description": "How group members are arranged in the desktop coordinate space. Stored at Stage 0; applied from\nthe multi-monitor stage." })
export type LocalSummary = { readonly "audio_streaming": boolean, readonly "conflicts"?: ReadonlyArray<string>, readonly "kept_displays": number, readonly "native_paired_clients": number, readonly "paired_clients": number, readonly "pending_approvals": number, readonly "pin_pending": boolean, readonly "session"?: null | { readonly "fps": number, readonly "height": number, readonly "width": number }, readonly "version": string, readonly "video_streaming": boolean }
export const LocalSummary = Schema.Struct({ "audio_streaming": Schema.Boolean.annotate({ "description": "True while the audio stream thread is running." }), "conflicts": Schema.optionalKey(Schema.Array(Schema.String).annotate({ "description": "Other Moonlight-compatible hosts (Sunshine/Apollo/…) detected on this machine at startup —\nrunning one alongside Punktfunk is unsupported. Compact labels (e.g. `Sunshine (running)`);\nthe tray/console surface them so the clash is visible before pairing silently fails." })), "kept_displays": Schema.Number.annotate({ "description": "Virtual displays being KEPT with no live session — lingering (keep-alive window) or pinned\n(`keep_alive: forever`). Non-zero means a display (and, exclusive, your physical monitors) is\nheld; the tray surfaces it + a one-click release. Active (in-use) displays are not counted.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "native_paired_clients": Schema.Number.annotate({ "description": "Number of paired native (punktfunk/1) devices.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "paired_clients": Schema.Number.annotate({ "description": "Number of pinned (paired) GameStream client certificates.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "pending_approvals": Schema.Number.annotate({ "description": "Native pairing knocks awaiting the operator's approval (count only).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "pin_pending": Schema.Boolean.annotate({ "description": "True while a GameStream pairing handshake is parked waiting for the user's 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": "The active launch session (set by Moonlight's `/launch`, cleared on cancel/stop)." })], { mode: "oneOf" })), "version": Schema.String.annotate({ "description": "Host version (mirrors `/health`)." }), "video_streaming": Schema.Boolean.annotate({ "description": "True while the video stream thread is running." }) }).annotate({ "description": "Non-sensitive host status for the local tray icon: counts and booleans only — no PIN values,\nno fingerprints, no device names. Served unauthenticated to LOOPBACK peers only (see\n`require_auth`): the bearer-token file is SYSTEM/Administrators-DACL'd on Windows, so the\nper-user tray process cannot authenticate — this narrow read-only route is its status source." })
export type LogEntry = { readonly "level": string, readonly "msg": string, readonly "seq": number, readonly "target": string, readonly "ts_ms": number }
export const LogEntry = Schema.Struct({ "level": Schema.String.annotate({ "description": "`ERROR` | `WARN` | `INFO` | `DEBUG` | `TRACE`." }), "msg": Schema.String.annotate({ "description": "The formatted message, structured fields appended as `key=value`." }), "seq": Schema.Number.annotate({ "description": "Monotonic sequence number (1-based) — pass the last one back as the `after` cursor.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "target": Schema.String.annotate({ "description": "The emitting module path (tracing target)." }), "ts_ms": Schema.Number.annotate({ "description": "Unix timestamp in milliseconds.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "One captured log event." })
export type ModeConflict = "separate" | "steal" | "join" | "reject"
export const ModeConflict = Schema.Literals(["separate", "steal", "join", "reject"]).annotate({ "description": "Admission when a *different* client connects while a display/session is already live and asks for\na different mode. Stored at Stage 0; enforced from the mode-conflict admission stage." })
export type NativeClient = { readonly "fingerprint": string, readonly "name": string }
export const NativeClient = Schema.Struct({ "fingerprint": Schema.String.annotate({ "description": "Hex SHA-256 of the client certificate — its stable id here." }), "name": Schema.String.annotate({ "description": "The name the client supplied when pairing." }) }).annotate({ "description": "A paired native (punktfunk/1) client." })
export type NativePairStatus = { readonly "armed": boolean, readonly "enabled": boolean, readonly "expires_in_secs"?: never, readonly "paired_clients": number, readonly "pin"?: string | null }
export const NativePairStatus = Schema.Struct({ "armed": Schema.Boolean.annotate({ "description": "True while a pairing window is open." }), "enabled": Schema.Boolean.annotate({ "description": "Whether the native host is running (the unified host started with `--native`)." }), "expires_in_secs": Schema.optionalKey(Schema.Never), "paired_clients": Schema.Number.annotate({ "description": "Number of paired native clients.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "pin": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The PIN to display while armed (null when disarmed)." })) }).annotate({ "description": "Native (punktfunk/1) pairing status. Unlike GameStream, the **host** mints the PIN (the SPAKE2\nceremony needs it client-side first), so the console **displays** `pin` for the user to enter on\ntheir device — armed on demand for a short window." })
export type PairedClient = { readonly "fingerprint": string, readonly "not_after_unix"?: never, readonly "not_before_unix"?: never, readonly "subject"?: string | null }
export const PairedClient = Schema.Struct({ "fingerprint": Schema.String.annotate({ "description": "Lowercase hex SHA-256 of the client certificate DER — the client's stable id here." }), "not_after_unix": Schema.optionalKey(Schema.Never), "not_before_unix": Schema.optionalKey(Schema.Never), "subject": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Certificate subject (e.g. `CN=NVIDIA GameStream Client`), if the DER parses." })) }).annotate({ "description": "A paired (certificate-pinned) Moonlight client." })
export type PairingStatus = { readonly "pin_pending": boolean }
export const PairingStatus = Schema.Struct({ "pin_pending": Schema.Boolean.annotate({ "description": "True while a pairing handshake is parked waiting for the user's PIN." }) }).annotate({ "description": "Pairing-flow status." })
export type PendingDevice = { readonly "age_secs": number, readonly "fingerprint": string, readonly "id": number, readonly "name": string }
export const PendingDevice = Schema.Struct({ "age_secs": Schema.Number.annotate({ "description": "Seconds since the device last knocked.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "fingerprint": Schema.String.annotate({ "description": "Hex SHA-256 of the device's certificate — what approval pins." }), "id": Schema.Number.annotate({ "description": "Id to address approve/deny (per-process; entries expire after ~10 minutes).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "name": Schema.String.annotate({ "description": "Best-effort device label (the client's own name, else fingerprint-derived)." }) }).annotate({ "description": "An unpaired device that tried to connect while the host requires pairing — awaiting\n**delegated approval** (approve it here instead of fetching the host PIN out of band)." })
export type Plane = "native" | "gamestream"
export const Plane = Schema.Literals(["native", "gamestream"]).annotate({ "description": "Which protocol plane an event originated from. Hooks and scripts filter on it — a hook\nthat fires for native clients but not Moonlight clients is a bug, not a v2 feature." })
export type PluginRegistration = { readonly "title": string, readonly "ui"?: null | { readonly "icon"?: string | null, readonly "port": number, readonly "secret": string }, readonly "version"?: string | null }
export const PluginRegistration = Schema.Struct({ "title": Schema.String.annotate({ "description": "Human-readable title for the console nav entry (164 chars; control chars stripped)." }), "ui": Schema.optionalKey(Schema.Union([Schema.Null, Schema.Struct({ "icon": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Optional lucide icon name for the console nav entry (`^[a-z0-9-]{1,48}$`)." })), "port": Schema.Number.annotate({ "description": "The **loopback** port the plugin serves its UI on. The host and console only ever dial\n`127.0.0.1:<port>`; a registration can never carry a hostname.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "secret": Schema.String.annotate({ "description": "Per-boot shared secret the console proxy must present (as `Authorization: Bearer`) on every\nrequest to the plugin's UI server. Rotated whenever the plugin restarts." }) }).annotate({ "description": "Present iff the plugin serves a UI surface. A registration with no `ui` is a liveness/phone-book\nentry only (e.g. a future runner-management listing) and grows no nav entry." })], { mode: "oneOf" })), "version": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Optional plugin version, purely informational (≤32 chars)." })) }).annotate({ "description": "Register/renew body for `PUT /plugins/{id}`." })
export type PluginUiPublic = { readonly "icon"?: string | null, readonly "port": number }
export const PluginUiPublic = Schema.Struct({ "icon": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), "port": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "The secret-free view of a plugin's UI surface — what [`list_plugins`] returns to the browser." })
export type PortMap = { readonly "audio": number, readonly "control": number, readonly "http": number, readonly "https": number, readonly "mgmt": number, readonly "rtsp": number, readonly "video": number }
export const PortMap = Schema.Struct({ "audio": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "control": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "http": Schema.Number.annotate({ "description": "nvhttp plain HTTP (serverinfo, pairing).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "https": Schema.Number.annotate({ "description": "nvhttp mutual-TLS HTTPS (post-pairing).", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "mgmt": Schema.Number.annotate({ "description": "This management API.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "rtsp": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "video": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "Every port a client integration may need (Moonlight derives the stream ports from the\nHTTP base; a control pane should not have to)." })
export type Position = { readonly "x": number, readonly "y": number }
export const Position = Schema.Struct({ "x": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()), "y": Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()) }).annotate({ "description": "A desktop-space offset for a display (top-left origin)." })
export type PrepCmd = { readonly "do": string, readonly "undo"?: string | null }
export const PrepCmd = Schema.Struct({ "do": Schema.String.annotate({ "description": "Command run before launch. Same execution recipe and ownership checks as hook `run`\ncommands (event-less: stdin is empty JSON, env carries the `PF_APP_*` context)." }), "undo": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Command run after the session ends. Skipped when its `do` failed (it never took effect)." })) }).annotate({ "description": "One per-app preparation step (RFC §6 — deliberate Sunshine `prep-cmd` parity): `do` runs\n**synchronously before the app launches** (an HDR toggle or a MangoHud env change must land\nfirst), `undo` runs at session end — reverse order across steps, best-effort, on every exit\npath including a crash-unwind (RAII via [`PrepGuard`])." })
export type Preset = "custom" | "default" | "gaming-rig" | "shared-desktop" | "hotdesk" | "workstation"
export const Preset = Schema.Literals(["custom", "default", "gaming-rig", "shared-desktop", "hotdesk", "workstation"]).annotate({ "description": "A named bundle of the fields below. `Custom` (the default) means the explicit fields rule; any\nother preset ignores the stored fields and expands to its own ([`DisplayPolicy::effective`])." })
export type ProviderRemoved = { readonly "removed": number }
export const ProviderRemoved = Schema.Struct({ "removed": Schema.Number.annotate({ "description": "How many entries the provider owned (and were removed)." }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "The count envelope a provider uninstall returns." })
export type ReleaseDisplayRequest = { readonly "slot"?: never }
export const ReleaseDisplayRequest = Schema.Struct({ "slot": Schema.optionalKey(Schema.Never) }).annotate({ "description": "Request body for `releaseDisplay`." })
export type ReleaseDisplayResult = { readonly "released": number }
export const ReleaseDisplayResult = Schema.Struct({ "released": Schema.Number.annotate({ "description": "Number of kept displays torn down." }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "Result of a `/display/release`." })
export type SessionRef = { readonly "client": string, readonly "hdr": boolean, readonly "id": number, readonly "mode": string }
export const SessionRef = Schema.Struct({ "client": Schema.String.annotate({ "description": "Short client label (cert-fingerprint prefix, or peer IP for an anonymous client)." }), "hdr": Schema.Boolean, "id": Schema.Number.annotate({ "description": "Host-local session id (unique within this host process).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "mode": Schema.String.annotate({ "description": "Negotiated mode, `WxH@Hz` (e.g. `\"3840x2160@120\"`)." }) }).annotate({ "description": "A live A/V session (the plane-neutral notion the Dashboard shows)." })
export type SetGpuPreference = { readonly "gpu_id"?: string | null, readonly "mode": string }
export const SetGpuPreference = Schema.Struct({ "gpu_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Required when `mode` is `manual`: the stable `id` of a currently listed GPU\n(see `listGpus`)." })), "mode": Schema.String.annotate({ "description": "`auto` (env pin, else max dedicated VRAM — the default) or `manual`." }) }).annotate({ "description": "Request body for `setGpuPreference`." })
export type StageTiming = { readonly "name": string, readonly "p50_us": number, readonly "p99_us": number }
export const StageTiming = Schema.Struct({ "name": Schema.String.annotate({ "description": "`\"capture\" | \"submit\" | \"encode\" | \"packetize\" | \"send\"` (path-dependent)." }), "p50_us": Schema.Number.annotate({ "format": "float" }).check(Schema.isFinite()), "p99_us": Schema.Number.annotate({ "format": "float" }).check(Schema.isFinite()) }).annotate({ "description": "One pipeline stage's latency in an aggregation window (microseconds)." })
export type StatsStatus = { readonly "armed": boolean, readonly "elapsed_ms": number, readonly "kind": string, readonly "sample_count": number, readonly "started_unix_ms": number }
export const StatsStatus = Schema.Struct({ "armed": Schema.Boolean.annotate({ "description": "Capture currently running." }), "elapsed_ms": Schema.Number.annotate({ "description": "Host-measured elapsed time of the in-progress capture, in ms (`0` if idle). Computed from the\nhost's MONOTONIC clock, so a console can show elapsed time without subtracting `started_unix_ms`\nfrom its own (possibly skewed) wall clock.", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "kind": Schema.String.annotate({ "description": "Path of the in-progress capture (`\"\"` if idle)." }), "sample_count": Schema.Number.annotate({ "description": "Samples in the in-progress capture.", "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), "started_unix_ms": Schema.Number.annotate({ "description": "Unix start time of the in-progress capture (`0` if idle).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "Snapshot of the in-progress capture for the management API." })
export type SubmitPin = { readonly "pin": string }
export const SubmitPin = Schema.Struct({ "pin": Schema.String.annotate({ "description": "116 ASCII digits (Moonlight shows 4)." }) }).annotate({ "description": "The PIN Moonlight displays during pairing." })
export type Topology = "auto" | "extend" | "primary" | "exclusive"
export const Topology = Schema.Literals(["auto", "extend", "primary", "exclusive"]).annotate({ "description": "What the host does to the box's display topology while managed virtual displays are up." })
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 RuntimeStatus = { readonly "active_sessions": number, readonly "audio_streaming": boolean, 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." }), "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 DisplayStateResponse = { readonly "displays": ReadonlyArray<ApiDisplayInfo> }
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 "env_override"?: string | null, readonly "gpus": ReadonlyArray<ApiGpu>, 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" })), "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 GameEntry = { 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({ "art": Artwork, "id": Schema.String.annotate({ "description": "Stable, store-qualified id: `steam:<appid>` or `custom:<id>`." }), "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": "One title in the unified library, regardless of which store it came from." })
export type HooksConfig = { readonly "hooks"?: ReadonlyArray<HookEntry> }
export const HooksConfig = Schema.Struct({ "hooks": Schema.optionalKey(Schema.Array(HookEntry)) }).annotate({ "description": "The operator's hook configuration — the `hooks.json` document and the `/api/v1/hooks` body." })
export type LogPage = { readonly "dropped": boolean, readonly "entries": ReadonlyArray<LogEntry>, readonly "next": number }
export const LogPage = Schema.Struct({ "dropped": Schema.Boolean.annotate({ "description": "True when entries between `after` and the first returned one were already evicted." }), "entries": Schema.Array(LogEntry), "next": Schema.Number.annotate({ "description": "Cursor for the next poll (the last returned seq, or the request's `after` when empty).", "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) }).annotate({ "description": "One poll's worth of log entries." })
export type ClientRef = { readonly "fingerprint"?: string | null, readonly "name": string, readonly "plane": Plane }
export const ClientRef = Schema.Struct({ "fingerprint": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Hex SHA-256 certificate fingerprint, when the client presented one." })), "name": Schema.String.annotate({ "description": "Client-supplied device name; may be empty (an anonymous or compat-plane client)." }), "plane": Plane }).annotate({ "description": "The connecting/disconnecting client's identity." })
export type DeviceRef = { readonly "fingerprint": string, readonly "name": string, readonly "plane": Plane }
export const DeviceRef = Schema.Struct({ "fingerprint": Schema.String.annotate({ "description": "Hex certificate fingerprint." }), "name": Schema.String.annotate({ "description": "Sanitized device name (the pairing store's copy)." }), "plane": Plane }).annotate({ "description": "A device in the pairing flow." })
export type StreamRef = { readonly "app"?: string | null, readonly "client": string, readonly "hdr": boolean, readonly "mode": string, readonly "plane": Plane }
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<ApiCodec>, 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 DisplayLayoutRequest = { readonly "positions"?: { readonly [x: string]: Position } }
export const DisplayLayoutRequest = Schema.Struct({ "positions": Schema.optionalKey(Schema.Record(Schema.String, Position).annotate({ "description": "`{\"<identity_slot>\": {\"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 } }
export const Layout = Schema.Struct({ "mode": Schema.optionalKey(LayoutMode), "positions": Schema.optionalKey(Schema.Record(Schema.String, Position).check(Schema.isPropertyNames(Schema.String))) }).annotate({ "description": "Group layout: the arrangement mode plus, for [`LayoutMode::Manual`], per-slot offsets keyed by\nidentity-slot id (string keys for stable JSON)." })
export type CustomEntry = { readonly "art"?: Artwork, readonly "external_id"?: string | null, readonly "id": string, readonly "launch"?: null | LaunchSpec, readonly "prep"?: ReadonlyArray<PrepCmd>, readonly "provider"?: string | null, readonly "title": string }
export const CustomEntry = Schema.Struct({ "art": Schema.optionalKey(Artwork), "external_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The provider's own stable key for this title — the reconcile diff key, so the\nhost-assigned `id` stays stable across reconciles. Present iff `provider` is." })), "id": Schema.String.annotate({ "description": "Host-assigned, stable for the life of the entry (the `{id}` in the CRUD path)." }), "launch": Schema.optionalKey(Schema.Union([Schema.Null, LaunchSpec], { mode: "oneOf" })), "prep": Schema.optionalKey(Schema.Array(PrepCmd).annotate({ "description": "Per-title prep/undo steps (RFC §6): each `do` runs before this title launches, each\n`undo` at session end in reverse order (see [`crate::hooks::run_prep`])." })), "provider": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The external provider owning this entry (RFC §8), set ONLY by the provider reconcile\nAPI — `None` = a manual entry, which no provider operation ever touches, and which the\nmanual CRUD alone may edit (the converse holds too: manual CRUD refuses provider-owned\nentries, so ownership is never ambiguous)." })), "title": Schema.String }).annotate({ "description": "A user-added title, persisted in the hardened host config dir's `library.json` (see\n[`custom_path`]). Same shape the API returns and the web console edits." })
export type CustomInput = { readonly "art"?: Artwork, readonly "launch"?: null | LaunchSpec, readonly "prep"?: ReadonlyArray<PrepCmd>, readonly "title": string }
export const CustomInput = Schema.Struct({ "art": Schema.optionalKey(Artwork), "launch": Schema.optionalKey(Schema.Union([Schema.Null, LaunchSpec], { mode: "oneOf" })), "prep": Schema.optionalKey(Schema.Array(PrepCmd).annotate({ "description": "Per-title prep/undo steps — commands run as the host user; operator-privileged config." })), "title": Schema.String }).annotate({ "description": "Request body to create or replace a custom entry (no `id` — the host owns it)." })
export type ProviderEntryInput = { readonly "art"?: Artwork, readonly "external_id": string, readonly "launch"?: null | LaunchSpec, readonly "prep"?: ReadonlyArray<PrepCmd>, readonly "title": string }
export const ProviderEntryInput = Schema.Struct({ "art": Schema.optionalKey(Artwork), "external_id": Schema.String.annotate({ "description": "The provider's stable id for this title (the reconcile diff key)." }), "launch": Schema.optionalKey(Schema.Union([Schema.Null, LaunchSpec], { mode: "oneOf" })), "prep": Schema.optionalKey(Schema.Array(PrepCmd).annotate({ "description": "Per-title prep/undo steps — commands run as the host user; operator-privileged config." })), "title": Schema.String }).annotate({ "description": "One title in a provider's declarative reconcile payload (RFC §8): [`CustomInput`] plus the\nprovider's required stable key." })
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<StageTiming>, 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 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 "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 "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({ "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({ "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`<config>/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 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 }
export const PresetInfo = 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 effective policy this preset expands to (the same fields a `custom` policy carries)." }), "id": Schema.String.annotate({ "description": "The preset id (`default` | `gaming-rig` | `shared-desktop` | `hotdesk` | `workstation`)." }), "summary": Schema.String.annotate({ "description": "One-line story shown next to the option." }) }).annotate({ "description": "One preset's human-facing description + the fields it expands to, so the console can render a\npreset picker with an accurate \"what this does\" preview without hardcoding the expansion." })
export type Capture = { readonly "meta": CaptureMeta, readonly "samples": ReadonlyArray<StatsSample> }
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<CustomPreset>, 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<string>, readonly "presets": ReadonlyArray<PresetInfo>, 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)." })
// schemas
export type ListPairedClients200 = ReadonlyArray<PairedClient>
export const ListPairedClients200 = Schema.Array(PairedClient)
export type ListPairedClients401 = ApiError
export const ListPairedClients401 = ApiError
export type UnpairClient400 = ApiError
export const UnpairClient400 = ApiError
export type UnpairClient401 = ApiError
export const UnpairClient401 = ApiError
export type UnpairClient404 = ApiError
export const UnpairClient404 = ApiError
export type ListCompositors200 = ReadonlyArray<AvailableCompositor>
export const ListCompositors200 = Schema.Array(AvailableCompositor)
export type ListCompositors401 = ApiError
export const ListCompositors401 = ApiError
export type SetDisplayLayoutRequestJson = DisplayLayoutRequest
export const SetDisplayLayoutRequestJson = DisplayLayoutRequest
export type SetDisplayLayout200 = DisplaySettingsState
export const SetDisplayLayout200 = DisplaySettingsState
export type SetDisplayLayout401 = ApiError
export const SetDisplayLayout401 = ApiError
export type SetDisplayLayout500 = ApiError
export const SetDisplayLayout500 = ApiError
export type ListCustomPresets200 = ReadonlyArray<CustomPreset>
export const ListCustomPresets200 = Schema.Array(CustomPreset)
export type ListCustomPresets401 = ApiError
export const ListCustomPresets401 = ApiError
export type CreateCustomPresetRequestJson = CustomPresetInput
export const CreateCustomPresetRequestJson = CustomPresetInput
export type CreateCustomPreset201 = CustomPreset
export const CreateCustomPreset201 = CustomPreset
export type CreateCustomPreset400 = ApiError
export const CreateCustomPreset400 = ApiError
export type CreateCustomPreset401 = ApiError
export const CreateCustomPreset401 = ApiError
export type CreateCustomPreset500 = ApiError
export const CreateCustomPreset500 = ApiError
export type UpdateCustomPresetRequestJson = CustomPresetInput
export const UpdateCustomPresetRequestJson = CustomPresetInput
export type UpdateCustomPreset200 = CustomPreset
export const UpdateCustomPreset200 = CustomPreset
export type UpdateCustomPreset400 = ApiError
export const UpdateCustomPreset400 = ApiError
export type UpdateCustomPreset401 = ApiError
export const UpdateCustomPreset401 = ApiError
export type UpdateCustomPreset404 = ApiError
export const UpdateCustomPreset404 = ApiError
export type UpdateCustomPreset500 = ApiError
export const UpdateCustomPreset500 = ApiError
export type DeleteCustomPreset401 = ApiError
export const DeleteCustomPreset401 = ApiError
export type DeleteCustomPreset404 = ApiError
export const DeleteCustomPreset404 = ApiError
export type DeleteCustomPreset500 = ApiError
export const DeleteCustomPreset500 = ApiError
export type ReleaseDisplayRequestJson = ReleaseDisplayRequest
export const ReleaseDisplayRequestJson = ReleaseDisplayRequest
export type ReleaseDisplay200 = ReleaseDisplayResult
export const ReleaseDisplay200 = ReleaseDisplayResult
export type ReleaseDisplay401 = ApiError
export const ReleaseDisplay401 = ApiError
export type GetDisplaySettings200 = DisplaySettingsState
export const GetDisplaySettings200 = DisplaySettingsState
export type GetDisplaySettings401 = ApiError
export const GetDisplaySettings401 = ApiError
export type SetDisplaySettingsRequestJson = DisplayPolicy
export const SetDisplaySettingsRequestJson = DisplayPolicy
export type SetDisplaySettings200 = DisplaySettingsState
export const SetDisplaySettings200 = DisplaySettingsState
export type SetDisplaySettings400 = ApiError
export const SetDisplaySettings400 = ApiError
export type SetDisplaySettings401 = ApiError
export const SetDisplaySettings401 = ApiError
export type SetDisplaySettings500 = ApiError
export const SetDisplaySettings500 = ApiError
export type GetDisplayState200 = DisplayStateResponse
export const GetDisplayState200 = DisplayStateResponse
export type GetDisplayState401 = ApiError
export const GetDisplayState401 = ApiError
export type StreamEventsParams = { readonly "since"?: number, readonly "kinds"?: string, readonly "Last-Event-ID"?: never }
export const StreamEventsParams = Schema.Struct({ "since": Schema.optionalKey(Schema.Number.annotate({ "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))), "kinds": Schema.optionalKey(Schema.String), "Last-Event-ID": Schema.optionalKey(Schema.Never) })
export type StreamEvents200Sse = HostEvent
export const StreamEvents200Sse = HostEvent
export type StreamEvents401 = ApiError
export const StreamEvents401 = ApiError
export type StreamEvents503 = ApiError
export const StreamEvents503 = ApiError
export type ListGpus200 = GpuState
export const ListGpus200 = GpuState
export type ListGpus401 = ApiError
export const ListGpus401 = ApiError
export type SetGpuPreferenceRequestJson = SetGpuPreference
export const SetGpuPreferenceRequestJson = SetGpuPreference
export type SetGpuPreference200 = GpuState
export const SetGpuPreference200 = GpuState
export type SetGpuPreference400 = ApiError
export const SetGpuPreference400 = ApiError
export type SetGpuPreference401 = ApiError
export const SetGpuPreference401 = ApiError
export type SetGpuPreference500 = ApiError
export const SetGpuPreference500 = ApiError
export type GetHealth200 = Health
export const GetHealth200 = Health
export type GetHooks200 = HooksConfig
export const GetHooks200 = HooksConfig
export type GetHooks401 = ApiError
export const GetHooks401 = ApiError
export type SetHooksRequestJson = HooksConfig
export const SetHooksRequestJson = HooksConfig
export type SetHooks200 = HooksConfig
export const SetHooks200 = HooksConfig
export type SetHooks400 = ApiError
export const SetHooks400 = ApiError
export type SetHooks401 = ApiError
export const SetHooks401 = ApiError
export type SetHooks500 = ApiError
export const SetHooks500 = ApiError
export type GetHostInfo200 = HostInfo
export const GetHostInfo200 = HostInfo
export type GetHostInfo401 = ApiError
export const GetHostInfo401 = ApiError
export type GetLibraryParams = { readonly "provider"?: string }
export const GetLibraryParams = Schema.Struct({ "provider": Schema.optionalKey(Schema.String) })
export type GetLibrary200 = ReadonlyArray<GameEntry>
export const GetLibrary200 = Schema.Array(GameEntry)
export type GetLibrary401 = ApiError
export const GetLibrary401 = ApiError
export type GetLibraryArt401 = ApiError
export const GetLibraryArt401 = ApiError
export type GetLibraryArt404 = ApiError
export const GetLibraryArt404 = ApiError
export type CreateCustomGameRequestJson = CustomInput
export const CreateCustomGameRequestJson = CustomInput
export type CreateCustomGame201 = CustomEntry
export const CreateCustomGame201 = CustomEntry
export type CreateCustomGame400 = ApiError
export const CreateCustomGame400 = ApiError
export type CreateCustomGame401 = ApiError
export const CreateCustomGame401 = ApiError
export type CreateCustomGame500 = ApiError
export const CreateCustomGame500 = ApiError
export type UpdateCustomGameRequestJson = CustomInput
export const UpdateCustomGameRequestJson = CustomInput
export type UpdateCustomGame200 = CustomEntry
export const UpdateCustomGame200 = CustomEntry
export type UpdateCustomGame400 = ApiError
export const UpdateCustomGame400 = ApiError
export type UpdateCustomGame401 = ApiError
export const UpdateCustomGame401 = ApiError
export type UpdateCustomGame404 = ApiError
export const UpdateCustomGame404 = ApiError
export type UpdateCustomGame500 = ApiError
export const UpdateCustomGame500 = ApiError
export type DeleteCustomGame401 = ApiError
export const DeleteCustomGame401 = ApiError
export type DeleteCustomGame404 = ApiError
export const DeleteCustomGame404 = ApiError
export type DeleteCustomGame500 = ApiError
export const DeleteCustomGame500 = ApiError
export type ReconcileProviderEntriesRequestJson = ReadonlyArray<ProviderEntryInput>
export const ReconcileProviderEntriesRequestJson = Schema.Array(ProviderEntryInput)
export type ReconcileProviderEntries200 = ReadonlyArray<CustomEntry>
export const ReconcileProviderEntries200 = Schema.Array(CustomEntry)
export type ReconcileProviderEntries400 = ApiError
export const ReconcileProviderEntries400 = ApiError
export type ReconcileProviderEntries401 = ApiError
export const ReconcileProviderEntries401 = ApiError
export type ReconcileProviderEntries500 = ApiError
export const ReconcileProviderEntries500 = ApiError
export type DeleteProviderEntries200 = ProviderRemoved
export const DeleteProviderEntries200 = ProviderRemoved
export type DeleteProviderEntries400 = ApiError
export const DeleteProviderEntries400 = ApiError
export type DeleteProviderEntries401 = ApiError
export const DeleteProviderEntries401 = ApiError
export type DeleteProviderEntries500 = ApiError
export const DeleteProviderEntries500 = ApiError
export type GetLocalSummary200 = LocalSummary
export const GetLocalSummary200 = LocalSummary
export type GetLocalSummary401 = ApiError
export const GetLocalSummary401 = ApiError
export type LogsGetParams = { readonly "after"?: number, readonly "limit"?: number }
export const LogsGetParams = Schema.Struct({ "after": Schema.optionalKey(Schema.Number.annotate({ "format": "int64" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))), "limit": Schema.optionalKey(Schema.Number.annotate({ "format": "int32" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))) })
export type LogsGet200 = LogPage
export const LogsGet200 = LogPage
export type LogsGet401 = ApiError
export const LogsGet401 = ApiError
export type ListNativeClients200 = ReadonlyArray<NativeClient>
export const ListNativeClients200 = Schema.Array(NativeClient)
export type ListNativeClients401 = ApiError
export const ListNativeClients401 = ApiError
export type UnpairNativeClient401 = ApiError
export const UnpairNativeClient401 = ApiError
export type UnpairNativeClient404 = ApiError
export const UnpairNativeClient404 = ApiError
export type UnpairNativeClient503 = ApiError
export const UnpairNativeClient503 = ApiError
export type GetNativePairing200 = NativePairStatus
export const GetNativePairing200 = NativePairStatus
export type GetNativePairing401 = ApiError
export const GetNativePairing401 = ApiError
export type DisarmNativePairing401 = ApiError
export const DisarmNativePairing401 = ApiError
export type DisarmNativePairing503 = ApiError
export const DisarmNativePairing503 = ApiError
export type ArmNativePairingRequestJson = ArmNativePairing
export const ArmNativePairingRequestJson = ArmNativePairing
export type ArmNativePairing200 = NativePairStatus
export const ArmNativePairing200 = NativePairStatus
export type ArmNativePairing401 = ApiError
export const ArmNativePairing401 = ApiError
export type ArmNativePairing503 = ApiError
export const ArmNativePairing503 = ApiError
export type ListPendingDevices200 = ReadonlyArray<PendingDevice>
export const ListPendingDevices200 = Schema.Array(PendingDevice)
export type ListPendingDevices401 = ApiError
export const ListPendingDevices401 = ApiError
export type ApprovePendingDeviceRequestJson = ApprovePending
export const ApprovePendingDeviceRequestJson = ApprovePending
export type ApprovePendingDevice200 = NativeClient
export const ApprovePendingDevice200 = NativeClient
export type ApprovePendingDevice401 = ApiError
export const ApprovePendingDevice401 = ApiError
export type ApprovePendingDevice404 = ApiError
export const ApprovePendingDevice404 = ApiError
export type ApprovePendingDevice500 = ApiError
export const ApprovePendingDevice500 = ApiError
export type ApprovePendingDevice503 = ApiError
export const ApprovePendingDevice503 = ApiError
export type DenyPendingDevice401 = ApiError
export const DenyPendingDevice401 = ApiError
export type DenyPendingDevice404 = ApiError
export const DenyPendingDevice404 = ApiError
export type DenyPendingDevice503 = ApiError
export const DenyPendingDevice503 = ApiError
export type GetPairingStatus200 = PairingStatus
export const GetPairingStatus200 = PairingStatus
export type GetPairingStatus401 = ApiError
export const GetPairingStatus401 = ApiError
export type SubmitPairingPinRequestJson = SubmitPin
export const SubmitPairingPinRequestJson = SubmitPin
export type SubmitPairingPin400 = ApiError
export const SubmitPairingPin400 = ApiError
export type SubmitPairingPin401 = ApiError
export const SubmitPairingPin401 = ApiError
export type SubmitPairingPin409 = ApiError
export const SubmitPairingPin409 = ApiError
export type SubmitPairingPin415 = ApiError
export const SubmitPairingPin415 = ApiError
export type SubmitPairingPin422 = ApiError
export const SubmitPairingPin422 = ApiError
export type ListPlugins200 = ReadonlyArray<PluginSummary>
export const ListPlugins200 = Schema.Array(PluginSummary)
export type ListPlugins401 = ApiError
export const ListPlugins401 = ApiError
export type RegisterPluginRequestJson = PluginRegistration
export const RegisterPluginRequestJson = PluginRegistration
export type RegisterPlugin400 = ApiError
export const RegisterPlugin400 = ApiError
export type RegisterPlugin401 = ApiError
export const RegisterPlugin401 = ApiError
export type DeregisterPlugin401 = ApiError
export const DeregisterPlugin401 = ApiError
export type GetPluginUiCredential200 = UiCredential
export const GetPluginUiCredential200 = UiCredential
export type GetPluginUiCredential401 = ApiError
export const GetPluginUiCredential401 = ApiError
export type GetPluginUiCredential404 = ApiError
export const GetPluginUiCredential404 = ApiError
export type StopSession401 = ApiError
export const StopSession401 = ApiError
export type RequestIdr401 = ApiError
export const RequestIdr401 = ApiError
export type RequestIdr409 = ApiError
export const RequestIdr409 = ApiError
export type StatsCaptureLive200 = Capture
export const StatsCaptureLive200 = Capture
export type StatsCaptureLive401 = ApiError
export const StatsCaptureLive401 = ApiError
export type StatsCaptureLive404 = ApiError
export const StatsCaptureLive404 = ApiError
export type StatsCaptureStart200 = StatsStatus
export const StatsCaptureStart200 = StatsStatus
export type StatsCaptureStart401 = ApiError
export const StatsCaptureStart401 = ApiError
export type StatsCaptureStatus200 = StatsStatus
export const StatsCaptureStatus200 = StatsStatus
export type StatsCaptureStatus401 = ApiError
export const StatsCaptureStatus401 = ApiError
export type StatsCaptureStop200 = CaptureMeta
export const StatsCaptureStop200 = CaptureMeta
export type StatsCaptureStop401 = ApiError
export const StatsCaptureStop401 = ApiError
export type StatsCaptureStop500 = ApiError
export const StatsCaptureStop500 = ApiError
export type StatsRecordingsList200 = ReadonlyArray<CaptureMeta>
export const StatsRecordingsList200 = Schema.Array(CaptureMeta)
export type StatsRecordingsList401 = ApiError
export const StatsRecordingsList401 = ApiError
export type StatsRecordingGet200 = Capture
export const StatsRecordingGet200 = Capture
export type StatsRecordingGet401 = ApiError
export const StatsRecordingGet401 = ApiError
export type StatsRecordingGet404 = ApiError
export const StatsRecordingGet404 = ApiError
export type StatsRecordingGet500 = ApiError
export const StatsRecordingGet500 = ApiError
export type StatsRecordingDelete401 = ApiError
export const StatsRecordingDelete401 = ApiError
export type StatsRecordingDelete404 = ApiError
export const StatsRecordingDelete404 = ApiError
export type StatsRecordingDelete500 = ApiError
export const StatsRecordingDelete500 = ApiError
export type GetStatus200 = RuntimeStatus
export const GetStatus200 = RuntimeStatus
export type GetStatus401 = ApiError
export const GetStatus401 = ApiError
export interface OperationConfig {
/**
* Whether or not the response should be included in the value returned from
* an operation.
*
* If set to `true`, a tuple of `[A, HttpClientResponse]` will be returned,
* where `A` is the success type of the operation.
*
* If set to `false`, only the success type of the operation will be returned.
*/
readonly includeResponse?: boolean | undefined
}
/**
* A utility type which optionally includes the response in the return result
* of an operation based upon the value of the `includeResponse` configuration
* option.
*/
export type WithOptionalResponse<A, Config extends OperationConfig> = Config extends {
readonly includeResponse: true
} ? [A, HttpClientResponse.HttpClientResponse] : A
export const make = (
httpClient: HttpClient.HttpClient,
options: {
readonly transformClient?: ((client: HttpClient.HttpClient) => Effect.Effect<HttpClient.HttpClient>) | undefined
} = {}
): Punktfunk => {
const unexpectedStatus = (response: HttpClientResponse.HttpClientResponse) =>
Effect.flatMap(
Effect.orElseSucceed(response.json, () => "Unexpected status code"),
(description) =>
Effect.fail(
new HttpClientError.HttpClientError({
reason: new HttpClientError.StatusCodeError({
request: response.request,
response,
description: typeof description === "string" ? description : JSON.stringify(description),
}),
}),
),
)
const withResponse = <Config extends OperationConfig>(config: Config | undefined) => (
f: (response: HttpClientResponse.HttpClientResponse) => Effect.Effect<any, any>,
): (request: HttpClientRequest.HttpClientRequest) => Effect.Effect<any, any> => {
const withOptionalResponse = (
config?.includeResponse
? (response: HttpClientResponse.HttpClientResponse) => Effect.map(f(response), (a) => [a, response])
: (response: HttpClientResponse.HttpClientResponse) => f(response)
) as any
return options?.transformClient
? (request) =>
Effect.flatMap(
Effect.flatMap(options.transformClient!(httpClient), (client) => client.execute(request)),
withOptionalResponse
)
: (request) => Effect.flatMap(httpClient.execute(request), withOptionalResponse)
}
const sseRequest = <
Type,
DecodingServices
>(
schema: Schema.ConstraintDecoder<Type, DecodingServices>
) =>
(
request: HttpClientRequest.HttpClientRequest
): Stream.Stream<
{ readonly event: string; readonly id: string | undefined; readonly data: Type },
HttpClientError.HttpClientError | SchemaError | Sse.Retry,
DecodingServices
> =>
HttpClient.filterStatusOk(httpClient).execute(request).pipe(
Effect.map((response) => response.stream),
Stream.unwrap,
Stream.decodeText(),
Stream.pipeThroughChannel(Sse.decodeDataSchema(schema))
)
const decodeSuccess =
<Schema extends Schema.Constraint>(schema: Schema) =>
(response: HttpClientResponse.HttpClientResponse) =>
HttpClientResponse.schemaBodyJson(schema)(response)
const decodeError =
<const Tag extends string, Schema extends Schema.Constraint>(tag: Tag, schema: Schema) =>
(response: HttpClientResponse.HttpClientResponse) =>
Effect.flatMap(
HttpClientResponse.schemaBodyJson(schema)(response),
(cause) => Effect.fail(PunktfunkError(tag, cause, response)),
)
return {
httpClient,
"listPairedClients": (options) => HttpClientRequest.get(`/api/v1/clients`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(ListPairedClients200),
"401": decodeError("ListPairedClients401", ListPairedClients401),
orElse: unexpectedStatus
}))
),
"unpairClient": (fingerprint, options) => HttpClientRequest.delete(`/api/v1/clients/${fingerprint}`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"400": decodeError("UnpairClient400", UnpairClient400),
"401": decodeError("UnpairClient401", UnpairClient401),
"404": decodeError("UnpairClient404", UnpairClient404),
"204": () => Effect.void,
orElse: unexpectedStatus
}))
),
"listCompositors": (options) => HttpClientRequest.get(`/api/v1/compositors`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(ListCompositors200),
"401": decodeError("ListCompositors401", ListCompositors401),
orElse: unexpectedStatus
}))
),
"setDisplayLayout": (options) => HttpClientRequest.put(`/api/v1/display/layout`).pipe(
HttpClientRequest.bodyJsonUnsafe(options.payload),
withResponse(options.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(SetDisplayLayout200),
"401": decodeError("SetDisplayLayout401", SetDisplayLayout401),
"500": decodeError("SetDisplayLayout500", SetDisplayLayout500),
orElse: unexpectedStatus
}))
),
"listCustomPresets": (options) => HttpClientRequest.get(`/api/v1/display/presets`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(ListCustomPresets200),
"401": decodeError("ListCustomPresets401", ListCustomPresets401),
orElse: unexpectedStatus
}))
),
"createCustomPreset": (options) => HttpClientRequest.post(`/api/v1/display/presets`).pipe(
HttpClientRequest.bodyJsonUnsafe(options.payload),
withResponse(options.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(CreateCustomPreset201),
"400": decodeError("CreateCustomPreset400", CreateCustomPreset400),
"401": decodeError("CreateCustomPreset401", CreateCustomPreset401),
"500": decodeError("CreateCustomPreset500", CreateCustomPreset500),
orElse: unexpectedStatus
}))
),
"updateCustomPreset": (id, options) => HttpClientRequest.put(`/api/v1/display/presets/${id}`).pipe(
HttpClientRequest.bodyJsonUnsafe(options.payload),
withResponse(options.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(UpdateCustomPreset200),
"400": decodeError("UpdateCustomPreset400", UpdateCustomPreset400),
"401": decodeError("UpdateCustomPreset401", UpdateCustomPreset401),
"404": decodeError("UpdateCustomPreset404", UpdateCustomPreset404),
"500": decodeError("UpdateCustomPreset500", UpdateCustomPreset500),
orElse: unexpectedStatus
}))
),
"deleteCustomPreset": (id, options) => HttpClientRequest.delete(`/api/v1/display/presets/${id}`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"401": decodeError("DeleteCustomPreset401", DeleteCustomPreset401),
"404": decodeError("DeleteCustomPreset404", DeleteCustomPreset404),
"500": decodeError("DeleteCustomPreset500", DeleteCustomPreset500),
"204": () => Effect.void,
orElse: unexpectedStatus
}))
),
"releaseDisplay": (options) => HttpClientRequest.post(`/api/v1/display/release`).pipe(
HttpClientRequest.bodyJsonUnsafe(options.payload),
withResponse(options.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(ReleaseDisplay200),
"401": decodeError("ReleaseDisplay401", ReleaseDisplay401),
orElse: unexpectedStatus
}))
),
"getDisplaySettings": (options) => HttpClientRequest.get(`/api/v1/display/settings`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(GetDisplaySettings200),
"401": decodeError("GetDisplaySettings401", GetDisplaySettings401),
orElse: unexpectedStatus
}))
),
"setDisplaySettings": (options) => HttpClientRequest.put(`/api/v1/display/settings`).pipe(
HttpClientRequest.bodyJsonUnsafe(options.payload),
withResponse(options.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(SetDisplaySettings200),
"400": decodeError("SetDisplaySettings400", SetDisplaySettings400),
"401": decodeError("SetDisplaySettings401", SetDisplaySettings401),
"500": decodeError("SetDisplaySettings500", SetDisplaySettings500),
orElse: unexpectedStatus
}))
),
"getDisplayState": (options) => HttpClientRequest.get(`/api/v1/display/state`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(GetDisplayState200),
"401": decodeError("GetDisplayState401", GetDisplayState401),
orElse: unexpectedStatus
}))
),
"streamEvents": (options) => HttpClientRequest.get(`/api/v1/events`).pipe(
HttpClientRequest.setUrlParams({ "since": options?.params?.["since"] as any, "kinds": options?.params?.["kinds"] as any }),
HttpClientRequest.setHeaders({ "Last-Event-ID": options?.params?.["Last-Event-ID"] ?? undefined }),
withResponse(options?.config)(HttpClientResponse.matchStatus({
"401": decodeError("StreamEvents401", StreamEvents401),
"503": decodeError("StreamEvents503", StreamEvents503),
orElse: unexpectedStatus
}))
),
"streamEventsSse": (options) => HttpClientRequest.get(`/api/v1/events`).pipe(
HttpClientRequest.setUrlParams({ "since": options?.params?.["since"] as any, "kinds": options?.params?.["kinds"] as any }),
HttpClientRequest.setHeaders({ "Last-Event-ID": options?.params?.["Last-Event-ID"] ?? undefined }),
sseRequest(StreamEvents200Sse)
),
"listGpus": (options) => HttpClientRequest.get(`/api/v1/gpus`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(ListGpus200),
"401": decodeError("ListGpus401", ListGpus401),
orElse: unexpectedStatus
}))
),
"setGpuPreference": (options) => HttpClientRequest.put(`/api/v1/gpus/preference`).pipe(
HttpClientRequest.bodyJsonUnsafe(options.payload),
withResponse(options.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(SetGpuPreference200),
"400": decodeError("SetGpuPreference400", SetGpuPreference400),
"401": decodeError("SetGpuPreference401", SetGpuPreference401),
"500": decodeError("SetGpuPreference500", SetGpuPreference500),
orElse: unexpectedStatus
}))
),
"getHealth": (options) => HttpClientRequest.get(`/api/v1/health`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(GetHealth200),
orElse: unexpectedStatus
}))
),
"getHooks": (options) => HttpClientRequest.get(`/api/v1/hooks`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(GetHooks200),
"401": decodeError("GetHooks401", GetHooks401),
orElse: unexpectedStatus
}))
),
"setHooks": (options) => HttpClientRequest.put(`/api/v1/hooks`).pipe(
HttpClientRequest.bodyJsonUnsafe(options.payload),
withResponse(options.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(SetHooks200),
"400": decodeError("SetHooks400", SetHooks400),
"401": decodeError("SetHooks401", SetHooks401),
"500": decodeError("SetHooks500", SetHooks500),
orElse: unexpectedStatus
}))
),
"getHostInfo": (options) => HttpClientRequest.get(`/api/v1/host`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(GetHostInfo200),
"401": decodeError("GetHostInfo401", GetHostInfo401),
orElse: unexpectedStatus
}))
),
"getLibrary": (options) => HttpClientRequest.get(`/api/v1/library`).pipe(
HttpClientRequest.setUrlParams({ "provider": options?.params?.["provider"] as any }),
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(GetLibrary200),
"401": decodeError("GetLibrary401", GetLibrary401),
orElse: unexpectedStatus
}))
),
"getLibraryArt": (id, kind, options) => HttpClientRequest.get(`/api/v1/library/art/${id}/${kind}`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"401": decodeError("GetLibraryArt401", GetLibraryArt401),
"404": decodeError("GetLibraryArt404", GetLibraryArt404),
orElse: unexpectedStatus
}))
),
"createCustomGame": (options) => HttpClientRequest.post(`/api/v1/library/custom`).pipe(
HttpClientRequest.bodyJsonUnsafe(options.payload),
withResponse(options.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(CreateCustomGame201),
"400": decodeError("CreateCustomGame400", CreateCustomGame400),
"401": decodeError("CreateCustomGame401", CreateCustomGame401),
"500": decodeError("CreateCustomGame500", CreateCustomGame500),
orElse: unexpectedStatus
}))
),
"updateCustomGame": (id, options) => HttpClientRequest.put(`/api/v1/library/custom/${id}`).pipe(
HttpClientRequest.bodyJsonUnsafe(options.payload),
withResponse(options.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(UpdateCustomGame200),
"400": decodeError("UpdateCustomGame400", UpdateCustomGame400),
"401": decodeError("UpdateCustomGame401", UpdateCustomGame401),
"404": decodeError("UpdateCustomGame404", UpdateCustomGame404),
"500": decodeError("UpdateCustomGame500", UpdateCustomGame500),
orElse: unexpectedStatus
}))
),
"deleteCustomGame": (id, options) => HttpClientRequest.delete(`/api/v1/library/custom/${id}`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"401": decodeError("DeleteCustomGame401", DeleteCustomGame401),
"404": decodeError("DeleteCustomGame404", DeleteCustomGame404),
"500": decodeError("DeleteCustomGame500", DeleteCustomGame500),
"204": () => Effect.void,
orElse: unexpectedStatus
}))
),
"reconcileProviderEntries": (provider, options) => HttpClientRequest.put(`/api/v1/library/provider/${provider}`).pipe(
HttpClientRequest.bodyJsonUnsafe(options.payload),
withResponse(options.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(ReconcileProviderEntries200),
"400": decodeError("ReconcileProviderEntries400", ReconcileProviderEntries400),
"401": decodeError("ReconcileProviderEntries401", ReconcileProviderEntries401),
"500": decodeError("ReconcileProviderEntries500", ReconcileProviderEntries500),
orElse: unexpectedStatus
}))
),
"deleteProviderEntries": (provider, options) => HttpClientRequest.delete(`/api/v1/library/provider/${provider}`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(DeleteProviderEntries200),
"400": decodeError("DeleteProviderEntries400", DeleteProviderEntries400),
"401": decodeError("DeleteProviderEntries401", DeleteProviderEntries401),
"500": decodeError("DeleteProviderEntries500", DeleteProviderEntries500),
orElse: unexpectedStatus
}))
),
"getLocalSummary": (options) => HttpClientRequest.get(`/api/v1/local/summary`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(GetLocalSummary200),
"401": decodeError("GetLocalSummary401", GetLocalSummary401),
orElse: unexpectedStatus
}))
),
"logsGet": (options) => HttpClientRequest.get(`/api/v1/logs`).pipe(
HttpClientRequest.setUrlParams({ "after": options?.params?.["after"] as any, "limit": options?.params?.["limit"] as any }),
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(LogsGet200),
"401": decodeError("LogsGet401", LogsGet401),
orElse: unexpectedStatus
}))
),
"listNativeClients": (options) => HttpClientRequest.get(`/api/v1/native/clients`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(ListNativeClients200),
"401": decodeError("ListNativeClients401", ListNativeClients401),
orElse: unexpectedStatus
}))
),
"unpairNativeClient": (fingerprint, options) => HttpClientRequest.delete(`/api/v1/native/clients/${fingerprint}`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"401": decodeError("UnpairNativeClient401", UnpairNativeClient401),
"404": decodeError("UnpairNativeClient404", UnpairNativeClient404),
"503": decodeError("UnpairNativeClient503", UnpairNativeClient503),
"204": () => Effect.void,
orElse: unexpectedStatus
}))
),
"getNativePairing": (options) => HttpClientRequest.get(`/api/v1/native/pair`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(GetNativePairing200),
"401": decodeError("GetNativePairing401", GetNativePairing401),
orElse: unexpectedStatus
}))
),
"disarmNativePairing": (options) => HttpClientRequest.delete(`/api/v1/native/pair`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"401": decodeError("DisarmNativePairing401", DisarmNativePairing401),
"503": decodeError("DisarmNativePairing503", DisarmNativePairing503),
"204": () => Effect.void,
orElse: unexpectedStatus
}))
),
"armNativePairing": (options) => HttpClientRequest.post(`/api/v1/native/pair/arm`).pipe(
HttpClientRequest.bodyJsonUnsafe(options.payload),
withResponse(options.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(ArmNativePairing200),
"401": decodeError("ArmNativePairing401", ArmNativePairing401),
"503": decodeError("ArmNativePairing503", ArmNativePairing503),
orElse: unexpectedStatus
}))
),
"listPendingDevices": (options) => HttpClientRequest.get(`/api/v1/native/pending`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(ListPendingDevices200),
"401": decodeError("ListPendingDevices401", ListPendingDevices401),
orElse: unexpectedStatus
}))
),
"approvePendingDevice": (id, options) => HttpClientRequest.post(`/api/v1/native/pending/${id}/approve`).pipe(
HttpClientRequest.bodyJsonUnsafe(options.payload),
withResponse(options.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(ApprovePendingDevice200),
"401": decodeError("ApprovePendingDevice401", ApprovePendingDevice401),
"404": decodeError("ApprovePendingDevice404", ApprovePendingDevice404),
"500": decodeError("ApprovePendingDevice500", ApprovePendingDevice500),
"503": decodeError("ApprovePendingDevice503", ApprovePendingDevice503),
orElse: unexpectedStatus
}))
),
"denyPendingDevice": (id, options) => HttpClientRequest.post(`/api/v1/native/pending/${id}/deny`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"401": decodeError("DenyPendingDevice401", DenyPendingDevice401),
"404": decodeError("DenyPendingDevice404", DenyPendingDevice404),
"503": decodeError("DenyPendingDevice503", DenyPendingDevice503),
"204": () => Effect.void,
orElse: unexpectedStatus
}))
),
"getPairingStatus": (options) => HttpClientRequest.get(`/api/v1/pair`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(GetPairingStatus200),
"401": decodeError("GetPairingStatus401", GetPairingStatus401),
orElse: unexpectedStatus
}))
),
"submitPairingPin": (options) => HttpClientRequest.post(`/api/v1/pair/pin`).pipe(
HttpClientRequest.bodyJsonUnsafe(options.payload),
withResponse(options.config)(HttpClientResponse.matchStatus({
"400": decodeError("SubmitPairingPin400", SubmitPairingPin400),
"401": decodeError("SubmitPairingPin401", SubmitPairingPin401),
"409": decodeError("SubmitPairingPin409", SubmitPairingPin409),
"415": decodeError("SubmitPairingPin415", SubmitPairingPin415),
"422": decodeError("SubmitPairingPin422", SubmitPairingPin422),
"204": () => Effect.void,
orElse: unexpectedStatus
}))
),
"listPlugins": (options) => HttpClientRequest.get(`/api/v1/plugins`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(ListPlugins200),
"401": decodeError("ListPlugins401", ListPlugins401),
orElse: unexpectedStatus
}))
),
"registerPlugin": (id, options) => HttpClientRequest.put(`/api/v1/plugins/${id}`).pipe(
HttpClientRequest.bodyJsonUnsafe(options.payload),
withResponse(options.config)(HttpClientResponse.matchStatus({
"400": decodeError("RegisterPlugin400", RegisterPlugin400),
"401": decodeError("RegisterPlugin401", RegisterPlugin401),
"204": () => Effect.void,
orElse: unexpectedStatus
}))
),
"deregisterPlugin": (id, options) => HttpClientRequest.delete(`/api/v1/plugins/${id}`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"401": decodeError("DeregisterPlugin401", DeregisterPlugin401),
"204": () => Effect.void,
orElse: unexpectedStatus
}))
),
"getPluginUiCredential": (id, options) => HttpClientRequest.get(`/api/v1/plugins/${id}/ui-credential`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(GetPluginUiCredential200),
"401": decodeError("GetPluginUiCredential401", GetPluginUiCredential401),
"404": decodeError("GetPluginUiCredential404", GetPluginUiCredential404),
orElse: unexpectedStatus
}))
),
"stopSession": (options) => HttpClientRequest.delete(`/api/v1/session`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"401": decodeError("StopSession401", StopSession401),
"204": () => Effect.void,
orElse: unexpectedStatus
}))
),
"requestIdr": (options) => HttpClientRequest.post(`/api/v1/session/idr`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"401": decodeError("RequestIdr401", RequestIdr401),
"409": decodeError("RequestIdr409", RequestIdr409),
"202": () => Effect.void,
orElse: unexpectedStatus
}))
),
"statsCaptureLive": (options) => HttpClientRequest.get(`/api/v1/stats/capture/live`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(StatsCaptureLive200),
"401": decodeError("StatsCaptureLive401", StatsCaptureLive401),
"404": decodeError("StatsCaptureLive404", StatsCaptureLive404),
orElse: unexpectedStatus
}))
),
"statsCaptureStart": (options) => HttpClientRequest.post(`/api/v1/stats/capture/start`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(StatsCaptureStart200),
"401": decodeError("StatsCaptureStart401", StatsCaptureStart401),
orElse: unexpectedStatus
}))
),
"statsCaptureStatus": (options) => HttpClientRequest.get(`/api/v1/stats/capture/status`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(StatsCaptureStatus200),
"401": decodeError("StatsCaptureStatus401", StatsCaptureStatus401),
orElse: unexpectedStatus
}))
),
"statsCaptureStop": (options) => HttpClientRequest.post(`/api/v1/stats/capture/stop`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(StatsCaptureStop200),
"401": decodeError("StatsCaptureStop401", StatsCaptureStop401),
"500": decodeError("StatsCaptureStop500", StatsCaptureStop500),
"204": () => Effect.void,
orElse: unexpectedStatus
}))
),
"statsRecordingsList": (options) => HttpClientRequest.get(`/api/v1/stats/recordings`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(StatsRecordingsList200),
"401": decodeError("StatsRecordingsList401", StatsRecordingsList401),
orElse: unexpectedStatus
}))
),
"statsRecordingGet": (id, options) => HttpClientRequest.get(`/api/v1/stats/recordings/${id}`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(StatsRecordingGet200),
"401": decodeError("StatsRecordingGet401", StatsRecordingGet401),
"404": decodeError("StatsRecordingGet404", StatsRecordingGet404),
"500": decodeError("StatsRecordingGet500", StatsRecordingGet500),
orElse: unexpectedStatus
}))
),
"statsRecordingDelete": (id, options) => HttpClientRequest.delete(`/api/v1/stats/recordings/${id}`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"401": decodeError("StatsRecordingDelete401", StatsRecordingDelete401),
"404": decodeError("StatsRecordingDelete404", StatsRecordingDelete404),
"500": decodeError("StatsRecordingDelete500", StatsRecordingDelete500),
"204": () => Effect.void,
orElse: unexpectedStatus
}))
),
"getStatus": (options) => HttpClientRequest.get(`/api/v1/status`).pipe(
withResponse(options?.config)(HttpClientResponse.matchStatus({
"2xx": decodeSuccess(GetStatus200),
"401": decodeError("GetStatus401", GetStatus401),
orElse: unexpectedStatus
}))
)
}
}
export interface Punktfunk {
readonly httpClient: HttpClient.HttpClient
/**
* List paired clients
*/
readonly "listPairedClients": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof ListPairedClients200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"ListPairedClients401", typeof ListPairedClients401.Type>>
/**
* Removes the client's certificate from the pairing store. Caveat: the nvhttp TLS layer
* does not yet reject unlisted certificates (`gamestream/tls.rs` accepts any well-formed
* client cert — a planned hardening step), so until that lands this removes the client
* from the listing without severing its ability to reconnect.
*/
readonly "unpairClient": <Config extends OperationConfig>(fingerprint: string, options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<void, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"UnpairClient400", typeof UnpairClient400.Type> | PunktfunkError<"UnpairClient401", typeof UnpairClient401.Type> | PunktfunkError<"UnpairClient404", typeof UnpairClient404.Type>>
/**
* Lists every backend the host knows how to drive, flags which are usable right now, and marks
* the one an unspecified (`Auto`) client request resolves to. Clients pass an `id` to their
* `--compositor` flag (or `PUNKTFUNK_COMPOSITOR_*` over the C ABI) to request it.
*/
readonly "listCompositors": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof ListCompositors200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"ListCompositors401", typeof ListCompositors401.Type>>
/**
* Set the **manual** desktop arrangement — per-identity-slot `(x, y)` offsets so a multi-monitor
* group (§6A/§6B) comes back where the operator placed it. Persisted into the policy's layout block
* and switched to manual mode; applied from the next connect (a live group re-applies on its next
* acquire). Locks in the current effective behavior as explicit fields, so arranging displays never
* silently changes keep-alive/topology/conflict/identity. See `design/display-management.md` §6.2.
*/
readonly "setDisplayLayout": <Config extends OperationConfig>(options: { readonly payload: typeof SetDisplayLayoutRequestJson.Encoded; readonly config?: Config | undefined }) => Effect.Effect<WithOptionalResponse<typeof SetDisplayLayout200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"SetDisplayLayout401", typeof SetDisplayLayout401.Type> | PunktfunkError<"SetDisplayLayout500", typeof SetDisplayLayout500.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.
*/
readonly "listCustomPresets": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof ListCustomPresets200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"ListCustomPresets401", typeof ListCustomPresets401.Type>>
/**
* Stores a named bundle of the display-behavior axes (+ the game-session axis) the operator can
* apply later. The host assigns a stable id, returned in the body. Applying a preset is a
* `PUT /display/settings` with a `Custom` policy carrying its `fields` — no separate apply route.
*/
readonly "createCustomPreset": <Config extends OperationConfig>(options: { readonly payload: typeof CreateCustomPresetRequestJson.Encoded; readonly config?: Config | undefined }) => Effect.Effect<WithOptionalResponse<typeof CreateCustomPreset201.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"CreateCustomPreset400", typeof CreateCustomPreset400.Type> | PunktfunkError<"CreateCustomPreset401", typeof CreateCustomPreset401.Type> | PunktfunkError<"CreateCustomPreset500", typeof CreateCustomPreset500.Type>>
/**
* Update a custom preset
*/
readonly "updateCustomPreset": <Config extends OperationConfig>(id: string, options: { readonly payload: typeof UpdateCustomPresetRequestJson.Encoded; readonly config?: Config | undefined }) => Effect.Effect<WithOptionalResponse<typeof UpdateCustomPreset200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"UpdateCustomPreset400", typeof UpdateCustomPreset400.Type> | PunktfunkError<"UpdateCustomPreset401", typeof UpdateCustomPreset401.Type> | PunktfunkError<"UpdateCustomPreset404", typeof UpdateCustomPreset404.Type> | PunktfunkError<"UpdateCustomPreset500", typeof UpdateCustomPreset500.Type>>
/**
* Removes it from the catalog. The active policy is untouched — if this preset was the one applied,
* the running behavior stays exactly as it was (the catalog and `display-settings.json` are decoupled).
*/
readonly "deleteCustomPreset": <Config extends OperationConfig>(id: string, options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<void, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"DeleteCustomPreset401", typeof DeleteCustomPreset401.Type> | PunktfunkError<"DeleteCustomPreset404", typeof DeleteCustomPreset404.Type> | PunktfunkError<"DeleteCustomPreset500", typeof DeleteCustomPreset500.Type>>
/**
* Tear down lingering/pinned displays now — so a physical-screen user gets their screen back
* without waiting out the linger. `slot` releases one; omit it to release all kept displays.
* Active (streaming) displays are never torn down here (that is session control).
*/
readonly "releaseDisplay": <Config extends OperationConfig>(options: { readonly payload: typeof ReleaseDisplayRequestJson.Encoded; readonly config?: Config | undefined }) => Effect.Effect<WithOptionalResponse<typeof ReleaseDisplay200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"ReleaseDisplay401", typeof ReleaseDisplay401.Type>>
/**
* The stored virtual-display policy (lifecycle, topology, conflict handling, identity, layout),
* every preset's expansion, and which options this build enforces yet. See
* `design/display-management.md`.
*/
readonly "getDisplaySettings": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof GetDisplaySettings200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"GetDisplaySettings401", typeof GetDisplaySettings401.Type>>
/**
* Persists a new policy (validated + clamped) and applies it from the next connect/teardown — a
* running session keeps the display it opened on. `keep_alive: forever` (the gaming-rig preset) is
* honored (the display is Pinned; free it via `POST /display/release`).
*/
readonly "setDisplaySettings": <Config extends OperationConfig>(options: { readonly payload: typeof SetDisplaySettingsRequestJson.Encoded; readonly config?: Config | undefined }) => Effect.Effect<WithOptionalResponse<typeof SetDisplaySettings200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"SetDisplaySettings400", typeof SetDisplaySettings400.Type> | PunktfunkError<"SetDisplaySettings401", typeof SetDisplaySettings401.Type> | PunktfunkError<"SetDisplaySettings500", typeof SetDisplaySettings500.Type>>
/**
* The host's managed virtual displays right now — active (streaming), lingering (kept after
* disconnect, counting down to teardown), or pinned (kept indefinitely). See
* `design/display-management.md`.
*/
readonly "getDisplayState": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof GetDisplayState200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"GetDisplayState401", typeof GetDisplayState401.Type>>
/**
* Server-Sent Events stream of the host's lifecycle events: client connect/disconnect, session
* and stream start/end, pairing decisions, display create/release, library changes, host
* start/stop — both protocol planes. Frames carry `id:` = the event's monotonic `seq`,
* `event:` = its kind, and `data:` = the event JSON (schema-versioned, additive-only).
*
* Resume: standard `Last-Event-ID` (or `?since=`) replays from the in-memory ring; a consumer
* that fell off the ring receives an `event: dropped` frame first and should resync via the
* REST snapshots. Keep-alive comments are sent every 15 s.
*/
readonly "streamEvents": <Config extends OperationConfig>(options: { readonly params?: typeof StreamEventsParams.Encoded | undefined; readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<void, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"StreamEvents401", typeof StreamEvents401.Type> | PunktfunkError<"StreamEvents503", typeof StreamEvents503.Type>>
/**
* Server-Sent Events stream of the host's lifecycle events: client connect/disconnect, session
* and stream start/end, pairing decisions, display create/release, library changes, host
* start/stop — both protocol planes. Frames carry `id:` = the event's monotonic `seq`,
* `event:` = its kind, and `data:` = the event JSON (schema-versioned, additive-only).
*
* Resume: standard `Last-Event-ID` (or `?since=`) replays from the in-memory ring; a consumer
* that fell off the ring receives an `event: dropped` frame first and should resync via the
* REST snapshots. Keep-alive comments are sent every 15 s.
*/
readonly "streamEventsSse": (options: { readonly params?: typeof StreamEventsParams.Encoded | undefined } | undefined) => Stream.Stream<{ readonly event: string; readonly id: string | undefined; readonly data: typeof StreamEvents200Sse.Type }, HttpClientError.HttpClientError | SchemaError | Sse.Retry, typeof StreamEvents200Sse.DecodingServices>
/**
* Lists the host's hardware GPUs, the persisted auto/manual preference, the GPU the next session
* will use (and why), and the GPU live sessions encode on right now.
*/
readonly "listGpus": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof ListGpus200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"ListGpus401", typeof ListGpus401.Type>>
/**
* `auto` restores automatic selection (`PUNKTFUNK_RENDER_ADAPTER` pin, else max dedicated VRAM);
* `manual` pins capture + encode to the given GPU. Persisted across restarts; applies to the
* **next** session (a running session keeps its GPU). If the preferred GPU is absent at session
* start the host falls back to automatic selection rather than failing.
*/
readonly "setGpuPreference": <Config extends OperationConfig>(options: { readonly payload: typeof SetGpuPreferenceRequestJson.Encoded; readonly config?: Config | undefined }) => Effect.Effect<WithOptionalResponse<typeof SetGpuPreference200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"SetGpuPreference400", typeof SetGpuPreference400.Type> | PunktfunkError<"SetGpuPreference401", typeof SetGpuPreference401.Type> | PunktfunkError<"SetGpuPreference500", typeof SetGpuPreference500.Type>>
/**
* Always available without authentication.
*/
readonly "getHealth": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof GetHealth200.Type, Config>, HttpClientError.HttpClientError | SchemaError>
/**
* The operator's `hooks.json`: commands and webhooks fired on host lifecycle events. Empty
* when unconfigured.
*/
readonly "getHooks": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof GetHooks200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"GetHooks401", typeof GetHooks401.Type>>
/**
* Validates and persists a full `hooks.json` document (this is a whole-document PUT, not a
* patch). Applies from the next event — no restart. Hook commands run as the host user
* (interactive user session on Windows): treat this configuration as operator-privileged.
*/
readonly "setHooks": <Config extends OperationConfig>(options: { readonly payload: typeof SetHooksRequestJson.Encoded; readonly config?: Config | undefined }) => Effect.Effect<WithOptionalResponse<typeof SetHooks200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"SetHooks400", typeof SetHooks400.Type> | PunktfunkError<"SetHooks401", typeof SetHooks401.Type> | PunktfunkError<"SetHooks500", typeof SetHooks500.Type>>
/**
* Host identity and capabilities
*/
readonly "getHostInfo": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof GetHostInfo200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"GetHostInfo401", typeof GetHostInfo401.Type>>
/**
* Every installed-store title (Steam, read from the host's local files — no Steam API key)
* merged with the user's custom entries, sorted by title. Artwork fields are URLs the client
* fetches directly (the public Steam CDN for Steam titles). `?provider=` narrows to the
* entries a given external provider owns.
*/
readonly "getLibrary": <Config extends OperationConfig>(options: { readonly params?: typeof GetLibraryParams.Encoded | undefined; readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof GetLibrary200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"GetLibrary401", typeof GetLibrary401.Type>>
/**
* Resolves `kind` (`portrait` | `hero` | `logo` | `header`) for the given library id and streams
* the image bytes. For a Steam title, the host's own local Steam cache is tried first (exact —
* it's what the user's Steam client already shows for it), the public Steam CDN's flat URL
* convention as a fallback (newer titles' CDN assets can live at a per-asset-hash path the host
* can't predict, in which case this 404s and the client falls through to its next art candidate).
* Only Steam ids are backed today; any other store 404s.
*/
readonly "getLibraryArt": <Config extends OperationConfig>(id: string, kind: string, options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<void, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"GetLibraryArt401", typeof GetLibraryArt401.Type> | PunktfunkError<"GetLibraryArt404", typeof GetLibraryArt404.Type>>
/**
* Creates a user-curated title (e.g. a non-Steam game, an emulator, a ROM) with caller-supplied
* artwork URLs. The host assigns a stable id, returned in the body.
*/
readonly "createCustomGame": <Config extends OperationConfig>(options: { readonly payload: typeof CreateCustomGameRequestJson.Encoded; readonly config?: Config | undefined }) => Effect.Effect<WithOptionalResponse<typeof CreateCustomGame201.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"CreateCustomGame400", typeof CreateCustomGame400.Type> | PunktfunkError<"CreateCustomGame401", typeof CreateCustomGame401.Type> | PunktfunkError<"CreateCustomGame500", typeof CreateCustomGame500.Type>>
/**
* Update a custom library entry
*/
readonly "updateCustomGame": <Config extends OperationConfig>(id: string, options: { readonly payload: typeof UpdateCustomGameRequestJson.Encoded; readonly config?: Config | undefined }) => Effect.Effect<WithOptionalResponse<typeof UpdateCustomGame200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"UpdateCustomGame400", typeof UpdateCustomGame400.Type> | PunktfunkError<"UpdateCustomGame401", typeof UpdateCustomGame401.Type> | PunktfunkError<"UpdateCustomGame404", typeof UpdateCustomGame404.Type> | PunktfunkError<"UpdateCustomGame500", typeof UpdateCustomGame500.Type>>
/**
* Delete a custom library entry
*/
readonly "deleteCustomGame": <Config extends OperationConfig>(id: string, options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<void, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"DeleteCustomGame401", typeof DeleteCustomGame401.Type> | PunktfunkError<"DeleteCustomGame404", typeof DeleteCustomGame404.Type> | PunktfunkError<"DeleteCustomGame500", typeof DeleteCustomGame500.Type>>
/**
* Atomically replaces the full entry set owned by `{provider}` (RFC §8): the payload is the
* provider's desired list, keyed by its own stable `external_id` — the host diffs, keeps each
* surviving title's host id stable across reconciles, drops orphans, and never touches manual
* entries or other providers'. An empty array removes everything the provider owns. Emits
* `library.changed` with the provider as `source`.
*/
readonly "reconcileProviderEntries": <Config extends OperationConfig>(provider: string, options: { readonly payload: typeof ReconcileProviderEntriesRequestJson.Encoded; readonly config?: Config | undefined }) => Effect.Effect<WithOptionalResponse<typeof ReconcileProviderEntries200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"ReconcileProviderEntries400", typeof ReconcileProviderEntries400.Type> | PunktfunkError<"ReconcileProviderEntries401", typeof ReconcileProviderEntries401.Type> | PunktfunkError<"ReconcileProviderEntries500", typeof ReconcileProviderEntries500.Type>>
/**
* Deletes every entry owned by `{provider}` — the clean-uninstall path for a provider plugin
* (RFC §8). Emits `library.changed` when anything was removed.
*/
readonly "deleteProviderEntries": <Config extends OperationConfig>(provider: string, options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof DeleteProviderEntries200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"DeleteProviderEntries400", typeof DeleteProviderEntries400.Type> | PunktfunkError<"DeleteProviderEntries401", typeof DeleteProviderEntries401.Type> | PunktfunkError<"DeleteProviderEntries500", typeof DeleteProviderEntries500.Type>>
/**
* Non-sensitive status (counts and booleans only — no PIN values, no fingerprints, no device
* names). Unauthenticated, but served to loopback peers only.
*/
readonly "getLocalSummary": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof GetLocalSummary200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"GetLocalSummary401", typeof GetLocalSummary401.Type>>
/**
* The host's recent log entries — an in-memory ring of the newest few thousand, captured at
* DEBUG and above regardless of `RUST_LOG`. Follow live by polling with `after` set to the last
* response's `next` cursor; a `dropped: true` means entries were evicted between polls (the ring
* wrapped). Bearer-only: logs can reference client identities and host paths, so this is part of
* the loopback-only admin surface, never the LAN-readable mTLS one.
*/
readonly "logsGet": <Config extends OperationConfig>(options: { readonly params?: typeof LogsGetParams.Encoded | undefined; readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof LogsGet200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"LogsGet401", typeof LogsGet401.Type>>
/**
* List native paired clients
*/
readonly "listNativeClients": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof ListNativeClients200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"ListNativeClients401", typeof ListNativeClients401.Type>>
/**
* Removes a punktfunk/1 client from the native trust store by fingerprint.
*/
readonly "unpairNativeClient": <Config extends OperationConfig>(fingerprint: string, options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<void, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"UnpairNativeClient401", typeof UnpairNativeClient401.Type> | PunktfunkError<"UnpairNativeClient404", typeof UnpairNativeClient404.Type> | PunktfunkError<"UnpairNativeClient503", typeof UnpairNativeClient503.Type>>
/**
* The native (punktfunk/1) pairing window. Poll while armed to show the PIN + countdown.
* `enabled: false` means this host runs GameStream only (no `--native`).
*/
readonly "getNativePairing": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof GetNativePairing200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"GetNativePairing401", typeof GetNativePairing401.Type>>
/**
* Closes the pairing window immediately (no new ceremonies accepted).
*/
readonly "disarmNativePairing": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<void, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"DisarmNativePairing401", typeof DisarmNativePairing401.Type> | PunktfunkError<"DisarmNativePairing503", typeof DisarmNativePairing503.Type>>
/**
* Opens a pairing window and mints a fresh PIN to display. The user enters it on their device
* within `ttl_secs`; the device then appears in the native client list.
*/
readonly "armNativePairing": <Config extends OperationConfig>(options: { readonly payload: typeof ArmNativePairingRequestJson.Encoded; readonly config?: Config | undefined }) => Effect.Effect<WithOptionalResponse<typeof ArmNativePairing200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"ArmNativePairing401", typeof ArmNativePairing401.Type> | PunktfunkError<"ArmNativePairing503", typeof ArmNativePairing503.Type>>
/**
* Unpaired devices that tried to connect while the host requires pairing. Approve one to pair
* it without a PIN (delegated approval); entries expire after ~10 minutes.
*/
readonly "listPendingDevices": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof ListPendingDevices200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"ListPendingDevices401", typeof ListPendingDevices401.Type>>
/**
* Pairs the device's certificate fingerprint — it can connect immediately (no PIN). Optionally
* relabel it via the body; send `{}` to keep the name it knocked with.
*/
readonly "approvePendingDevice": <Config extends OperationConfig>(id: string, options: { readonly payload: typeof ApprovePendingDeviceRequestJson.Encoded; readonly config?: Config | undefined }) => Effect.Effect<WithOptionalResponse<typeof ApprovePendingDevice200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"ApprovePendingDevice401", typeof ApprovePendingDevice401.Type> | PunktfunkError<"ApprovePendingDevice404", typeof ApprovePendingDevice404.Type> | PunktfunkError<"ApprovePendingDevice500", typeof ApprovePendingDevice500.Type> | PunktfunkError<"ApprovePendingDevice503", typeof ApprovePendingDevice503.Type>>
/**
* Drops the request. Not a blocklist — the device's next attempt knocks again.
*/
readonly "denyPendingDevice": <Config extends OperationConfig>(id: string, options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<void, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"DenyPendingDevice401", typeof DenyPendingDevice401.Type> | PunktfunkError<"DenyPendingDevice404", typeof DenyPendingDevice404.Type> | PunktfunkError<"DenyPendingDevice503", typeof DenyPendingDevice503.Type>>
/**
* Poll this to know when to prompt the user for the PIN Moonlight displays.
*/
readonly "getPairingStatus": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof GetPairingStatus200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"GetPairingStatus401", typeof GetPairingStatus401.Type>>
/**
* Delivers the PIN the Moonlight client is displaying, completing the out-of-band half
* of the pairing handshake.
*/
readonly "submitPairingPin": <Config extends OperationConfig>(options: { readonly payload: typeof SubmitPairingPinRequestJson.Encoded; readonly config?: Config | undefined }) => Effect.Effect<WithOptionalResponse<void, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"SubmitPairingPin400", typeof SubmitPairingPin400.Type> | PunktfunkError<"SubmitPairingPin401", typeof SubmitPairingPin401.Type> | PunktfunkError<"SubmitPairingPin409", typeof SubmitPairingPin409.Type> | PunktfunkError<"SubmitPairingPin415", typeof SubmitPairingPin415.Type> | PunktfunkError<"SubmitPairingPin422", typeof SubmitPairingPin422.Type>>
/**
* The live plugin directory (lease not expired), sorted by title. **Secret-free**: each entry
* reports its id, title, optional version, and — for plugins that serve one — a UI descriptor
* (loopback port + icon). The console renders these as nav entries and proxies to the port; it
* fetches the secret separately, server-side.
*/
readonly "listPlugins": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof ListPlugins200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"ListPlugins401", typeof ListPlugins401.Type>>
/**
* Upserts the plugin's directory entry and renews its lease (TTL 90 s). Idempotent: a plugin PUTs
* this every ~30 s while it runs. The optional `ui` block declares a loopback UI surface the console
* will proxy and add to its nav. Emits `plugins.changed` when an operator-visible field changed
* (first registration, restart, or re-scan) — a pure renewal is silent.
*/
readonly "registerPlugin": <Config extends OperationConfig>(id: string, options: { readonly payload: typeof RegisterPluginRequestJson.Encoded; readonly config?: Config | undefined }) => Effect.Effect<WithOptionalResponse<void, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"RegisterPlugin400", typeof RegisterPlugin400.Type> | PunktfunkError<"RegisterPlugin401", typeof RegisterPlugin401.Type>>
/**
* The clean-shutdown path: removes the plugin's directory entry immediately (the SDK helper calls
* this from its scope finalizer on `SIGTERM`). Emits `plugins.changed` when a live entry was
* removed. Idempotent — deleting an unknown/expired id is a no-op `204`.
*/
readonly "deregisterPlugin": <Config extends OperationConfig>(id: string, options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<void, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"DeregisterPlugin401", typeof DeregisterPlugin401.Type>>
/**
* Returns `{port, secret}` for a live plugin's loopback UI — the console proxy's server-side lookup.
* Bearer + loopback only (like every mutation), and additionally excluded from the console's browser
* passthrough: the secret never reaches a browser.
*/
readonly "getPluginUiCredential": <Config extends OperationConfig>(id: string, options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof GetPluginUiCredential200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"GetPluginUiCredential401", typeof GetPluginUiCredential401.Type> | PunktfunkError<"GetPluginUiCredential404", typeof GetPluginUiCredential404.Type>>
/**
* Kicks the connected client: stops the video/audio stream threads and clears the launch
* state. Idempotent — succeeds even when nothing is streaming.
*/
readonly "stopSession": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<void, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"StopSession401", typeof StopSession401.Type>>
/**
* Asks the encoder for an IDR frame on the active video stream (what a client requests
* after unrecoverable loss — exposed for debugging).
*/
readonly "requestIdr": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<void, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"RequestIdr401", typeof RequestIdr401.Type> | PunktfunkError<"RequestIdr409", typeof RequestIdr409.Type>>
/**
* The full sample time-series of the capture currently recording, for live graphing. `404` when
* nothing is armed.
*/
readonly "statsCaptureLive": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof StatsCaptureLive200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"StatsCaptureLive401", typeof StatsCaptureLive401.Type> | PunktfunkError<"StatsCaptureLive404", typeof StatsCaptureLive404.Type>>
/**
* Arms a new performance-stats capture. Idempotent: if a capture is already running this returns
* the current status unchanged. While armed, the streaming loops emit aggregated samples (~ every
* 12 s) into the in-progress capture, readable live via `GET /stats/capture/live`.
*/
readonly "statsCaptureStart": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof StatsCaptureStart200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"StatsCaptureStart401", typeof StatsCaptureStart401.Type>>
/**
* Whether a capture is armed, its sample count, and start time. Poll this (e.g. every 2 s) to
* drive the capture-control UI.
*/
readonly "statsCaptureStatus": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof StatsCaptureStatus200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"StatsCaptureStatus401", typeof StatsCaptureStatus401.Type>>
/**
* Disarms the in-progress capture and writes it to disk atomically, returning its summary. If
* nothing was recording, returns `204 No Content`.
*/
readonly "statsCaptureStop": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof StatsCaptureStop200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"StatsCaptureStop401", typeof StatsCaptureStop401.Type> | PunktfunkError<"StatsCaptureStop500", typeof StatsCaptureStop500.Type>>
/**
* Every saved capture's summary (the `meta` head only — not the sample body), newest first.
*/
readonly "statsRecordingsList": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof StatsRecordingsList200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"StatsRecordingsList401", typeof StatsRecordingsList401.Type>>
/**
* The full capture (meta + samples) for `id`, for graphing or download.
*/
readonly "statsRecordingGet": <Config extends OperationConfig>(id: string, options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof StatsRecordingGet200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"StatsRecordingGet401", typeof StatsRecordingGet401.Type> | PunktfunkError<"StatsRecordingGet404", typeof StatsRecordingGet404.Type> | PunktfunkError<"StatsRecordingGet500", typeof StatsRecordingGet500.Type>>
/**
* Removes the recording `id` from disk. `404` if there is no such recording.
*/
readonly "statsRecordingDelete": <Config extends OperationConfig>(id: string, options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<void, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"StatsRecordingDelete401", typeof StatsRecordingDelete401.Type> | PunktfunkError<"StatsRecordingDelete404", typeof StatsRecordingDelete404.Type> | PunktfunkError<"StatsRecordingDelete500", typeof StatsRecordingDelete500.Type>>
/**
* Live host status
*/
readonly "getStatus": <Config extends OperationConfig>(options: { readonly config?: Config | undefined } | undefined) => Effect.Effect<WithOptionalResponse<typeof GetStatus200.Type, Config>, HttpClientError.HttpClientError | SchemaError | PunktfunkError<"GetStatus401", typeof GetStatus401.Type>>
}
export interface PunktfunkError<Tag extends string, E> {
readonly _tag: Tag
readonly request: HttpClientRequest.HttpClientRequest
readonly response: HttpClientResponse.HttpClientResponse
readonly cause: E
}
class PunktfunkErrorImpl extends Data.Error<{
_tag: string
cause: any
request: HttpClientRequest.HttpClientRequest
response: HttpClientResponse.HttpClientResponse
}> {}
export const PunktfunkError = <Tag extends string, E>(
tag: Tag,
cause: E,
response: HttpClientResponse.HttpClientResponse,
): PunktfunkError<Tag, E> =>
new PunktfunkErrorImpl({
_tag: tag,
cause,
response,
request: response.request,
}) as any