Skip to main content

cratestack_axum/rpc/
mod.rs

1//! Runtime primitives for the `transport rpc` generation style.
2//!
3//! See `docs/design/rpc-transport.md` for the full design. This module
4//! provides the binding-side surface that schemas with `transport rpc`
5//! generate against:
6//!
7//! - `POST /rpc/{op_id}` — unary calls. Body is the codec-encoded *input*
8//!   (no frame wrapper); response body is the codec-encoded *output* on
9//!   success, or an [`RpcErrorBody`] on error with HTTP status mapped via
10//!   [`CratestackError::status_code`].
11//! - `POST /rpc/batch` — sequence of `RpcRequest` frames in, sequence of
12//!   `RpcResponseFrame` frames out in the same order. Per-frame errors
13//!   don't poison the batch.
14//! - `GET /rpc/subscribe/{op_id}` — SSE subscription dispatch for
15//!   `@@subscribe`d models (design doc §3.4a, cratestack#390). One
16//!   `event: message` per `ModelEvent<T>`, terminated by one
17//!   `event: error` on backpressure overflow. See [`sse`] and
18//!   [`subscription_bridge`].
19//!
20//! The full WebSocket frame loop (§3.4) remains speced but unbuilt,
21//! gated on a real bidirectional/high-multiplexing need per issue
22//! #183's spike decision — see `docs/design/rpc-transport.md` §6.5.
23//!
24//! The macro emits the dispatch table and the `rpc_router` constructor.
25//! This crate provides the shared frame shapes, error mapping, and the
26//! `RPC_*_PATH` constants both sides agree on.
27
28mod batch;
29mod codec_helpers;
30mod credential_expiry;
31mod error_encode;
32mod model_feed;
33mod procedure_subscription;
34mod sse;
35mod sse_subscription;
36mod subscribe_error;
37mod subscribe_query;
38mod subscription_bridge;
39mod synthesize;
40pub(crate) mod util;
41
42#[cfg(test)]
43mod tests_error;
44#[cfg(test)]
45mod tests_frame;
46#[cfg(test)]
47mod tests_get;
48#[cfg(test)]
49mod tests_list;
50#[cfg(test)]
51mod tests_response_rebuffer;
52
53// Re-export the wire shapes from `cratestack-core::rpc`. Both the server
54// binding and every generated client agree on those shapes, and lifting
55// them into core means the client crates don't need to depend on axum.
56// `RpcListInput`/`RpcListPredicate`/`RpcPkInput`/`RpcUpdateInput` joined
57// this list via cratestack#490 — previously defined locally in this
58// crate's own (now-removed) `inputs` module, which meant
59// `include_client_schema!`'s RPC model-CRUD codegen (`::cratestack::rpc::
60// RpcListInput`, …) could never resolve for a facade without
61// `cratestack-axum` in its graph. See `cratestack-core::rpc`'s doc comment
62// on those types for the full story.
63pub use cratestack_core::rpc::{
64    RPC_BATCH_PATH, RPC_STREAM_ERROR_TAG, RPC_SUBSCRIBE_PATH, RPC_UNARY_PATH, RpcErrorBody,
65    RpcGetInput, RpcListInput, RpcListPredicate, RpcPkInput, RpcRequest, RpcResponseFrame,
66    RpcUpdateInput, cratestack_error_code_to_rpc_code, rpc_code,
67};
68
69pub use batch::response_to_frame;
70pub use codec_helpers::{decode_rpc_body, encode_rpc_value};
71pub use credential_expiry::until_credential_expires;
72pub use error_encode::{convert_handler_error_response, encode_rpc_error};
73pub use model_feed::{FeedEvent, model_events, model_feed, route_event};
74pub use procedure_subscription::{procedure_feed, procedure_input_query, procedure_query_args};
75pub use sse::{encode_model_event_sse_response, validate_subscribe_accept_header};
76pub use sse_subscription::encode_subscription_sse_response;
77pub use subscribe_error::encode_subscribe_error;
78pub use subscribe_query::{
79    SubscribeQuery, project_event_fields, split_subscribe_query, subscribe_input_query,
80};
81pub use subscription_bridge::{SubscriptionPush, guarded_receiver_stream, subscription_channel};
82pub use synthesize::{synthesize_get_query, synthesize_list_query};
83
84/// Codec/transport capabilities for every RPC binding route. Both unary
85/// and batch accept and emit CBOR or JSON, default CBOR; sequence
86/// responses (streaming) are not yet supported by this binding.
87///
88/// Used by `encode_transport_result_with_status_for` to negotiate
89/// response content type when the dispatcher synthesizes an error
90/// response or wraps a batch result.
91pub const RPC_BINDING_CAPABILITIES: cratestack_core::RouteTransportCapabilities =
92    cratestack_core::RouteTransportCapabilities {
93        request_types: &["application/cbor", "application/json"],
94        response_types: &["application/cbor", "application/json"],
95        default_response_type: "application/cbor",
96        supports_sequence_response: false,
97    };