@@ -89,6 +89,13 @@ pub enum RawModuleDefV10Section {
8989
9090 /// Names provided explicitly by the user that do not follow from the case conversion policy.
9191 ExplicitNames ( ExplicitNames ) ,
92+
93+ /// Outbox table definitions.
94+ ///
95+ /// Each entry marks a table as an outbox table for inter-database communication,
96+ /// specifying the remote reducer to call and optionally a local callback reducer.
97+ /// New variant — old modules simply omit this section; old servers skip it.
98+ Outboxes ( Vec < RawOutboxDefV10 > ) ,
9299}
93100
94101#[ derive( Debug , Clone , Copy , Default , SpacetimeType ) ]
@@ -264,6 +271,31 @@ pub struct RawColumnDefaultValueV10 {
264271 pub value : Box < [ u8 ] > ,
265272}
266273
274+ /// Marks a table as an outbox table for inter-database communication.
275+ ///
276+ /// The table must have:
277+ /// - Col 0: `u64` with `#[primary_key] #[auto_inc]` — the row ID stored in `st_msg_id`.
278+ /// - Col 1: `Identity` (encoded as U256) — the target database identity.
279+ /// - Remaining cols: arguments forwarded verbatim to the remote reducer.
280+ ///
281+ /// The `remote_reducer` is the name of the reducer to call on the target database.
282+ /// If `on_result_reducer` is set, that local reducer is called when delivery completes,
283+ /// with signature `fn on_result(ctx: &ReducerContext, request: OutboxRow, result: Result<(), String>)`.
284+ #[ derive( Debug , Clone , SpacetimeType ) ]
285+ #[ sats( crate = crate ) ]
286+ #[ cfg_attr( feature = "test" , derive( PartialEq , Eq , PartialOrd , Ord ) ) ]
287+ pub struct RawOutboxDefV10 {
288+ /// The `source_name` of the outbox table (as given in `accessor = ...`).
289+ pub table_name : RawIdentifier ,
290+
291+ /// The name of the reducer to call on the target database.
292+ pub remote_reducer : RawIdentifier ,
293+
294+ /// The name of the local reducer to call with the delivery result.
295+ /// If `None`, no callback is made after delivery.
296+ pub on_result_reducer : Option < RawIdentifier > ,
297+ }
298+
267299/// A reducer definition.
268300#[ derive( Debug , Clone , SpacetimeType ) ]
269301#[ sats( crate = crate ) ]
@@ -584,6 +616,14 @@ impl RawModuleDefV10 {
584616 . expect ( "Tables section must exist for tests" )
585617 }
586618
619+ /// Get the outboxes section, if present.
620+ pub fn outboxes ( & self ) -> Option < & Vec < RawOutboxDefV10 > > {
621+ self . sections . iter ( ) . find_map ( |s| match s {
622+ RawModuleDefV10Section :: Outboxes ( outboxes) => Some ( outboxes) ,
623+ _ => None ,
624+ } )
625+ }
626+
587627 // Get the row-level security section, if present.
588628 pub fn row_level_security ( & self ) -> Option < & Vec < RawRowLevelSecurityDefV10 > > {
589629 self . sections . iter ( ) . find_map ( |s| match s {
@@ -785,6 +825,24 @@ impl RawModuleDefV10Builder {
785825 }
786826 }
787827
828+ /// Get mutable access to the outboxes section, creating it if missing.
829+ fn outboxes_mut ( & mut self ) -> & mut Vec < RawOutboxDefV10 > {
830+ let idx = self
831+ . module
832+ . sections
833+ . iter ( )
834+ . position ( |s| matches ! ( s, RawModuleDefV10Section :: Outboxes ( _) ) )
835+ . unwrap_or_else ( || {
836+ self . module . sections . push ( RawModuleDefV10Section :: Outboxes ( Vec :: new ( ) ) ) ;
837+ self . module . sections . len ( ) - 1
838+ } ) ;
839+
840+ match & mut self . module . sections [ idx] {
841+ RawModuleDefV10Section :: Outboxes ( outboxes) => outboxes,
842+ _ => unreachable ! ( "Just ensured Outboxes section exists" ) ,
843+ }
844+ }
845+
788846 /// Get mutable access to the case conversion policy, creating it if missing.
789847 fn explicit_names_mut ( & mut self ) -> & mut ExplicitNames {
790848 let idx = self
@@ -1040,6 +1098,24 @@ impl RawModuleDefV10Builder {
10401098 } ) ;
10411099 }
10421100
1101+ /// Register an outbox table for inter-database communication.
1102+ ///
1103+ /// `table_name` is the `source_name` of the table (i.e. `accessor =` value).
1104+ /// `remote_reducer` is the reducer to call on the target database.
1105+ /// `on_result_reducer` is an optional local reducer called with the delivery result.
1106+ pub fn add_outbox (
1107+ & mut self ,
1108+ table_name : impl Into < RawIdentifier > ,
1109+ remote_reducer : impl Into < RawIdentifier > ,
1110+ on_result_reducer : Option < impl Into < RawIdentifier > > ,
1111+ ) {
1112+ self . outboxes_mut ( ) . push ( RawOutboxDefV10 {
1113+ table_name : table_name. into ( ) ,
1114+ remote_reducer : remote_reducer. into ( ) ,
1115+ on_result_reducer : on_result_reducer. map ( Into :: into) ,
1116+ } ) ;
1117+ }
1118+
10431119 /// Add a row-level security policy to the module.
10441120 ///
10451121 /// The `sql` expression should be a valid SQL expression that will be used to filter rows.
0 commit comments