ript 0.1.2

Rust implementation of the InertiaJS protocol compatible with `riptc` for generating strong TypeScript bindings.
Documentation
//! `ript`'s driver which implements the required middleware for responses to work.

use std::sync::Arc;

use axum::{
    Json,
    extract::{FromRequestParts, OriginalUri},
    http::{StatusCode, header::LOCATION},
    response::{Html, IntoResponse, Response},
};

use crate::{
    extension::InertiaExtension,
    inertia::{self, RenderResponse},
};

/// Axum map response function for powering inertia.
pub async fn driver(mut parts: axum::http::request::Parts, mut res: Response) -> Response {
    let res_exts = res.extensions_mut();
    let Some(inertia_ext): Option<Arc<InertiaExtension>> = res_exts.remove() else {
        tracing::error!("extension not set, handler likely failed");
        return res;
    };

    let (mut res_parts, _body_unsused_we_overwrite) = res.into_parts();

    if let Some(redirect) = inertia_ext.take_redirect() {
        res_parts.status = StatusCode::SEE_OTHER;
        res_parts.headers.insert(LOCATION, redirect);

        return res_parts.into_response().into_response();
    }

    let component = match inertia_ext.component() {
        Some(component) => component,
        None => {
            tracing::warn!(
                "component nor redirect set, this is likely caused by lack of an error handler middleware"
            );
            return res_parts.into_response().into_response();
        }
    };

    let props = inertia_ext.take_props();
    let version = inertia_ext.version();

    // unwrap fine, this extractor's error type is `Infallible`
    let original_uri = OriginalUri::from_request_parts(&mut parts, &())
        .await
        .unwrap();

    let render_response = RenderResponse::builder()
        .clear_history(inertia_ext.get_clear_history())
        .encrypt_history(inertia_ext.get_encrypt_history())
        .url(original_uri.to_string())
        .version(version.expect("version never set"))
        .component(component)
        .props(&props)
        .build();

    res_parts
        .headers
        .append("Vary", "X-Inertia".try_into().unwrap());

    if inertia::RequestHeaders::from(&parts.headers).x_inertia() {
        res_parts
            .headers
            .append("X-Inertia", "true".try_into().unwrap());

        (res_parts, Json(render_response)).into_response()
    } else {
        let html = inertia_ext.render_html(render_response).await;
        Html(html).into_response()
    }
}