sdk

Radroots SDK and bindings
git clone https://radroots.dev/git/sdk.git
Log | Files | Refs | README

commit 54a92213c851bef0d107c4a06688dc97426ac5ce
parent 05c68dc8409efe6f552341a70bbe5fd10bedcd10
Author: triesap <tyson@radroots.org>
Date:   Wed, 24 Jun 2026 08:51:45 +0000

types: render bindings from dto registry

- replace the types binding model dependency with dto registry roots
- describe generic result envelopes with explicit DTO descriptors
- route the types package through xtask DTO registry rendering
- verify cargo, xtask generation, and package TypeScript checks

Diffstat:
MCargo.lock | 2+-
Mcrates/types_bindings/Cargo.toml | 2+-
Mcrates/types_bindings/src/lib.rs | 149+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Mtools/xtask/src/dto_roots.rs | 14++++++++++++++
Mtools/xtask/src/output.rs | 2+-
5 files changed, 136 insertions(+), 33 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -2157,7 +2157,7 @@ dependencies = [ name = "radroots_types_bindings" version = "0.1.0" dependencies = [ - "radroots_sdk_binding_model", + "dto_bindgen_core", "radroots_types", ] diff --git a/crates/types_bindings/Cargo.toml b/crates/types_bindings/Cargo.toml @@ -9,5 +9,5 @@ homepage.workspace = true publish = false [dependencies] -radroots_sdk_binding_model = { path = "../binding_model" } +dto_bindgen_core = { workspace = true } radroots_types = { workspace = true } diff --git a/crates/types_bindings/src/lib.rs b/crates/types_bindings/src/lib.rs @@ -1,40 +1,129 @@ pub use radroots_types as upstream; -use radroots_sdk_binding_model as ts; - -pub fn types_module() -> ts::TsModule { - ts::module(vec![ - ts::type_alias_params( - "IError", - &["T"], - ts::object(vec![ts::field("err", ts::reference("T"))]), - ), - ts::type_alias_params( - "IResult", - &["T"], - ts::object(vec![ts::field("result", ts::reference("T"))]), - ), - ts::type_alias_params( - "IResultList", - &["T"], - ts::object(vec![ts::field("results", ts::array(ts::reference("T")))]), - ), - ts::type_alias( - "IResultPass", - ts::object(vec![ts::field("pass", ts::boolean())]), - ), - ]) +use dto_bindgen_core::{ + DescribeCtx, Dto, FieldDef, GenericParam, IdentName, Primitive, RootDescriptor, RustTypeId, + SourceSpan, StructDef, TargetFieldNames, TypeDef, TypeRef, WireFieldNames, +}; + +struct IErrorDto; +struct IResultDto; +struct IResultListDto; +struct IResultPassDto; + +pub fn dto_roots() -> Vec<RootDescriptor> { + vec![ + RootDescriptor::new::<IErrorDto>(), + RootDescriptor::new::<IResultDto>(), + RootDescriptor::new::<IResultListDto>(), + RootDescriptor::new::<IResultPassDto>(), + ] +} + +impl Dto for IErrorDto { + fn describe(ctx: &mut DescribeCtx) -> TypeRef { + ctx.register_type( + rust_id("IError"), + generic_struct("IError", "err", TypeRef::GenericParam("T".to_owned())), + ) + } +} + +impl Dto for IResultDto { + fn describe(ctx: &mut DescribeCtx) -> TypeRef { + ctx.register_type( + rust_id("IResult"), + generic_struct("IResult", "result", TypeRef::GenericParam("T".to_owned())), + ) + } +} + +impl Dto for IResultListDto { + fn describe(ctx: &mut DescribeCtx) -> TypeRef { + ctx.register_type( + rust_id("IResultList"), + generic_struct( + "IResultList", + "results", + TypeRef::vec(TypeRef::GenericParam("T".to_owned())), + ), + ) + } +} + +impl Dto for IResultPassDto { + fn describe(ctx: &mut DescribeCtx) -> TypeRef { + ctx.register_type( + rust_id("IResultPass"), + TypeDef::Struct( + StructDef::new("IResultPass", "IResultPass", source_span()) + .with_field(field("pass", TypeRef::Primitive(Primitive::Bool))), + ), + ) + } +} + +fn generic_struct(export_name: &str, field_name: &str, field_type: TypeRef) -> TypeDef { + let mut def = StructDef::new(export_name, export_name, source_span()) + .with_field(field(field_name, field_type)); + def.generics.push(GenericParam::new("T")); + TypeDef::Struct(def) +} + +fn field(name: &str, ty: TypeRef) -> FieldDef { + FieldDef::new( + IdentName::new(name), + WireFieldNames::same(name), + TargetFieldNames::new(name, name), + ty, + source_span(), + ) +} + +fn rust_id(name: &'static str) -> RustTypeId { + RustTypeId::new(env!("CARGO_PKG_NAME"), name) +} + +fn source_span() -> SourceSpan { + SourceSpan::new(file!(), line!(), column!()) } #[cfg(test)] mod tests { - use super::types_module; + use super::dto_roots; + use dto_bindgen_core::{TypeDef, TypeRef, build_registry}; + + #[test] + fn preserves_result_wrapper_roots() { + let registry = build_registry(dto_roots()); + let actual = registry + .types_by_id + .values() + .map(|type_def| match type_def { + TypeDef::Struct(def) => def.export_name.as_str(), + TypeDef::Enum(def) => def.export_name.as_str(), + }) + .collect::<Vec<_>>(); + + assert_eq!(actual, ["IError", "IResult", "IResultList", "IResultPass"]); + } #[test] - fn preserves_result_wrapper_exports() { - let rendered = types_module().render(); - assert!(rendered.contains("export type IError")); - assert!(rendered.contains("export type IResultList")); - assert!(rendered.contains("export type IResultPass")); + fn preserves_generic_result_wrapper_fields() { + let registry = build_registry(dto_roots()); + let result_list = registry + .types_by_id + .values() + .find_map(|type_def| match type_def { + TypeDef::Struct(def) if def.export_name == "IResultList" => Some(def), + _ => None, + }) + .expect("IResultList descriptor"); + + assert_eq!(result_list.generics[0].name, "T"); + assert_eq!(result_list.fields[0].target.typescript, "results"); + assert_eq!( + result_list.fields[0].ty, + TypeRef::vec(TypeRef::GenericParam("T".to_owned())) + ); } } diff --git a/tools/xtask/src/dto_roots.rs b/tools/xtask/src/dto_roots.rs @@ -49,6 +49,10 @@ pub const DTO_PACKAGE_ROOTS: &[DtoPackageRootSet] = &[ package_key: "trade", roots: trade_roots, }, + DtoPackageRootSet { + package_key: "types", + roots: types_roots, + }, ]; pub const MANUAL_DESCRIPTOR_FAMILIES: &[ManualDescriptorFamily] = &[ @@ -170,6 +174,11 @@ pub fn trade_types_module() -> Result<DtoTypesModule, String> { ) } +pub fn types_types_module() -> Result<DtoTypesModule, String> { + let root_set = package_root_set("types").ok_or_else(|| "missing types DTO roots".to_owned())?; + render_registry_types(&root_set.registry(), &DtoRegistryRenderOptions::default()) +} + fn core_roots() -> Vec<RootDescriptor> { radroots_core::dto::dto_roots().into_iter().collect() } @@ -188,6 +197,10 @@ fn trade_roots() -> Vec<RootDescriptor> { radroots_trade_bindings::dto_roots() } +fn types_roots() -> Vec<RootDescriptor> { + radroots_types_bindings::dto_roots() +} + fn core_import_options( registry: &Registry, mut options: DtoRegistryRenderOptions, @@ -484,6 +497,7 @@ mod tests { assert!(package_root_set("events").is_some()); assert!(package_root_set("events_indexed").is_some()); assert!(package_root_set("trade").is_some()); + assert!(package_root_set("types").is_some()); } #[test] diff --git a/tools/xtask/src/output.rs b/tools/xtask/src/output.rs @@ -130,7 +130,7 @@ pub fn package_outputs() -> Result<Vec<PackageOutput>, String> { }, PackageOutput { spec: spec_by_key("types"), - types_ts: Some(TsSource::Module(radroots_types_bindings::types_module())), + types_ts: Some(TsSource::DtoRegistry(dto_roots::types_types_module()?)), types_imports_ts: None, constants_ts: None, kinds_ts: None,