gsm_core/
interfaces.rs

1//! Helpers for converting core types to the canonical host bindings.
2use greentic_interfaces_host::bindings;
3use greentic_types::{GreenticError, SessionCursor, TenantCtx};
4use std::convert::TryFrom;
5
6pub type HostTenantCtx = bindings::greentic::interfaces_types::types::TenantCtx;
7pub type HostSessionCursor = bindings::greentic::interfaces_types::types::SessionCursor;
8
9// Surface common host-facing modules so callers can import everything via gsm-core.
10pub use greentic_interfaces_host::{
11    component, events_bridge, events_broker, events_sink, events_source, http_client,
12    messaging_session, pack_exports, secrets, state, telemetry, types, validate,
13};
14
15/// Map a `TenantCtx` into its WIT host binding representation.
16pub fn to_host_tenant_ctx(ctx: &TenantCtx) -> Result<HostTenantCtx, GreenticError> {
17    HostTenantCtx::try_from(ctx.clone())
18}
19
20/// Map a WIT host binding tenant context back into the core type.
21pub fn from_host_tenant_ctx(wit: HostTenantCtx) -> Result<TenantCtx, GreenticError> {
22    TenantCtx::try_from(wit)
23}
24
25/// Map a session cursor into its host binding counterpart.
26pub fn to_host_session_cursor(cursor: SessionCursor) -> HostSessionCursor {
27    cursor.into()
28}
29
30/// Map a host binding session cursor back into the core type.
31pub fn from_host_session_cursor(cursor: HostSessionCursor) -> SessionCursor {
32    cursor.into()
33}
34
35#[cfg(test)]
36mod tests {
37    use super::*;
38    use greentic_types::{GreenticError, SessionCursor, TenantCtx};
39
40    fn fixture_id<T>(value: &str) -> T
41    where
42        T: TryFrom<String, Error = GreenticError>,
43    {
44        T::try_from(value.to_owned())
45            .unwrap_or_else(|err| panic!("invalid fixture identifier '{value}': {err}"))
46    }
47
48    fn sample_tenant_ctx() -> TenantCtx {
49        TenantCtx {
50            env: fixture_id("prod"),
51            tenant: fixture_id("tenant-1"),
52            tenant_id: fixture_id("tenant-1"),
53            team: Some(fixture_id("team-42")),
54            team_id: Some(fixture_id("team-42")),
55            user: Some(fixture_id("user-7")),
56            user_id: Some(fixture_id("user-7")),
57            session_id: Some("sess-42".into()),
58            flow_id: Some("flow-42".into()),
59            node_id: Some("node-42".into()),
60            provider_id: Some("provider-42".into()),
61            trace_id: Some("trace".into()),
62            correlation_id: Some("corr".into()),
63            deadline: None,
64            attempt: 2,
65            idempotency_key: Some("idem".into()),
66            impersonation: None,
67            attributes: Default::default(),
68        }
69    }
70
71    #[test]
72    fn tenant_ctx_roundtrips_via_host_bindings() {
73        let ctx = sample_tenant_ctx();
74        let wit = to_host_tenant_ctx(&ctx).expect("map to host");
75        let back = from_host_tenant_ctx(wit).expect("map from host");
76        assert_eq!(back.env, ctx.env);
77        assert_eq!(back.tenant, ctx.tenant);
78        assert_eq!(back.user, ctx.user);
79        assert_eq!(back.session_id, ctx.session_id);
80        assert_eq!(back.flow_id, ctx.flow_id);
81        assert_eq!(back.provider_id, ctx.provider_id);
82    }
83
84    #[test]
85    fn session_cursor_roundtrips_via_host_bindings() {
86        let cursor = SessionCursor {
87            node_pointer: "node".into(),
88            wait_reason: Some("waiting".into()),
89            outbox_marker: Some("marker".into()),
90        };
91        let wit = to_host_session_cursor(cursor.clone());
92        let back = from_host_session_cursor(wit);
93        assert_eq!(back.node_pointer, cursor.node_pointer);
94        assert_eq!(back.wait_reason, cursor.wait_reason);
95        assert_eq!(back.outbox_marker, cursor.outbox_marker);
96    }
97}