docs: missing_docs sweep — 0 warnings + deny gate + publish-prep decisions (HY-02, HY-04, HY-11)
- document every public-API item across 18 files (openapi_spec model, HttpAuthScheme/HttpServiceConfig, HttpClientBuildError + SharedHttpClient accessors, RetryAfterMiddleware, GatewayDispatch, gateway error mapping, CallRequest/SchemaQuery/SubscribeStream, HttpAdapter + ALPNs + builders, decoy/healthz/state, WsSessions/WsPumps, from_openapi/from_jsonschema/from_mcp/from_wss/to_mcp, lib.rs module docs) - enforcement: #![deny(missing_docs)] at crate root — stronger than CI rustdocflags (every build incl. cfg(test), where rustdoc misses the test-support module docs) - HY-10 (opportunistic): all 8 docs.rs/alkhttp placeholder ADR links + the one relative ../docs link converted to plain text; the 10 pre-existing private/redundant intra-doc-link warnings fixed — RUSTDOCFLAGS="-D warnings" cargo doc is fully clean - HY-11 decision: docs/ + tasks/ excluded from the published package (contributor-facing design/process material; ADR references degrade to plain text uniformly). cargo publish --dry-run: 38 files, ~889 KiB, zero docs/ or tasks/ entries - HY-04 decision: keep + document — frame_channel0_chunk's unwrap is on serializing the acyclic EventEnvelope (unreachable failure); # Panics on it and the adjacent WsClient senders state the contract Verified: cargo test (299 + 5 TLS), --all-features (370 + suites), --no-default-features (299), clippy --all-targets -D warnings (default + all-features), fmt --check, cargo doc -D warnings clean, cargo publish --dry-run --allow-dirty clean. Tasks: review-001-missing-docs-sweep (final pending task; 42/42)
This commit is contained in:
+26
-3
@@ -17,8 +17,8 @@
|
||||
//! sends must match what `/schema` advertises, so peer-supplied input
|
||||
//! cannot add upstream query parameters, headers, or craft a request body
|
||||
//! the contract does not declare. Declared keys route by designation: a
|
||||
//! property marked [`HEADER_PARAM_IN_MARKER`]` = "header"` is sent as a
|
||||
//! request header, the declared [`GATEWAY_BODY_KEY`] property becomes the
|
||||
//! property marked with the `HEADER_PARAM_IN_MARKER` marker key set to "header" is sent as a
|
||||
//! request header, the declared `GATEWAY_BODY_KEY` property becomes the
|
||||
//! request body, and every other declared key becomes an upstream query
|
||||
//! parameter.
|
||||
|
||||
@@ -79,17 +79,40 @@ pub(crate) const GATEWAY_BODY_KEY: &str = "body";
|
||||
pub(crate) const HEADER_PARAM_IN_MARKER: &str = "wire";
|
||||
pub(crate) const HEADER_PARAM_MARKER_VALUE: &str = "header";
|
||||
|
||||
/// The credential scheme forwarded handlers apply to outbound requests
|
||||
/// (ADR-014). The credential value itself flows through
|
||||
/// `OperationContext.capabilities` at call time — never through this
|
||||
/// config.
|
||||
#[derive(Clone)]
|
||||
pub enum HttpAuthScheme {
|
||||
/// `Authorization: Bearer <token>` from the caller's `Bearer`
|
||||
/// capability.
|
||||
Bearer,
|
||||
ApiKey { header_name: String },
|
||||
/// A named API-key header (e.g. `x-api-key`) carrying the caller's
|
||||
/// `ApiKey` capability value.
|
||||
ApiKey {
|
||||
/// The upstream header the key is sent in.
|
||||
header_name: String,
|
||||
},
|
||||
/// HTTP Basic auth from the caller's `username`/`password`
|
||||
/// capability pair.
|
||||
Basic,
|
||||
}
|
||||
|
||||
/// Assembly-time configuration for one imported HTTP service: the
|
||||
/// registry namespace its operations land under, where traffic goes,
|
||||
/// and how credentials attach.
|
||||
pub struct HttpServiceConfig {
|
||||
/// Registry namespace for the imported operations (the
|
||||
/// `<namespace>/<operationId>` op names).
|
||||
pub namespace: String,
|
||||
/// Outbound base URL every path template is resolved against.
|
||||
pub base_url: String,
|
||||
/// Credential scheme for outbound requests; `None` sends an
|
||||
/// unauthenticated request.
|
||||
pub auth: Option<HttpAuthScheme>,
|
||||
/// Static headers attached to every outbound request (e.g. a
|
||||
/// required `User-Agent`).
|
||||
pub default_headers: HashMap<String, String>,
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,10 @@ use serde_json::Value;
|
||||
use super::forward::{forward, forward_stream, HttpServiceConfig};
|
||||
use crate::client::SharedHttpClient;
|
||||
|
||||
/// The HTTP-backed single-endpoint adapter (ADR-066): one caller-built
|
||||
/// [`OperationSpec`] forwarded to one HTTP endpoint. Eagerly validated
|
||||
/// at construction; the caller's spec visibility is forced to
|
||||
/// `Internal` (ADR-015).
|
||||
pub struct FromJsonSchema {
|
||||
spec: OperationSpec,
|
||||
config: HttpServiceConfig,
|
||||
@@ -61,7 +65,7 @@ impl FromJsonSchema {
|
||||
/// are rejected at call time. Mark a property with
|
||||
/// `"wire": "header"` to route it as an upstream HTTPS header
|
||||
/// instead of a query parameter (review 001 OAI-03). Input key
|
||||
/// [`GATEWAY_BODY_KEY`](super::forward::GATEWAY_BODY_KEY) carries
|
||||
/// `GATEWAY_BODY_KEY` ("body") carries
|
||||
/// the request body.
|
||||
pub fn new(
|
||||
spec: OperationSpec,
|
||||
|
||||
@@ -50,6 +50,9 @@ const MCP_CAPABILITY_KEY: &str = "mcp";
|
||||
/// timed out. Payload is the array-of-content-blocks shape; retryable.
|
||||
const MCP_TRANSPORT_ERROR: &str = "MCP_TRANSPORT_ERROR";
|
||||
|
||||
/// The `from_mcp` adapter (mcp feature): imports a remote MCP server's
|
||||
/// tools as call-protocol operations under one namespace, with the
|
||||
/// auth token injected per-call from `Capabilities` (ADR-014).
|
||||
pub struct FromMCP {
|
||||
endpoint: String,
|
||||
auth_token: Option<Secret<String>>,
|
||||
@@ -57,6 +60,8 @@ pub struct FromMCP {
|
||||
}
|
||||
|
||||
impl FromMCP {
|
||||
/// Assemble the adapter for a streamable-HTTP MCP `endpoint`,
|
||||
/// registering its tools under `namespace`.
|
||||
pub fn new(endpoint: impl Into<String>, namespace: impl Into<String>) -> Self {
|
||||
Self {
|
||||
endpoint: endpoint.into(),
|
||||
@@ -65,19 +70,24 @@ impl FromMCP {
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the auth token sent as the MCP endpoint's `Authorization:
|
||||
/// Bearer` header (wrapped in `Secret` so it never logs).
|
||||
pub fn with_auth_token(mut self, token: impl Into<String>) -> Self {
|
||||
self.auth_token = Some(Secret::new(token.into()));
|
||||
self
|
||||
}
|
||||
|
||||
/// The configured MCP endpoint URL.
|
||||
pub fn endpoint(&self) -> &str {
|
||||
&self.endpoint
|
||||
}
|
||||
|
||||
/// The namespace imported operations register under.
|
||||
pub fn namespace(&self) -> &str {
|
||||
&self.namespace
|
||||
}
|
||||
|
||||
/// The configured token, for introspection (never logged).
|
||||
pub fn auth_token(&self) -> Option<&Secret<String>> {
|
||||
self.auth_token.as_ref()
|
||||
}
|
||||
|
||||
@@ -88,6 +88,9 @@ fn reject_collisions(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The `from_openapi` adapter (ADR-051 input format): turns a parsed
|
||||
/// OpenAPI document into forwarding-handler registrations under one
|
||||
/// namespace — the credential injection point per ADR-014.
|
||||
pub struct FromOpenAPI {
|
||||
spec: OpenAPISpec,
|
||||
config: HttpServiceConfig,
|
||||
@@ -95,6 +98,8 @@ pub struct FromOpenAPI {
|
||||
}
|
||||
|
||||
impl FromOpenAPI {
|
||||
/// Assemble the adapter over a parsed spec, service config, and the
|
||||
/// shared outbound client.
|
||||
pub fn new(
|
||||
spec: OpenAPISpec,
|
||||
config: HttpServiceConfig,
|
||||
|
||||
@@ -78,6 +78,9 @@ fn connection_closed_error() -> CallError {
|
||||
CallError::new("CONNECTION_CLOSED", "from_wss connection dropped", true)
|
||||
}
|
||||
|
||||
/// The `from_wss` consumer adapter (wss feature): dials a remote WS
|
||||
/// endpoint speaking the channels protocol and imports its operations
|
||||
/// under an optional namespace (discovered when omitted).
|
||||
pub struct FromWss {
|
||||
endpoint: String,
|
||||
auth_token: Option<Secret<String>>,
|
||||
@@ -86,6 +89,8 @@ pub struct FromWss {
|
||||
}
|
||||
|
||||
impl FromWss {
|
||||
/// Assemble the adapter for a `wss://` (or explicit `ws://`)
|
||||
/// channel endpoint.
|
||||
pub fn new(endpoint: impl Into<String>) -> Self {
|
||||
Self {
|
||||
endpoint: endpoint.into(),
|
||||
@@ -95,11 +100,15 @@ impl FromWss {
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the auth token injected per-call from `Capabilities`
|
||||
/// (wrapped in `Secret` so it never logs).
|
||||
pub fn with_auth_token(mut self, token: impl Into<String>) -> Self {
|
||||
self.auth_token = Some(Secret::new(token.into()));
|
||||
self
|
||||
}
|
||||
|
||||
/// Pin the namespace imported operations register under; without
|
||||
/// it the remote's discovery advertises namespaces per operation.
|
||||
pub fn with_namespace(mut self, namespace: impl Into<String>) -> Self {
|
||||
self.namespace = Some(namespace.into());
|
||||
self
|
||||
@@ -114,14 +123,17 @@ impl FromWss {
|
||||
self
|
||||
}
|
||||
|
||||
/// The configured channel endpoint URL.
|
||||
pub fn endpoint(&self) -> &str {
|
||||
&self.endpoint
|
||||
}
|
||||
|
||||
/// The pinned namespace, when one was set.
|
||||
pub fn namespace(&self) -> Option<&str> {
|
||||
self.namespace.as_deref()
|
||||
}
|
||||
|
||||
/// The configured token, for introspection (never logged).
|
||||
pub fn auth_token(&self) -> Option<&Secret<String>> {
|
||||
self.auth_token.as_ref()
|
||||
}
|
||||
@@ -134,6 +146,7 @@ impl FromWss {
|
||||
/// in-flight pending calls with retryable `CONNECTION_CLOSED`.
|
||||
pub struct WssSession {
|
||||
_client: ChannelClient,
|
||||
/// The live channel-0 connection the consumer drives calls through.
|
||||
pub call_connection: Arc<CallConnection>,
|
||||
_monitor: WssDropMonitor,
|
||||
}
|
||||
|
||||
@@ -16,50 +16,89 @@ use serde_json::Value;
|
||||
/// exhausting the stack.
|
||||
pub(crate) const MAX_REF_RESOLUTION_DEPTH: usize = 64;
|
||||
|
||||
/// The `paths`-level HTTP methods the adapter models. `trace` is
|
||||
/// deliberately absent (OAI-06): a path carrying only unsupported
|
||||
/// methods is skipped with a warning, not imported as a mis-behaving op.
|
||||
pub(crate) const HTTP_METHODS: &[&str] =
|
||||
&["get", "post", "put", "patch", "delete", "head", "options"];
|
||||
|
||||
/// The `info` block of an OpenAPI document.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OpenAPIInfo {
|
||||
/// Human-readable title (OpenAPI `info.title`).
|
||||
pub title: String,
|
||||
/// Declared spec/API version (OpenAPI `info.version`).
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
/// One entry of a path item: a concrete path plus the operations
|
||||
/// declared on it.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PathItem {
|
||||
/// `(method, operation)` pairs, methods lowercase as declared in the
|
||||
/// document (`get`, `post`, ...), in parsed order.
|
||||
pub operations: Vec<(String, Operation)>,
|
||||
}
|
||||
|
||||
/// One OpenAPI operation parsed into the shared model.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Operation {
|
||||
/// `operationId` when declared; `from_openapi` falls back to
|
||||
/// `method_path_derived` naming when absent.
|
||||
pub operation_id: Option<String>,
|
||||
/// Operation-level (non-`$ref`) parameters; `parameter $ref`s are
|
||||
/// resolved before this model is built.
|
||||
pub parameters: Vec<Parameter>,
|
||||
/// `requestBody` when declared; `requestBody $ref`s are resolved
|
||||
/// before this model is built.
|
||||
pub request_body: Option<RequestBody>,
|
||||
/// Responses keyed by their declared key — concrete statuses
|
||||
/// (`"200"`, `"404"`), wildcards (`"4XX"`), or `"default"`. Consumers
|
||||
/// must decide how to treat non-numeric keys (OAI-06).
|
||||
pub responses: BTreeMap<String, Response>,
|
||||
}
|
||||
|
||||
/// One OpenAPI parameter (`name`/`in`/`required`/`schema`).
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Parameter {
|
||||
/// Declared parameter name; must be unique per location per
|
||||
/// operation in a valid document.
|
||||
pub name: String,
|
||||
/// Parameter location: `path`, `query`, `header`, or `cookie`
|
||||
/// (the last unsupported and rejected loudly at import).
|
||||
pub in_: String,
|
||||
/// Whether the operation fails without the parameter.
|
||||
pub required: bool,
|
||||
/// The parameter's schema as declared (unresolved `$ref`s are
|
||||
/// resolved by the consumer via `resolve_refs_recursive`).
|
||||
pub schema: Option<Value>,
|
||||
}
|
||||
|
||||
/// An OpenAPI request body — the media-type → schema map of its
|
||||
/// `content` field.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RequestBody {
|
||||
/// Media type (e.g. `application/json`) → the body schema.
|
||||
pub content: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
/// An OpenAPI response — the media-type → schema map of its `content`
|
||||
/// field.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Response {
|
||||
/// Media type (e.g. `application/json`) → the response schema.
|
||||
pub content: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
/// The `components` block: reusable schemas, parameters, and request
|
||||
/// bodies keyed by name.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Components {
|
||||
/// `components/schemas` entries.
|
||||
pub schemas: HashMap<String, Value>,
|
||||
/// `components/parameters` entries.
|
||||
pub parameters: HashMap<String, Value>,
|
||||
/// `components/requestBodies` entries.
|
||||
pub request_bodies: HashMap<String, Value>,
|
||||
}
|
||||
|
||||
@@ -73,15 +112,29 @@ fn index_component_map(raw: Option<&Value>) -> HashMap<String, Value> {
|
||||
map
|
||||
}
|
||||
|
||||
/// A parsed OpenAPI 3.x document: the typed model (`info`, `paths`,
|
||||
/// `components`) plus the untouched `raw` document for `$ref`
|
||||
/// resolution.
|
||||
#[derive(Debug)]
|
||||
pub struct OpenAPISpec {
|
||||
/// The parsed `info` block.
|
||||
pub info: OpenAPIInfo,
|
||||
/// The path items keyed by their literal path string (with
|
||||
/// placeholders).
|
||||
pub paths: BTreeMap<String, PathItem>,
|
||||
/// The `components` block, when the document declares one.
|
||||
pub components: Option<Components>,
|
||||
/// The full document as parsed — the lookup target for `$ref`
|
||||
/// resolution.
|
||||
pub raw: Value,
|
||||
}
|
||||
|
||||
impl OpenAPISpec {
|
||||
/// Parse a JSON OpenAPI document.
|
||||
///
|
||||
/// Fails with [`AdapterError::SchemaParse`] for malformed JSON or an
|
||||
/// invalid document structure (missing `info`/`paths`, unresolvable
|
||||
/// parameter `$ref`s).
|
||||
pub fn from_json(doc: &str) -> Result<Self, AdapterError> {
|
||||
let raw: Value = serde_json::from_str(doc).map_err(|e| AdapterError::SchemaParse {
|
||||
message: format!("invalid JSON: {e}"),
|
||||
@@ -127,6 +180,12 @@ impl OpenAPISpec {
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse an already-deserialized OpenAPI document.
|
||||
///
|
||||
/// Validation mirrors [`from_json`](Self::from_json): the object
|
||||
/// shape, `info`/`paths` presence, parameter `$ref` resolvability,
|
||||
/// and the OAI-06 loud-feature gates (`servers` overrides,
|
||||
/// non-default `style`/`explode`) all apply.
|
||||
pub fn from_value(raw: Value) -> Result<Self, AdapterError> {
|
||||
if !raw.is_object() {
|
||||
return Err(AdapterError::SchemaParse {
|
||||
|
||||
@@ -119,15 +119,20 @@ fn batch_input_schema() -> Value {
|
||||
})
|
||||
}
|
||||
|
||||
/// The `to_mcp` projection (ADR-041): the local call-protocol
|
||||
/// operations exposed as 4 fixed MCP gateway tools (`search`, `schema`,
|
||||
/// `call`, `batch`) over the streamable-HTTP transport.
|
||||
pub struct ToMcpGateway {
|
||||
dispatch: Arc<GatewayDispatch>,
|
||||
}
|
||||
|
||||
impl ToMcpGateway {
|
||||
/// Assemble the gateway over a dispatch spine.
|
||||
pub fn new(dispatch: Arc<GatewayDispatch>) -> Self {
|
||||
Self { dispatch }
|
||||
}
|
||||
|
||||
/// The dispatch spine the tools invoke through.
|
||||
pub fn dispatch(&self) -> &Arc<GatewayDispatch> {
|
||||
&self.dispatch
|
||||
}
|
||||
@@ -480,8 +485,11 @@ impl rmcp::handler::server::ServerHandler for ToMcpGateway {
|
||||
}
|
||||
}
|
||||
|
||||
/// The ready-to-mount rmcp service wrapping [`ToMcpGateway`] over the
|
||||
/// streamable-HTTP transport.
|
||||
pub type ToMcpService = StreamableHttpService<ToMcpGateway, LocalSessionManager>;
|
||||
|
||||
/// Build the mountable MCP service for a dispatch spine.
|
||||
pub fn to_mcp_service(dispatch: Arc<GatewayDispatch>) -> ToMcpService {
|
||||
let gateway = ToMcpGateway::new(dispatch);
|
||||
StreamableHttpService::new(
|
||||
|
||||
Reference in New Issue
Block a user