Skip to content

Releases: mathisarends/canon

fastapi-streams 0.5.0

Choose a tag to compare

0.5.0 - 2026-10-25

Breaking changes

  • The client that a generated Python SDK creates when no http_client is
    passed now uses httpx.Timeout(None, connect=10.0) (also exported as
    runtime.DEFAULT_TIMEOUT) instead of timeout=None. Connecting to an
    unreachable host now fails with TransportError after 10 seconds instead of
    hanging; read, write and pool waits remain unbounded, so idle streams are
    unaffected. This changed default requires a minor release under the pre-1.0
    version policy. Migration: regenerate the SDK. To keep unbounded connects,
    pass RequestOptions(timeout=None) per request or inject your own client,
    for example Client(url, http_client=httpx.AsyncClient(timeout=None)).
    Injected clients and explicit RequestOptions.timeout values behave as
    before.

Added

  • Generated TypeScript clients accept RequestOptions.unknownEvents. The default
    "forward" keeps the current behavior; "ignore" skips JSON objects whose
    discriminator is a string tag the generated event union does not declare, so
    exhaustive switch statements survive additive server variants. Each
    generated operation now embeds its discriminator and known tags. Operations
    without a top-level discriminated union reject "ignore" with a TypeError
    before any request. Regenerate TypeScript SDKs to adopt the option.
  • --diff for schema --check, generate --check, check and sync --check
    prints a unified diff of each out-of-date file (including new and stale owned
    files and a changed application contract) to stdout, so CI logs and agents can
    see the drift without regenerating locally.
  • fastapi-streams sync reads [tool.fastapi-streams] (app, schema and
    [[tool.fastapi-streams.clients]] with language, output and the existing
    generation options) from pyproject.toml or --config, exports the schema and
    regenerates every client. sync --check reports all stale targets read-only.
    Unknown keys and invalid values are rejected with exit code 2.
  • fastapi_streams.codegen.writer.planned_files returns the files including the
    ownership manifest that write_files would write.

Performance

  • Generated Python and TypeScript runtimes split each decoded SSE chunk at line
    endings instead of iterating characters. With the repository benchmark,
    framing nested events is about 17x faster in Python and 4x faster in
    TypeScript; complete small/nested stream consumption is 2-4.7x faster. Long
    lines spanning many chunks are joined once. Framing semantics are unchanged:
    LF/CR/CRLF (also split across chunks), the leading BOM, multi-line data,
    comments and the end-of-stream frame behave as before. A randomized test
    compares both runtimes with the previous character parser. Regenerate SDKs to
    adopt the faster runtime.

Documentation

  • Point the README badge, example checkout and quickstart to the Canon workspace
    repository and its locked workspace commands. The documentation check now
    rejects links to the retired standalone repository.
  • Expand the package AGENTS.md with the module layout, focused test/codegen
    commands and the template-regeneration workflow.

fastapi-rpckit 0.4.1

Choose a tag to compare

0.4.1 - 2026-10-25

Performance

  • Validate each socket request envelope once. The reader's validated envelope is
    reused for dispatch and subscription handling instead of being validated again,
    which saves about 3 µs per request. Middleware still receives the original raw
    request, and error responses for invalid requests are unchanged. Wire output
    is unchanged; JSON encoding stays on the standard library because
    pydantic-core's serializer formats some floats differently.

Added

  • scripts/bench_rpc_requests.py measures sequential round-trip latency and
    pipelined request throughput over the in-process socket runtime. See
    Measure request throughput.

Documentation

  • Add a core-API overview to the README and use the workspace's locked root
    commands for development. Replace the stale version note with links to the
    changelog and the pyrpckit migration guide.
  • Refresh AGENTS.md: current module map, locked workspace commands and one
    consistent compatibility rule (preserve wire behavior and generated-client
    contracts; remove superseded Python APIs only through a breaking release).

fastapi-canon 0.8.1

Choose a tag to compare

0.8.1 - 2026-10-25

  • Update the optional Streams integration and development pin to 0.5.0 for the
    TypeScript unknownEvents option, --diff drift output, the config-driven
    fastapi-streams sync command and faster SSE line splitting in generated
    runtimes. Canon's public API and composition behavior remain unchanged; core
    imports continue to work without Streams, RPCkit or WebRTC.
  • Streams 0.5.0 changes the connect timeout of SDK-owned generated Python HTTP
    clients. Regenerate stream SDKs and follow the
    Streams 0.5.0 upgrade notes if a client
    relied on an unbounded connect time.

fastapi-canon 0.8.0

Choose a tag to compare

0.8.0 - 2026-10-25

Breaking changes

  • Extend the public constructor signatures with CanonRouter(policy=...) and
    Composition(router_policy=...). Update wrappers or signature snapshots that
    mirror those constructors. Existing calls without policies keep their behavior.
    To migrate a shared router helper, create a RouterPolicy containing its
    error_registry, dependencies, and shared raises, then instantiate
    CanonRouter(policy=...) explicitly. Keep route_class=DishkaRoute on the
    declaring router. Use Composition(router_policy=...) to extend contracts
    across included feature routers; ordinary parent raises= remains local.

Added

  • Export immutable RouterPolicy for reusable HTTP prerequisites and their error
    contracts. Combine policy, router and operation declarations with the existing
    registry collision checks and identity-based error deduplication.
  • Apply composition policies to nested HTTP/SSE operations without mutating
    reusable feature routers or walking FastAPI's internal route tree. Preserve
    FastAPI dependency behavior, combine same-status Problem schemas, and reject
    manual response collisions before installing the composition.
  • Optional python -m fastapi_canon.check_error_contracts source checker for
    explicit application exceptions missing from direct CanonRouter error
    contracts. It follows typed services, helpers and FastAPI dependencies,
    accounts for supported exception handling and inheritance, and reports
    unresolved paths as incomplete analysis. Warning output is the default;
    strict CI modes and JSON reports are opt-in.
  • Reuse source-checker function summaries and inheritance results within each
    invocation, preserving error paths and incomplete-analysis diagnostics. Add a
    reproducible benchmark for source-processing and full-command timings.

Fixed

  • Mark annotated module reassignments as incomplete source analysis, preventing
    later declarations from hiding a missing route error contract or creating a
    false gap for an already registered contract.
  • Report expanded ErrorRegistry(**config) arguments as incomplete instead of
    treating an unresolved catalog as empty and reporting missing error mappings.

fastapi-webrtc 0.3.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 08:51
6aad274

0.3.0 - 2026-10-24

Breaking changes

  • Replace the engine's MediaKind, SignalingState, ConnectionState,
    TransceiverDirection and ChannelState literal aliases with public StrEnum
    classes, also exported from fastapi_webrtc. Use members such as
    MediaKind.AUDIO and ConnectionState.CONNECTED in engine implementations,
    callbacks, stats and codec-preference maps. Convert native strings with the
    corresponding enum constructor; aiortc does this at its adapter boundary.
    Values and string/JSON serialization stay unchanged.
  • Make EngineCapabilities keyword-only. Replace positional flags with
    EngineCapabilities(trickle_ice=..., ice_restart=..., renegotiation=...);
    negotiated_data_channels still defaults to True.
  • Make ChannelParameters options after label keyword-only. For example,
    replace ChannelParameters("chat", False) with
    ChannelParameters("chat", ordered=False).
  • Replace MessageFormat and SessionEventKind literal aliases with public
    StrEnum classes, also exported from fastapi_webrtc. Use members such as
    MessageFormat.JSON and SessionEventKind.TRACK when constructing descriptors
    and events. Signaling descriptors reuse Direction, Role and MessageFormat;
    parsed SDP sections expose TransceiverDirection. JSON values stay unchanged.
  • Use the public DescriptionType enum for SessionDescription.type and signaling
    payloads. Replace SessionDescription("offer", sdp) with
    SessionDescription(DescriptionType.OFFER, sdp) (likewise for ANSWER).
    The aiortc adapter converts native description types directly instead of
    treating any non-offer value as an answer.
  • Declare remaining type aliases with Python 3.12's type syntax. These exported
    names are typing.TypeAliasType instances; introspection tools must handle
    their lazy __value__ instead of expecting a runtime union or Callable.
    SessionEvent.media_kind now uses MediaKind too.

fastapi-canon 0.7.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 08:56
6aad274

0.7.0 - 2026-10-24

Breaking changes

  • Pin the optional fastapi-canon[webrtc] integration to WebRTC 0.3.0. Custom
    engines must use its public StrEnum types and keyword-only engine/channel
    options; follow the
    WebRTC migration notes.
    Canon core and the Streams integration keep their existing behavior.

fastapi-webrtc 0.2.0

Choose a tag to compare

0.2.0 - 2026-10-20

Breaking changes

  • Generated runtimes export observeVideoHealth and its types. Regenerate clients
    and rename any colliding session/client declarations reported by code generation.
    Existing connect() readiness semantics are unchanged.
  • Add Session.engine and allow a router without a default engine when factories
    bind one per session. Custom constructor overrides should accept an optional
    engine. Supply either a router engine or a session engine; missing bindings are
    refused with handler_failure and returned tracks are cleaned up.
  • Extend WebRtcRouter.session() and SessionDeclaration with the optional
    admission_errors contract-provider hook. Custom router overrides must accept
    and forward this keyword. Regenerate clients to include declared admission
    metadata in session descriptors. The signaling protocol remains v1.

Added

  • Optional browser video health observation with separate opt-in first-frame and
    ongoing-stall deadlines, recovery events, per-track decoded stats and optional
    compositor frame callbacks. Abort, session close and stop() release observers;
    observation never closes sessions, stops tracks or chooses a fallback UI.
  • A tested remote send-only adapter example with per-viewer async-context-manager
    leases, explicit unsupported operations and partial statistics. Categorized
    WebRtcError failures during peer creation retain their stable protocol code.
  • Canon-independent admission contract export, including optional generated
    descriptor metadata. HTTP denials remain distinct from accepted-session errors;
    this metadata does not expose failed WebSocket handshake bodies in browsers.
  • An optional HTTP admission ticket recipe for readable
    denials before signaling, with application-owned authorization and atomic ticket
    consumption. It does not reserve remote viewer capacity automatically.

fastapi-webrtc 0.1.0

Choose a tag to compare

@github-actions github-actions released this 20 Oct 07:29
0e1dec2

0.1.0 - 2026-10-20

Initial release.

  • WebRtcRouter.session() declares WebRTC sessions as WebSocket signaling
    endpoints. FastAPI dependencies admit sessions before any peer is created and
    stay open until cleanup finished, also when the server cancels the endpoint.
  • Session handlers: on_start, run, on_track, typed on_message,
    on_close and outgoing tracks. Peer sends messages and tracks with
    renegotiation, and exposes stats and close codes. Stats report jitter as
    None when the engine cannot convert it to seconds (aiortc). on_close runs
    once per accepted session and keeps at least one second even when cancelled
    handlers used up shutdown_timeout_seconds.
  • Track ownership: session tracks and send_track(track) are stopped on removal
    or cleanup, including rejected and partially started sessions;
    send_track(track, owned=False) keeps shared sources running behind a
    sender-local forwarding track. Only active
    incoming tracks count against MediaPolicy.max_incoming_tracks.
  • Typed data channels from Pydantic models, str or bytes. JSON messages use
    the contract's serialization aliases. Channels support negotiated IDs,
    validated keyword-only reliability options, size limits, bounded inbound
    queues and send backpressure. A DataChannelSpec is generic over its message
    types: on_message accepts specs as keys, and peer.channel(spec) and
    peer.send_message(spec, ...) are type-checked against its models.
    Never as receive_model or send_model declares a one-way channel
    (format none); the generated client omits send or subscribe for it.
  • Signaling protocol fastapi-webrtc.v1. It uses perfect negotiation,
    candidate buffering, ICE username checks, categorized close codes and
    negotiation, media and transport deadlines. Negotiation timeouts and shutdown
    cancel blocked ICE and engine startup.
  • ICE server providers, TurnRestCredentials with separate engine URLs and
    session event hooks.
  • WebRtcRouter(allowed_origins=...) refuses cross-site browser handshakes with
    HTTP 403 before the session factory runs.
  • A pluggable Engine protocol, with an aiortc reference engine behind the
    aiortc extra.
  • Tested Canon/Dishka composition with explicit async-factory injection,
    session services, per-message request scopes and ordered cleanup.
  • fastapi-webrtc contract and fastapi-webrtc generate export a session
    contract and generate a dependency-free TypeScript browser client with typed
    parameters, channels and errors. Query models become flat named parameters.
    Ambiguous generated names fail before files are written. Both commands support
    --check drift detection.
  • The browser client merges query values from the base URL, shared credential
    providers, per-call maps and named parameters, in that order; null removes
    a value. timeoutMs bounds credential resolution and connection setup;
    signal cancels the whole session. Renegotiation
    and channel sends (sendTimeoutMs) have deadlines after connect, and
    permanent transport failure rejects pending operations.

fastapi-rpckit 0.4.0

Choose a tag to compare

0.4.0 - 2026-10-20

Breaking changes

  • Generated WebSocketFactory, SocketConnectionFactory and
    BinaryWebSocketFactory protocols accept their URL as a positional-only
    argument. Regenerate Python clients and pass the URL positionally when invoking
    these factories. This matches the existing generated runtime calls and permits
    custom factories with differently named first parameters. Custom factories
    with named first parameters continue to work.
  • serve_websocket() propagates caller task cancellation after endpoint cleanup.
    Direct callers that cancel and await this helper must handle CancelledError.

Fixed

  • Preserve the original ASGI cancellation while awaiting endpoint cleanup. This
    prevents teardown stalls with minimum AnyIO and Starlette versions and avoids
    leaking child-task cancellations through current Starlette TestClient sessions.
  • The generated default connectors adapt websockets' nominal Subprotocol type
    inside their lazy backend boundary. Factory protocols remain independent of
    websockets; consumers no longer need generator overrides for this mismatch.

fastapi-rpckit 0.3.0

Choose a tag to compare

@github-actions github-actions released this 20 Oct 07:33
0e1dec2

0.3.0 - 2026-10-20

Breaking changes

  • Remove server-to-client RPC. Every RPC method is now implemented by the
    server and called by the client. channel.client.method(), RpcClientMethod,
    RpcConnectedClient, the RpcClientMethod*Error exceptions,
    RpcClientClosedError, RpcProtocol.client_methods,
    RpcLimits.client_method_timeout and RpcTestClient(client_methods=...) /
    RpcTestClient.handle() are gone.
  • Remove channel.server. Declare operations directly on the channel with
    @channel.method(), @channel.event(), @channel.subscription(),
    @channel.stream() and @channel.socket(). These were already the
    default spelling; channel.server.X was an alias.
  • OpenRPC documents no longer contain x-rpc-client-methods or
    *ClientMethod request schemas, and the generators reject documents that
    still declare x-rpc-client-methods.
  • Generated Python clients no longer contain handlers.py,
    internal/client_methods.py, current_client_method_metadata(), the
    connect(handlers=...) option, the transport's request_handler= option
    or the create() class methods on client-method errors. Like TypeScript
    clients, they answer any request the server sends with method_not_found.
  • The server no longer accepts JSON-RPC response frames from the client. They
    are answered with invalid_request like any other malformed request.
  • Raw sockets are now sockets. A socket is a transport endpoint; the messages
    it carries belong to the handler. Migrate as follows:
    • @channel.raw_socket(...) becomes @channel.socket(...) with the same
      options.
    • service.raw_socket(path, handler, ...) becomes
      service.socket(path, handler, ...). service.socket(path, channels=...)
      still mounts JSON-RPC endpoints; passing both a handler and channels=, or
      JSON-RPC-only options with a handler, raises ProtocolDefinitionError.
    • Inject RpcSocket instead of RpcRawSocket; RpcRawMessage is
      RpcSocketMessage and RpcRawSocketEndpoint is RpcSocketEndpoint.
      The module fastapi_rpckit.raw_sockets is now fastapi_rpckit.sockets.
    • The low-level WebSocket adapter protocol formerly named RpcSocket is now
      RpcWebSocket. Rename custom adapters and annotations that implemented or
      referenced the old protocol; FastApiSocket is unchanged.
  • The contract lists sockets under x-rpckit-sockets instead of
    x-rpckit-raw-sockets. Re-export contracts and regenerate clients together;
    generators reject contracts that still contain x-rpckit-raw-sockets.
  • Generated clients rename their socket API. Python: module sockets (was
    raw_sockets), Socket, SocketMessage, SocketMessageType, SocketName,
    SocketEndpoint, SocketTransport, SocketOpener, SOCKETS,
    SocketConnection, SocketConnectionFactory, SocketConnectionStream;
    connect(socket_connection_factory=...) and socket_opener=... replace
    raw_socket_factory and raw_socket_opener. TypeScript: module sockets
    (was rawSockets), Socket, sockets, resolveSocketEndpoint,
    SocketConnectionStream, and the options socketConnectionFactory,
    socketQueueSize, and socketOpener replace rawSocketFactory,
    rawSocketQueueSize, and rawSocketOpener. Regenerate clients and rename
    these references in consuming code.
  • Server log messages and close reasons say "socket" instead of "raw socket".
    Socket wire behavior, close codes, and message framing are unchanged.
  • Typed JSON input is now validated before queueing. A malformed later message
    can therefore cancel an active invocation. Clients must send valid messages
    throughout a connection rather than depending on an earlier reply before an
    invalid queued message is rejected.

Migration:

  1. Replace @channel.server.method(...) and the other channel.server.*
    decorators with @channel.method(...) and the matching channel decorator.
  2. Replace each server-to-client call with a server method the client calls,
    an event or a subscription. Remove Inject[RpcConnectedClient] parameters.
  3. Drop client_method_timeout= from RpcLimits(...) and client_methods=
    from RpcTestClient(...).
  4. Regenerate clients and remove handler classes and handlers= arguments
    from Client.connect(...) calls.
  5. Rename @channel.raw_socket to @channel.socket, service.raw_socket(...) to
    service.socket(...), RpcRawSocket to RpcSocket, and the adapter
    protocol RpcSocket to RpcWebSocket, then re-export contracts and
    regenerate clients as described above.

Added

  • Infer typed JSON connections from Inject[RpcSocket[Incoming, Outgoing]],
    including aliases and unions. These handlers retain their own receive/send loop,
    unsolicited messages, multiple replies, and one dependency scope per connection.
    They share cached internal Pydantic validation and serialization with message
    handlers. Annotations alone define message types, directional contract schemas,
    and Python/TypeScript SDK types. Bare RpcSocket keeps raw text/binary behavior;
    protocol metadata never enables validation.

  • Declare JSON socket message handlers as async def ping(message: Ping) -> Pong.
    The library validates each input, calls the handler sequentially in a fresh
    invocation scope, and validates and serializes its response. Invalid input
    closes with 1002 and invalid output with 1011, without exposing message contents.
    Injecting RpcSocket keeps the existing connection-handler text/binary behavior.
    Protocol metadata alone still does not enable validation.

  • Export directional socket message schemas and generate Python and TypeScript
    Socket[Received, Sent] clients. Add a checked, live typed_socket example.
    Python SDK validation uses generated models; TypeScript supplies static payload
    types and JSON framing, with authoritative validation on the server.

  • Declare the application protocol of a socket with
    @channel.socket(..., protocol=RpcSocketProtocol(...)). The declaration
    holds a protocol name, version, encoding, and specification URI references.
    It is metadata only: messages still pass through unchanged. Handlers read it
    as RpcSocket.protocol.

  • Contracts export declared protocols as x-rpckit-protocol on socket entries.
    The generator IR keeps them as SocketProtocolDecl, whose
    resolve_schemas() resolves relative schema references against the contract
    location. Generated Python and TypeScript clients expose them as
    SocketProtocol on socket endpoints.

  • Plug typed protocol clients into code generation with
    fastapi_rpckit.codegen.bindings. A ProtocolBinding selected by protocol
    name emits a module into the generated client, and matching socket methods
    return its session instead of a generic Socket. Select bindings with
    bindings = [...] in the generator config, --binding, or the
    fastapi_rpckit.socket_bindings entry point group. Sockets without a
    binding keep the generic Socket.

  • Add the socket_protocol example: a small CDP-shaped protocol with Python and
    TypeScript bindings, tested against a live server.

Fixed

  • Close an opened TypeScript socket when a protocol binding fails to initialize,
    including asynchronous failures. Preserve the initialization error if closing
    the transport also fails.
  • Keep bindings with identical exported factory or session names separate in
    generated Python and TypeScript clients by importing their modules under
    distinct aliases.