- Added workspace structure to Osiris Cargo.toml - Created osiris-client crate for query operations (GET requests) - Implemented generic get(), list(), query() methods - Added KYC, payment, and communication query modules - Created comprehensive refactoring plan document CQRS Pattern: - Commands (writes) → Supervisor client → Rhai scripts - Queries (reads) → Osiris client → REST API Next steps: - Implement Osiris server with Axum - Restructure SDK client by category (kyc/, payment/, etc.) - Update FreezoneClient to use both supervisor and osiris clients
6.0 KiB
6.0 KiB
Creating New OSIRIS Objects
This guide explains how to create new object types in OSIRIS with automatic indexing and Rhai scripting support.
Step-by-Step Process
1. Create the Object Module
Create a new file in the appropriate directory under src/objects/:
src/objects/legal/for legal objectssrc/objects/money/for financial objectssrc/objects/heroledger/for HeroLedger objects- etc.
2. Define the Object Struct
CRITICAL: The struct MUST derive crate::DeriveObject to automatically implement the Object trait.
use crate::store::BaseData;
use serde::{Deserialize, Serialize};
/// Your object description
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, crate::DeriveObject)]
pub struct YourObject {
/// Base data for object storage (REQUIRED)
pub base_data: BaseData,
/// Your custom fields
pub title: String,
pub status: YourStatus,
// ... other fields
}
Required traits:
Debug- for debuggingClone- required by Object traitSerialize, Deserialize- for JSON serializationPartialEq- for comparisonscrate::DeriveObject- CRITICAL - auto-implements Object trait
Required field:
base_data: BaseData- MUST be present for object storage
3. Implement Constructor and Methods
impl YourObject {
/// Create a new object
pub fn new(id: u32) -> Self {
let base_data = BaseData::with_id(id, String::new());
Self {
base_data,
title: String::new(),
status: YourStatus::default(),
// ... initialize other fields
}
}
/// Fluent builder methods
pub fn title(mut self, title: impl ToString) -> Self {
self.title = title.to_string();
self
}
// ... other methods
}
4. Create Rhai Bindings Module
Create rhai.rs in the same directory:
use ::rhai::plugin::*;
use ::rhai::{CustomType, Dynamic, Engine, EvalAltResult, Module, TypeBuilder};
use super::{YourObject, YourStatus};
/// Register your modules with the Rhai engine
pub fn register_your_modules(parent_module: &mut Module) {
// Register custom types
parent_module.set_custom_type::<YourObject>("YourObject");
parent_module.set_custom_type::<YourStatus>("YourStatus");
// Merge functions
let your_module = exported_module!(rhai_your_module);
parent_module.merge(&your_module);
}
#[export_module]
mod rhai_your_module {
use super::YourObject;
use ::rhai::EvalAltResult;
// Constructor
#[rhai_fn(name = "new_your_object", return_raw)]
pub fn new_your_object(id: i64) -> Result<YourObject, Box<EvalAltResult>> {
Ok(YourObject::new(id as u32))
}
// Builder methods
#[rhai_fn(name = "title", return_raw)]
pub fn set_title(
obj: YourObject,
title: String,
) -> Result<YourObject, Box<EvalAltResult>> {
Ok(obj.title(title))
}
// Getters
#[rhai_fn(name = "title", pure)]
pub fn get_title(obj: &mut YourObject) -> String {
obj.title.clone()
}
}
// CustomType implementations
impl CustomType for YourObject {
fn build(mut builder: TypeBuilder<Self>) {
builder.with_name("YourObject");
}
}
impl CustomType for YourStatus {
fn build(mut builder: TypeBuilder<Self>) {
builder.with_name("YourStatus");
}
}
5. Update Module Exports
In mod.rs of your object category:
pub mod your_object;
pub mod rhai;
pub use your_object::{YourObject, YourStatus};
pub use rhai::register_your_modules;
In src/objects/mod.rs:
pub mod your_category;
pub use your_category::{YourObject, YourStatus};
6. Register in Engine (CRITICAL STEP)
In src/engine.rs, add the save registration in the OsirisPackage definition:
def_package! {
pub OsirisPackage(module) : StandardPackage {
// ... existing registrations ...
// Add your object's save method
FuncRegistration::new("save")
.set_into_module(module, |ctx: &mut OsirisContext, obj: crate::objects::YourObject| ctx.save_object(obj));
// ... existing registrations ...
// Register your modules
register_your_modules(module);
}
}
Also add the import at the top of engine.rs:
use crate::objects::your_category::rhai::register_your_modules;
7. Create Example Script
Create examples/engine/XX_your_object.rhai:
print("=== Your Object Example ===\n");
// Get context
let ctx = get_context(["alice", "bob"]);
// Create object
let obj = new_your_object(1)
.title("Example Title");
print("Object created: " + obj.title());
// Store in context
ctx.save(obj);
print("Object stored");
print("\n=== Example Complete ===");
Checklist
Before considering your object complete, verify:
- Struct derives
crate::DeriveObject - Struct has
base_data: BaseDatafield - Rhai module created with
register_*_modulesfunction - Custom types registered with
set_custom_type - Module exported in
mod.rsfiles - Save method registered in
src/engine.rs - Module registration added to
OsirisPackageinsrc/engine.rs - Example script created and tested
- Example runs successfully with
cargo run --example engine examples/engine/XX_your_object.rhai
Common Mistakes to Avoid
- Forgetting
crate::DeriveObject- Without this, the Object trait won't be implemented - Missing
base_datafield - Required for all storable objects - Not registering save in engine.rs - The save method MUST be in engine.rs, not context.rs
- Not calling
set_custom_type- Rhai won't recognize your type - Not merging the exported module - Your functions won't be available
Example: Contract Object
See the Contract object implementation as a reference:
- Struct:
src/objects/legal/contract.rs - Rhai bindings:
src/objects/legal/rhai.rs - Module exports:
src/objects/legal/mod.rsandsrc/objects/mod.rs - Engine registration:
src/engine.rs(line ~110 and ~138) - Example:
examples/engine/12_contract.rhai