""" Stripe-style version compatibility layer for browser-cli serve. When a behaviour-breaking change ships in a new server version, add one entry to _COMPAT below: ("X.Y.Z", request_fn, response_fn) - ``request_fn(msg: dict) -> dict`` Upgrade an incoming client message from a client older than X.Y.Z to the current format before forwarding it to the native host. - ``response_fn(resp: bytes, command: str) -> bytes`` Downgrade a native-host response to the format a client older than X.Y.Z expects before sending it back. Either function may be ``None`` when only one direction needs adapting. Entries must stay in ascending version order. ``adapt_request`` walks forward (oldest change first); ``adapt_response`` walks backward (newest change first) so the transformations compose correctly. Current baseline: 0.9.1 — no shims needed yet. """ from __future__ import annotations from typing import Callable from browser_cli.version_manager import parse_version _COMPAT: list[tuple[str, Callable[[dict], dict] | None, Callable[[bytes, str], bytes] | None]] = [ # ("1.0.0", _req_1_0_0, _resp_1_0_0), ] def adapt_request(msg: dict, client_version: str) -> dict: """Upgrade a client message to the current server format.""" cv = parse_version(client_version) for version, req_fn, _ in _COMPAT: if cv < parse_version(version) and req_fn is not None: msg = req_fn(msg) return msg def adapt_response(resp: bytes, command: str, client_version: str) -> bytes: """Downgrade a server response to the format the client expects.""" cv = parse_version(client_version) for version, _, resp_fn in reversed(_COMPAT): if cv < parse_version(version) and resp_fn is not None: resp = resp_fn(resp, command) return resp