feat(axum): register checked handles

Add HandlerRegistry::register_handle for generated Handle<T> values and migrate examples away from passing raw numeric handle ids at registration sites.

req: ceremony/004

req: public_api/001
This commit is contained in:
slhx agent
2026-05-26 00:26:42 +02:00
parent 4803d681d2
commit bc8534a768
5 changed files with 34 additions and 21 deletions
+12 -1
View File
@@ -5,7 +5,7 @@ use axum::http::{header, request::Parts, HeaderMap, HeaderValue, Request, Respon
use axum::response::sse::{Event, Sse};
use axum::response::IntoResponse;
use futures_util::{Stream, StreamExt};
use slhx_core::{BuildFingerprint, EffectBatch, IntoEffect};
use slhx_core::{BuildFingerprint, EffectBatch, Handle, IntoEffect};
use std::collections::BTreeMap;
use std::convert::Infallible;
@@ -262,6 +262,17 @@ impl HandlerRegistry {
self
}
pub fn register_handle<I, E>(
self,
handle: Handle<I>,
handler: impl Fn(InteractionForm) -> E + Send + Sync + 'static,
) -> Self
where
E: IntoEffect,
{
self.register(handle.id().id, handler)
}
pub fn dispatch(&self, form: InteractionForm) -> Result<EffectResponse, DispatchRejection> {
let handle_id = form.handle_id;
let Some(handler) = self.handlers.get(&handle_id) else {
+6 -4
View File
@@ -6,7 +6,7 @@ use slhx_axum::{
InteractionFormRejection, PageMode, PageRequest, PageResponse, SLHX_CONTENT_TYPE,
SLHX_FINGERPRINT_HEADER, SLHX_PARTIAL_HEADER, SLHX_RUNTIME_CONTENT_TYPE, SLHX_TITLE_HEADER,
};
use slhx_core::{push, BuildFingerprint, Slot};
use slhx_core::{push, BuildFingerprint, Handle, Slot};
fn selector(value: &str) -> Selector {
Selector::parse(value).expect("test selector parses")
@@ -100,14 +100,16 @@ fn interaction_form_preserves_hidden_csrf_fields_for_extractors() {
}
#[test]
fn handler_registry_dispatches_by_numeric_handle_id() {
fn handler_registry_dispatches_by_checked_handle() {
// req: ceremony/004 req: public_api/001
let title = Slot::<String>::new(7);
let registry = HandlerRegistry::new(BuildFingerprint(123)).register(42, move |form| {
let create = Handle::<()>::new(42);
let registry = HandlerRegistry::new(BuildFingerprint(123)).register_handle(create, move |form| {
title.text(form.value("title").unwrap_or(""))
});
let response = registry
.dispatch(InteractionForm::new(42, [("title".into(), "Hello".into())]))
.dispatch(InteractionForm::new(create.id().id, [("title".into(), "Hello".into())]))
.unwrap();
assert_eq!(response.batch.fingerprint, BuildFingerprint(123));