move repos into monorepo

This commit is contained in:
Timur Gordon
2025-11-13 20:44:00 +01:00
commit 4b23e5eb7f
204 changed files with 33737 additions and 0 deletions

View File

@@ -0,0 +1,241 @@
/// Flow Instance
///
/// Represents an active instance of a flow template for a specific entity (e.g., user).
use crate::store::{BaseData, Object, Storable};
use serde::{Deserialize, Serialize};
/// Status of a step in a flow instance
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(rename_all = "lowercase")]
pub enum StepStatus {
#[default]
Pending,
Active,
Completed,
Skipped,
Failed,
}
/// A step instance in a flow
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct StepInstance {
/// Step name (from template)
pub name: String,
/// Current status
pub status: StepStatus,
/// When step was started
pub started_at: Option<u64>,
/// When step was completed
pub completed_at: Option<u64>,
/// Step result data
#[serde(default)]
pub result: std::collections::HashMap<String, String>,
/// Error message if failed
pub error: Option<String>,
}
impl StepInstance {
pub fn new(name: String) -> Self {
Self {
name,
status: StepStatus::Pending,
started_at: None,
completed_at: None,
result: std::collections::HashMap::new(),
error: None,
}
}
}
/// Overall flow status
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(rename_all = "lowercase")]
pub enum FlowStatus {
#[default]
Created,
Running,
Completed,
Failed,
Cancelled,
}
/// Flow Instance - an active execution of a flow template
#[derive(Debug, Clone, Serialize, Deserialize, Default, crate::DeriveObject)]
pub struct FlowInstance {
#[serde(flatten)]
pub base_data: BaseData,
/// Instance name (typically entity_id or unique identifier)
pub name: String,
/// Template name this instance is based on
pub template_name: String,
/// Entity ID this flow is for (e.g., user_id)
pub entity_id: String,
/// Current flow status
pub status: FlowStatus,
/// Step instances
pub steps: Vec<StepInstance>,
/// Current step index
pub current_step: usize,
/// When flow was started
pub started_at: Option<u64>,
/// When flow was completed
pub completed_at: Option<u64>,
/// Instance metadata
#[serde(default)]
pub metadata: std::collections::HashMap<String, String>,
}
impl FlowInstance {
/// Create a new flow instance
pub fn new(id: u32, name: String, template_name: String, entity_id: String) -> Self {
let mut base_data = BaseData::new();
base_data.id = id;
Self {
base_data,
name,
template_name,
entity_id,
status: FlowStatus::Created,
steps: Vec::new(),
current_step: 0,
started_at: None,
completed_at: None,
metadata: std::collections::HashMap::new(),
}
}
/// Initialize steps from template
pub fn init_steps(&mut self, step_names: Vec<String>) {
self.steps = step_names.into_iter().map(StepInstance::new).collect();
self.base_data.update_modified();
}
/// Start the flow
pub fn start(&mut self) {
// Initialize default steps if none exist
if self.steps.is_empty() {
// Create default steps based on common workflow
self.steps = vec![
StepInstance::new("registration".to_string()),
StepInstance::new("kyc".to_string()),
StepInstance::new("email".to_string()),
];
}
self.status = FlowStatus::Running;
self.started_at = Some(Self::now());
// Start first step if exists
if let Some(step) = self.steps.first_mut() {
step.status = StepStatus::Active;
step.started_at = Some(Self::now());
}
self.base_data.update_modified();
}
/// Complete a step by name
pub fn complete_step(&mut self, step_name: &str) -> Result<(), String> {
let step_idx = self.steps.iter().position(|s| s.name == step_name)
.ok_or_else(|| format!("Step '{}' not found", step_name))?;
let step = &mut self.steps[step_idx];
step.status = StepStatus::Completed;
step.completed_at = Some(Self::now());
// Move to next step if this was the current step
if step_idx == self.current_step {
self.current_step += 1;
// Start next step if exists
if let Some(next_step) = self.steps.get_mut(self.current_step) {
next_step.status = StepStatus::Active;
next_step.started_at = Some(Self::now());
} else {
// All steps completed
self.status = FlowStatus::Completed;
self.completed_at = Some(Self::now());
}
}
self.base_data.update_modified();
Ok(())
}
/// Fail a step
pub fn fail_step(&mut self, step_name: &str, error: String) -> Result<(), String> {
let step = self.steps.iter_mut()
.find(|s| s.name == step_name)
.ok_or_else(|| format!("Step '{}' not found", step_name))?;
step.status = StepStatus::Failed;
step.error = Some(error);
step.completed_at = Some(Self::now());
self.status = FlowStatus::Failed;
self.base_data.update_modified();
Ok(())
}
/// Skip a step
pub fn skip_step(&mut self, step_name: &str) -> Result<(), String> {
let step = self.steps.iter_mut()
.find(|s| s.name == step_name)
.ok_or_else(|| format!("Step '{}' not found", step_name))?;
step.status = StepStatus::Skipped;
step.completed_at = Some(Self::now());
self.base_data.update_modified();
Ok(())
}
/// Get current step
pub fn get_current_step(&self) -> Option<&StepInstance> {
self.steps.get(self.current_step)
}
/// Get step by name
pub fn get_step(&self, name: &str) -> Option<&StepInstance> {
self.steps.iter().find(|s| s.name == name)
}
/// Set step result data
pub fn set_step_result(&mut self, step_name: &str, key: String, value: String) -> Result<(), String> {
let step = self.steps.iter_mut()
.find(|s| s.name == step_name)
.ok_or_else(|| format!("Step '{}' not found", step_name))?;
step.result.insert(key, value);
self.base_data.update_modified();
Ok(())
}
/// Add metadata
pub fn add_metadata(&mut self, key: String, value: String) {
self.metadata.insert(key, value);
self.base_data.update_modified();
}
/// Helper to get current timestamp
fn now() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs()
}
}

View File

@@ -0,0 +1,10 @@
/// Flow Module
///
/// Provides workflow/flow management with templates and instances.
pub mod template;
pub mod instance;
pub mod rhai;
pub use template::{FlowTemplate, FlowStep};
pub use instance::{FlowInstance, FlowStatus, StepStatus, StepInstance};

View File

@@ -0,0 +1,183 @@
/// Rhai bindings for Flow objects
use ::rhai::plugin::*;
use ::rhai::{CustomType, Dynamic, Engine, EvalAltResult, Module, TypeBuilder};
use super::template::{FlowTemplate, FlowStep};
use super::instance::{FlowInstance, FlowStatus, StepStatus};
// ============================================================================
// Flow Template Module
// ============================================================================
type RhaiFlowTemplate = FlowTemplate;
#[export_module]
mod rhai_flow_template_module {
use super::RhaiFlowTemplate;
#[rhai_fn(name = "new_flow", return_raw)]
pub fn new_flow() -> Result<RhaiFlowTemplate, Box<EvalAltResult>> {
Ok(FlowTemplate::new(0))
}
#[rhai_fn(name = "name", return_raw)]
pub fn set_name(
template: &mut RhaiFlowTemplate,
name: String,
) -> Result<RhaiFlowTemplate, Box<EvalAltResult>> {
let owned = std::mem::take(template);
*template = owned.name(name);
Ok(template.clone())
}
#[rhai_fn(name = "description", return_raw)]
pub fn set_description(
template: &mut RhaiFlowTemplate,
description: String,
) -> Result<RhaiFlowTemplate, Box<EvalAltResult>> {
let owned = std::mem::take(template);
*template = owned.description(description);
Ok(template.clone())
}
#[rhai_fn(name = "add_step", return_raw)]
pub fn add_step(
template: &mut RhaiFlowTemplate,
name: String,
description: String,
) -> Result<(), Box<EvalAltResult>> {
template.add_step(name, description);
Ok(())
}
#[rhai_fn(name = "build", return_raw)]
pub fn build(
template: &mut RhaiFlowTemplate,
) -> Result<RhaiFlowTemplate, Box<EvalAltResult>> {
Ok(template.clone())
}
// Getters
#[rhai_fn(name = "get_name")]
pub fn get_name(template: &mut RhaiFlowTemplate) -> String {
template.name.clone()
}
#[rhai_fn(name = "get_description")]
pub fn get_description(template: &mut RhaiFlowTemplate) -> String {
template.description.clone()
}
}
// ============================================================================
// Flow Instance Module
// ============================================================================
type RhaiFlowInstance = FlowInstance;
#[export_module]
mod rhai_flow_instance_module {
use super::RhaiFlowInstance;
#[rhai_fn(name = "new_flow_instance", return_raw)]
pub fn new_instance(
name: String,
template_name: String,
entity_id: String,
) -> Result<RhaiFlowInstance, Box<EvalAltResult>> {
Ok(FlowInstance::new(0, name, template_name, entity_id))
}
#[rhai_fn(name = "start", return_raw)]
pub fn start(
instance: &mut RhaiFlowInstance,
) -> Result<(), Box<EvalAltResult>> {
instance.start();
Ok(())
}
#[rhai_fn(name = "complete_step", return_raw)]
pub fn complete_step(
instance: &mut RhaiFlowInstance,
step_name: String,
) -> Result<(), Box<EvalAltResult>> {
instance.complete_step(&step_name)
.map_err(|e| e.into())
}
#[rhai_fn(name = "fail_step", return_raw)]
pub fn fail_step(
instance: &mut RhaiFlowInstance,
step_name: String,
error: String,
) -> Result<(), Box<EvalAltResult>> {
instance.fail_step(&step_name, error)
.map_err(|e| e.into())
}
#[rhai_fn(name = "skip_step", return_raw)]
pub fn skip_step(
instance: &mut RhaiFlowInstance,
step_name: String,
) -> Result<(), Box<EvalAltResult>> {
instance.skip_step(&step_name)
.map_err(|e| e.into())
}
// Getters
#[rhai_fn(name = "get_name")]
pub fn get_name(instance: &mut RhaiFlowInstance) -> String {
instance.name.clone()
}
#[rhai_fn(name = "get_template_name")]
pub fn get_template_name(instance: &mut RhaiFlowInstance) -> String {
instance.template_name.clone()
}
#[rhai_fn(name = "get_entity_id")]
pub fn get_entity_id(instance: &mut RhaiFlowInstance) -> String {
instance.entity_id.clone()
}
#[rhai_fn(name = "get_status")]
pub fn get_status(instance: &mut RhaiFlowInstance) -> String {
format!("{:?}", instance.status)
}
}
// ============================================================================
// Registration Functions
// ============================================================================
/// Register Flow modules into a Rhai Module (for use in packages)
pub fn register_flow_modules(parent_module: &mut Module) {
// Register custom types
parent_module.set_custom_type::<FlowTemplate>("FlowTemplate");
parent_module.set_custom_type::<FlowInstance>("FlowInstance");
// Merge flow template functions
let template_module = exported_module!(rhai_flow_template_module);
parent_module.merge(&template_module);
// Merge flow instance functions
let instance_module = exported_module!(rhai_flow_instance_module);
parent_module.merge(&instance_module);
}
// ============================================================================
// CustomType Implementations
// ============================================================================
impl CustomType for FlowTemplate {
fn build(mut builder: TypeBuilder<Self>) {
builder.with_name("FlowTemplate");
}
}
impl CustomType for FlowInstance {
fn build(mut builder: TypeBuilder<Self>) {
builder.with_name("FlowInstance");
}
}

View File

@@ -0,0 +1,117 @@
/// Flow Template
///
/// Defines a reusable workflow template with steps that can be instantiated multiple times.
use crate::store::{BaseData, Object, Storable};
use serde::{Deserialize, Serialize};
/// A step in a flow template
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct FlowStep {
/// Step name/identifier
pub name: String,
/// Step description
pub description: String,
/// Steps that must be completed before this step can start
#[serde(default)]
pub dependencies: Vec<String>,
}
impl FlowStep {
pub fn new(name: String, description: String) -> Self {
Self {
name,
description,
dependencies: Vec::new(),
}
}
pub fn with_dependencies(mut self, dependencies: Vec<String>) -> Self {
self.dependencies = dependencies;
self
}
pub fn add_dependency(&mut self, dependency: String) {
self.dependencies.push(dependency);
}
}
/// Flow Template - defines a reusable workflow
#[derive(Debug, Clone, Serialize, Deserialize, Default, crate::DeriveObject)]
pub struct FlowTemplate {
#[serde(flatten)]
pub base_data: BaseData,
/// Template name
pub name: String,
/// Template description
pub description: String,
/// Ordered list of steps
pub steps: Vec<FlowStep>,
/// Template metadata
#[serde(default)]
pub metadata: std::collections::HashMap<String, String>,
}
impl FlowTemplate {
/// Create a new flow template
pub fn new(id: u32) -> Self {
let mut base_data = BaseData::new();
base_data.id = id;
Self {
base_data,
name: String::new(),
description: String::new(),
steps: Vec::new(),
metadata: std::collections::HashMap::new(),
}
}
/// Builder: Set name
pub fn name(mut self, name: String) -> Self {
self.name = name;
self.base_data.update_modified();
self
}
/// Builder: Set description
pub fn description(mut self, description: String) -> Self {
self.description = description;
self.base_data.update_modified();
self
}
/// Add a step to the template
pub fn add_step(&mut self, name: String, description: String) {
self.steps.push(FlowStep::new(name, description));
self.base_data.update_modified();
}
/// Add a step with dependencies
pub fn add_step_with_dependencies(&mut self, name: String, description: String, dependencies: Vec<String>) {
let step = FlowStep::new(name, description).with_dependencies(dependencies);
self.steps.push(step);
self.base_data.update_modified();
}
/// Get step by name
pub fn get_step(&self, name: &str) -> Option<&FlowStep> {
self.steps.iter().find(|s| s.name == name)
}
/// Add metadata
pub fn add_metadata(&mut self, key: String, value: String) {
self.metadata.insert(key, value);
self.base_data.update_modified();
}
/// Build (for fluent API compatibility)
pub fn build(self) -> Self {
self
}
}