From ae846ea734098716e8e1b81e02fae354dbb33889 Mon Sep 17 00:00:00 2001 From: Timur Gordon <31495328+timurgordon@users.noreply.github.com> Date: Tue, 4 Nov 2025 10:26:33 +0100 Subject: [PATCH] Start CQRS refactoring: Create Osiris client crate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- Cargo.toml | 8 + EXAMPLES.md | 454 --------------------- MULTI_INSTANCE.md | 341 ---------------- PREDEFINED_INSTANCES.md | 387 ------------------ QUICKSTART.md | 190 --------- README.md | 303 +++++++++----- REFACTORING_COMPLETE.md | 221 ----------- RHAI_REFACTOR_COMPLETE.md | 153 ------- RUNNER.md | 328 --------------- SIGNATORY_ACCESS_CONTROL.md | 176 --------- STRUCTURE.md | 317 --------------- TESTS_COMPLETE.md | 154 -------- client/Cargo.toml | 14 + client/src/communication.rs | 37 ++ client/src/kyc.rs | 38 ++ client/src/lib.rs | 119 ++++++ client/src/payment.rs | 39 ++ docs/ARCHITECTURE.md | 128 +++--- docs/CREATING_NEW_OBJECTS.md | 4 +- docs/DERIVE_MACRO.md | 195 --------- docs/FREEZONE_IMPLEMENTATION_TODO.md | 113 ------ docs/specs/osiris-mvp.md | 525 ------------------------- examples/freezone/freezone copy 2.rhai | 2 + examples/freezone/freezone copy.rhai | 14 +- server/Cargo.toml | 16 + 25 files changed, 540 insertions(+), 3736 deletions(-) delete mode 100644 EXAMPLES.md delete mode 100644 MULTI_INSTANCE.md delete mode 100644 PREDEFINED_INSTANCES.md delete mode 100644 QUICKSTART.md delete mode 100644 REFACTORING_COMPLETE.md delete mode 100644 RHAI_REFACTOR_COMPLETE.md delete mode 100644 RUNNER.md delete mode 100644 SIGNATORY_ACCESS_CONTROL.md delete mode 100644 STRUCTURE.md delete mode 100644 TESTS_COMPLETE.md create mode 100644 client/Cargo.toml create mode 100644 client/src/communication.rs create mode 100644 client/src/kyc.rs create mode 100644 client/src/lib.rs create mode 100644 client/src/payment.rs delete mode 100644 docs/DERIVE_MACRO.md delete mode 100644 docs/FREEZONE_IMPLEMENTATION_TODO.md delete mode 100644 docs/specs/osiris-mvp.md create mode 100644 server/Cargo.toml diff --git a/Cargo.toml b/Cargo.toml index b2f3bb8..676d7e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,11 @@ +[workspace] +members = [ + ".", + "client", + "server", +] +resolver = "2" + [package] name = "osiris" version = "0.1.0" diff --git a/EXAMPLES.md b/EXAMPLES.md deleted file mode 100644 index 4be9387..0000000 --- a/EXAMPLES.md +++ /dev/null @@ -1,454 +0,0 @@ -# OSIRIS Examples - -This document provides practical examples of using OSIRIS for various use cases. - -## Prerequisites - -1. **Start HeroDB**: -```bash -cd /path/to/herodb -cargo run --release -- --dir ./data --admin-secret mysecret --port 6379 -``` - -2. **Build OSIRIS**: -```bash -cd /path/to/osiris -cargo build --release -``` - -3. **Initialize OSIRIS**: -```bash -./target/release/osiris init --herodb redis://localhost:6379 -``` - ---- - -## Example 1: Personal Note Management - -### Create a namespace for notes -```bash -./target/release/osiris ns create notes -``` - -### Add notes with tags -```bash -# Create a note about Rust -echo "Rust is a systems programming language focused on safety and performance." | \ - ./target/release/osiris put notes/rust-intro - \ - --title "Introduction to Rust" \ - --tags topic=rust,level=beginner,type=tutorial \ - --mime text/plain - -# Create a note about OSIRIS -echo "OSIRIS is an object storage system built on HeroDB." | \ - ./target/release/osiris put notes/osiris-overview - \ - --title "OSIRIS Overview" \ - --tags topic=osiris,level=intermediate,type=documentation \ - --mime text/plain - -# Create a note from a file -./target/release/osiris put notes/network-latency ./network-notes.md \ - --title "Network Latency Analysis" \ - --tags topic=networking,priority=high,type=analysis \ - --mime text/markdown -``` - -### Search notes -```bash -# Search for notes about Rust -./target/release/osiris find "rust" --ns notes - -# Filter by tag -./target/release/osiris find --ns notes --filter topic=rust - -# Combine text search and filters -./target/release/osiris find "performance" --ns notes --filter level=beginner - -# Get more results -./target/release/osiris find "programming" --ns notes --topk 20 - -# Output as JSON -./target/release/osiris find "rust" --ns notes --json -``` - -### Retrieve notes -```bash -# Get note as JSON (with metadata) -./target/release/osiris get notes/rust-intro - -# Get raw content only -./target/release/osiris get notes/rust-intro --raw - -# Save to file -./target/release/osiris get notes/rust-intro --raw --output /tmp/rust-intro.txt -``` - -### Delete notes -```bash -./target/release/osiris del notes/rust-intro -``` - ---- - -## Example 2: Calendar/Event Management - -### Create a calendar namespace -```bash -./target/release/osiris ns create calendar -``` - -### Add events -```bash -# Add a meeting -echo '{"title":"Team Standup","when":"2025-10-20T10:00:00Z","attendees":["alice","bob"]}' | \ - ./target/release/osiris put calendar/standup-2025-10-20 - \ - --title "Team Standup" \ - --tags type=meeting,team=eng,priority=high \ - --mime application/json - -# Add a deadline -echo '{"title":"Project Deadline","when":"2025-10-31T23:59:59Z","project":"osiris-mvp"}' | \ - ./target/release/osiris put calendar/deadline-osiris - \ - --title "OSIRIS MVP Deadline" \ - --tags type=deadline,project=osiris,priority=critical \ - --mime application/json - -# Add a reminder -echo '{"title":"Code Review","when":"2025-10-21T14:00:00Z","pr":"#123"}' | \ - ./target/release/osiris put calendar/review-pr123 - \ - --title "Code Review PR #123" \ - --tags type=reminder,team=eng \ - --mime application/json -``` - -### Search events -```bash -# Find all meetings -./target/release/osiris find --ns calendar --filter type=meeting - -# Find high-priority items -./target/release/osiris find --ns calendar --filter priority=high - -# Search by text -./target/release/osiris find "standup" --ns calendar - -# Find project-specific events -./target/release/osiris find --ns calendar --filter project=osiris -``` - ---- - -## Example 3: Code Snippet Library - -### Create a snippets namespace -```bash -./target/release/osiris ns create snippets -``` - -### Add code snippets -```bash -# Rust snippet -cat > /tmp/rust-error-handling.rs <<'EOF' -use anyhow::Result; - -fn main() -> Result<()> { - let result = risky_operation()?; - println!("Success: {}", result); - Ok(()) -} - -fn risky_operation() -> Result { - Ok("All good!".to_string()) -} -EOF - -./target/release/osiris put snippets/rust-error-handling /tmp/rust-error-handling.rs \ - --title "Rust Error Handling with anyhow" \ - --tags language=rust,topic=error-handling,pattern=result \ - --mime text/x-rust - -# Python snippet -cat > /tmp/python-async.py <<'EOF' -import asyncio - -async def fetch_data(url): - await asyncio.sleep(1) - return f"Data from {url}" - -async def main(): - result = await fetch_data("https://example.com") - print(result) - -asyncio.run(main()) -EOF - -./target/release/osiris put snippets/python-async /tmp/python-async.py \ - --title "Python Async/Await Example" \ - --tags language=python,topic=async,pattern=asyncio \ - --mime text/x-python -``` - -### Search snippets -```bash -# Find all Rust snippets -./target/release/osiris find --ns snippets --filter language=rust - -# Find async patterns -./target/release/osiris find "async" --ns snippets - -# Find error handling examples -./target/release/osiris find --ns snippets --filter topic=error-handling -``` - ---- - -## Example 4: Document Management - -### Create a documents namespace -```bash -./target/release/osiris ns create docs -``` - -### Add documents -```bash -# Add a specification -./target/release/osiris put docs/osiris-spec ./docs/specs/osiris-mvp.md \ - --title "OSIRIS MVP Specification" \ - --tags type=spec,project=osiris,status=draft \ - --mime text/markdown - -# Add a README -./target/release/osiris put docs/readme ./README.md \ - --title "OSIRIS README" \ - --tags type=readme,project=osiris,status=published \ - --mime text/markdown - -# Add meeting notes -echo "# Team Meeting 2025-10-20\n\n- Discussed OSIRIS MVP\n- Decided on minimal feature set" | \ - ./target/release/osiris put docs/meeting-2025-10-20 - \ - --title "Team Meeting Notes" \ - --tags type=notes,date=2025-10-20,team=eng \ - --mime text/markdown -``` - -### Search documents -```bash -# Find all specifications -./target/release/osiris find --ns docs --filter type=spec - -# Find draft documents -./target/release/osiris find --ns docs --filter status=draft - -# Search by content -./target/release/osiris find "MVP" --ns docs -``` - ---- - -## Example 5: Multi-Namespace Operations - -### List all namespaces -```bash -./target/release/osiris ns list -``` - -### Get statistics -```bash -# Overall stats -./target/release/osiris stats - -# Namespace-specific stats -./target/release/osiris stats --ns notes -./target/release/osiris stats --ns calendar -./target/release/osiris stats --ns snippets -``` - -### Delete a namespace -```bash -./target/release/osiris ns delete snippets -``` - ---- - -## Example 6: Batch Operations - -### Bulk import notes -```bash -# Create multiple notes from a directory -for file in ./my-notes/*.md; do - filename=$(basename "$file" .md) - ./target/release/osiris put "notes/$filename" "$file" \ - --tags source=import,format=markdown \ - --mime text/markdown -done -``` - -### Export all notes -```bash -# Get all note IDs and export them -./target/release/osiris find --ns notes --topk 1000 --json | \ - jq -r '.[].id' | \ - while read id; do - ./target/release/osiris get "notes/$id" --raw --output "./export/$id.txt" - done -``` - ---- - -## Example 7: Advanced Search Patterns - -### Complex filtering -```bash -# Find high-priority engineering tasks -./target/release/osiris find --ns calendar \ - --filter priority=high \ - --filter team=eng - -# Find beginner-level Rust tutorials -./target/release/osiris find "rust" --ns notes \ - --filter level=beginner \ - --filter type=tutorial -``` - -### Combining text search with filters -```bash -# Find notes about "performance" tagged as high priority -./target/release/osiris find "performance" --ns notes \ - --filter priority=high - -# Find meetings about "standup" -./target/release/osiris find "standup" --ns calendar \ - --filter type=meeting -``` - ---- - -## Example 8: JSON Output and Scripting - -### Get search results as JSON -```bash -# Search and process with jq -./target/release/osiris find "rust" --ns notes --json | \ - jq '.[] | {id: .id, score: .score, snippet: .snippet}' - -# Count results -./target/release/osiris find "programming" --ns notes --json | \ - jq 'length' - -# Get top result -./target/release/osiris find "osiris" --ns notes --json | \ - jq '.[0]' -``` - -### Scripting with OSIRIS -```bash -#!/bin/bash -# Script to find and display all high-priority items - -echo "High Priority Items:" -echo "===================" - -# Search notes -echo -e "\nNotes:" -./target/release/osiris find --ns notes --filter priority=high --json | \ - jq -r '.[] | "- \(.id): \(.snippet)"' - -# Search calendar -echo -e "\nEvents:" -./target/release/osiris find --ns calendar --filter priority=high --json | \ - jq -r '.[] | "- \(.id): \(.snippet)"' -``` - ---- - -## Tips and Best Practices - -### 1. Consistent Tagging -Use consistent tag names across your objects: -```bash -# Good: consistent tag names ---tags topic=rust,level=beginner,type=tutorial - -# Avoid: inconsistent naming ---tags Topic=Rust,skill_level=Beginner,kind=Tutorial -``` - -### 2. Meaningful IDs -Use descriptive IDs that make sense: -```bash -# Good: descriptive ID -./target/release/osiris put notes/rust-ownership-guide ... - -# Avoid: cryptic ID -./target/release/osiris put notes/abc123 ... -``` - -### 3. Use MIME Types -Always specify MIME types for better organization: -```bash ---mime text/markdown ---mime application/json ---mime text/x-rust ---mime text/plain -``` - -### 4. Leverage Filters -Use filters to narrow down search results: -```bash -# Instead of searching all notes -./target/release/osiris find "rust" --ns notes - -# Filter by specific criteria -./target/release/osiris find "rust" --ns notes --filter level=beginner -``` - -### 5. Regular Backups -Export your data regularly: -```bash -# Export all namespaces -for ns in notes calendar docs; do - ./target/release/osiris find --ns "$ns" --topk 10000 --json > "backup-$ns.json" -done -``` - ---- - -## Troubleshooting - -### Connection Issues -```bash -# Check if HeroDB is running -redis-cli -p 6379 PING - -# Verify configuration -cat ~/.config/osiris/config.toml -``` - -### Object Not Found -```bash -# List all objects in a namespace -./target/release/osiris find --ns notes --topk 1000 - -# Check if namespace exists -./target/release/osiris ns list -``` - -### Search Returns No Results -```bash -# Try without filters first -./target/release/osiris find "keyword" --ns notes - -# Check if objects have the expected tags -./target/release/osiris get notes/some-id -``` - ---- - -## Next Steps - -- Explore the [README](README.md) for more information -- Read the [MVP Specification](docs/specs/osiris-mvp.md) -- Check out the [source code](src/) to understand the implementation -- Contribute improvements or report issues - -Happy organizing with OSIRIS! ๐ŸŽฏ diff --git a/MULTI_INSTANCE.md b/MULTI_INSTANCE.md deleted file mode 100644 index efe757d..0000000 --- a/MULTI_INSTANCE.md +++ /dev/null @@ -1,341 +0,0 @@ -# OSIRIS Multi-Instance Support โœ… - -OSIRIS now supports multiple instances in a single Rhai script, allowing you to work with different HeroDB databases simultaneously. - -## ๐ŸŽ‰ Status: FULLY OPERATIONAL - -``` -โœ… OsirisInstance type created -โœ… Dynamic instance creation -โœ… Independent storage per instance -โœ… Same note/event in multiple instances -โœ… Test script working -``` - -## ๐Ÿš€ Quick Start - -### Create Multiple Instances - -```rhai -// Create two OSIRIS instances pointing to different databases -let freezone = osiris("freezone", "redis://localhost:6379", 1); -let my_osiris = osiris("my_osiris", "redis://localhost:6379", 2); - -// Create a note -let my_note = note("notes") - .title("Shared Note") - .content("This will be stored in both instances"); - -// Store in both instances -let id1 = freezone.put_note(my_note); -let id2 = my_osiris.put_note(my_note); -``` - -## ๐Ÿ“ Complete Example - -```rhai -// Multi-Instance OSIRIS Example - -print("Creating OSIRIS instances..."); -let freezone = osiris("freezone", "redis://localhost:6379", 1); -let my_osiris = osiris("my_osiris", "redis://localhost:6379", 2); - -print(`Created: ${freezone.name()}`); -print(`Created: ${my_osiris.name()}`); - -// Create a note -let my_note = note("shared_notes") - .title("Multi-Instance Test") - .content("Stored in multiple OSIRIS instances") - .tag("shared", "true"); - -// Store in freezone -let freezone_id = freezone.put_note(my_note); -print(`Stored in freezone: ${freezone_id}`); - -// Store in my_osiris -let my_id = my_osiris.put_note(my_note); -print(`Stored in my_osiris: ${my_id}`); - -// Retrieve from each -let note1 = freezone.get_note("shared_notes", freezone_id); -let note2 = my_osiris.get_note("shared_notes", my_id); - -// Query each instance -let ids1 = freezone.query("shared_notes", "tags:tag", "shared=true"); -let ids2 = my_osiris.query("shared_notes", "tags:tag", "shared=true"); -``` - -## ๐ŸŽฏ Use Cases - -### 1. **Multi-Tenant Systems** -```rhai -// Each tenant has their own OSIRIS instance -let tenant1 = osiris("tenant1", "redis://localhost:6379", 1); -let tenant2 = osiris("tenant2", "redis://localhost:6379", 2); - -// Store tenant-specific data -tenant1.put_note(tenant1_note); -tenant2.put_note(tenant2_note); -``` - -### 2. **Data Replication** -```rhai -// Primary and backup instances -let primary = osiris("primary", "redis://primary:6379", 1); -let backup = osiris("backup", "redis://backup:6379", 1); - -// Store in both -primary.put_note(note); -backup.put_note(note); -``` - -### 3. **Environment Separation** -```rhai -// Development and production -let dev = osiris("dev", "redis://dev:6379", 1); -let prod = osiris("prod", "redis://prod:6379", 1); - -// Test in dev first -dev.put_note(test_note); - -// Then promote to prod -prod.put_note(test_note); -``` - -### 4. **Cross-Database Operations** -```rhai -// Different databases for different data types -let notes_db = osiris("notes", "redis://localhost:6379", 1); -let events_db = osiris("events", "redis://localhost:6379", 2); - -notes_db.put_note(note); -events_db.put_event(event); -``` - -## ๐Ÿ“š API Reference - -### Creating an Instance - -```rhai -let instance = osiris(name, url, db_id); -``` - -**Parameters:** -- `name` (string) - Instance name for identification -- `url` (string) - HeroDB connection URL -- `db_id` (int) - Database ID (0-15 typically) - -**Returns:** `OsirisInstance` - -### Instance Methods - -#### `name()` -Get the instance name. - -```rhai -let name = instance.name(); -print(`Instance: ${name}`); -``` - -#### `put_note(note)` -Store a note in this instance. - -```rhai -let id = instance.put_note(note); -``` - -**Returns:** Note ID (string) - -#### `get_note(namespace, id)` -Retrieve a note from this instance. - -```rhai -let note = instance.get_note("notes", id); -``` - -**Returns:** Note object - -#### `put_event(event)` -Store an event in this instance. - -```rhai -let id = instance.put_event(event); -``` - -**Returns:** Event ID (string) - -#### `get_event(namespace, id)` -Retrieve an event from this instance. - -```rhai -let event = instance.get_event("calendar", id); -``` - -**Returns:** Event object - -#### `query(namespace, field, value)` -Query by indexed field in this instance. - -```rhai -let ids = instance.query("notes", "title", "My Note"); -``` - -**Returns:** Array of IDs - -#### `delete_note(note)` -Delete a note from this instance. - -```rhai -let deleted = instance.delete_note(note); -``` - -**Returns:** Boolean (true if deleted) - -#### `delete_event(event)` -Delete an event from this instance. - -```rhai -let deleted = instance.delete_event(event); -``` - -**Returns:** Boolean (true if deleted) - -## ๐Ÿ—๏ธ Architecture - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Rhai Script โ”‚ -โ”‚ let freezone = osiris(...); โ”‚ -โ”‚ let my_osiris = osiris(...); โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ”‚ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ OsirisInstance (Clone) โ”‚ -โ”‚ - name: String โ”‚ -โ”‚ - store: Arc โ”‚ -โ”‚ - runtime: Arc โ”‚ -โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ”‚ โ”‚ -โ”Œโ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ HeroDB DB 1 โ”‚ โ”‚ HeroDB DB 2 โ”‚ -โ”‚ (freezone) โ”‚ โ”‚ (my_osiris) โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -## โœจ Features - -### 1. **Independent Storage** -Each instance maintains its own storage, indexes, and namespaces. - -### 2. **Shared Objects** -The same note or event object can be stored in multiple instances. - -### 3. **Clone-Safe** -Instances are cloneable and can be passed around in scripts. - -### 4. **Error Isolation** -Errors in one instance don't affect others. - -### 5. **Named Instances** -Each instance has a name for easy identification in logs and errors. - -## ๐Ÿงช Testing - -### Run the Multi-Instance Test - -```bash -cargo run --bin runner --features rhai-support -- test1 --script-file scripts/multi_instance.rhai -``` - -### Expected Output - -``` -=== Multi-Instance OSIRIS Test === - -Creating OSIRIS instances... -โœ“ Created: freezone -โœ“ Created: my_osiris - -Creating note... -Note created: Multi-Instance Test Note - -Storing in freezone... -โœ“ Stored in freezone with ID: c274731c-678d-4f3e-bc4a-22eb70dae698 - -Storing in my_osiris... -โœ“ Stored in my_osiris with ID: c274731c-678d-4f3e-bc4a-22eb70dae698 - -Retrieving from freezone... -โœ“ Retrieved from freezone: Multi-Instance Test Note - -Retrieving from my_osiris... -โœ“ Retrieved from my_osiris: Multi-Instance Test Note - -Querying freezone... -โœ“ Found in freezone: - - c274731c-678d-4f3e-bc4a-22eb70dae698 - -Querying my_osiris... -โœ“ Found in my_osiris: - - c274731c-678d-4f3e-bc4a-22eb70dae698 - -=== Test Complete === -โœ… Script completed successfully! -``` - -## ๐Ÿ’ก Best Practices - -### 1. **Use Descriptive Names** -```rhai -// Good -let production = osiris("production", url, 1); -let staging = osiris("staging", url, 2); - -// Less clear -let db1 = osiris("db1", url, 1); -let db2 = osiris("db2", url, 2); -``` - -### 2. **Centralize Instance Creation** -```rhai -// Create all instances at the start -let freezone = osiris("freezone", "redis://localhost:6379", 1); -let my_osiris = osiris("my_osiris", "redis://localhost:6379", 2); - -// Then use them throughout the script -freezone.put_note(note1); -my_osiris.put_note(note2); -``` - -### 3. **Handle Errors Per Instance** -```rhai -// Each instance can fail independently -try { - freezone.put_note(note); -} catch (e) { - print(`Freezone error: ${e}`); -} - -try { - my_osiris.put_note(note); -} catch (e) { - print(`My OSIRIS error: ${e}`); -} -``` - -### 4. **Use Different Databases** -```rhai -// Separate databases for isolation -let instance1 = osiris("inst1", "redis://localhost:6379", 1); -let instance2 = osiris("inst2", "redis://localhost:6379", 2); -``` - -## ๐ŸŽ‰ Success! - -Multi-instance OSIRIS support is **fully operational** and ready for: -- โœ… Multi-tenant applications -- โœ… Data replication -- โœ… Environment separation -- โœ… Cross-database operations -- โœ… Production use diff --git a/PREDEFINED_INSTANCES.md b/PREDEFINED_INSTANCES.md deleted file mode 100644 index 3538b22..0000000 --- a/PREDEFINED_INSTANCES.md +++ /dev/null @@ -1,387 +0,0 @@ -# OSIRIS Predefined Instances โœ… - -OSIRIS runner now supports predefined instances that are automatically available in your Rhai scripts without needing to create them manually. - -## ๐ŸŽ‰ Status: FULLY OPERATIONAL - -``` -โœ… CLI argument parsing for instances -โœ… Automatic instance creation -โœ… Global scope injection -โœ… Multiple instances support -โœ… Test script working -``` - -## ๐Ÿš€ Quick Start - -### Define Instances via CLI - -```bash -cargo run --bin runner --features rhai-support -- runner1 \ - --instance freezone:redis://localhost:6379:1 \ - --instance my:redis://localhost:6379:2 \ - --script-file scripts/predefined_instances.rhai -``` - -### Use Them Directly in Scripts - -```rhai -// No need to create instances - they're already available! -freezone.put_note(my_note); -my.put_note(my_note); -``` - -## ๐Ÿ“ Complete Example - -### Command Line - -```bash -cargo run --bin runner --features rhai-support -- test1 \ - --instance freezone:redis://localhost:6379:1 \ - --instance my:redis://localhost:6379:2 \ - --script-file scripts/predefined_instances.rhai -``` - -### Script (scripts/predefined_instances.rhai) - -```rhai -print("=== Predefined Instances Example ==="); - -// freezone and my are already available! -print(`Using: ${freezone.name()}`); -print(`Using: ${my.name()}`); - -// Create a note -let my_note = note("notes") - .title("Test Note") - .content("Using predefined instances!"); - -// Use them directly - no setup needed! -freezone.put_note(my_note); -my.put_note(my_note); - -// Query each instance -let ids1 = freezone.query("notes", "title", "Test Note"); -let ids2 = my.query("notes", "title", "Test Note"); -``` - -### Output - -``` -๐Ÿš€ OSIRIS Runner -Runner ID: test1 -HeroDB: redis://localhost:6379 (DB 1) - Instance: freezone โ†’ redis://localhost:6379 (DB 1) - Instance: my โ†’ redis://localhost:6379 (DB 2) - -๐Ÿ“ Executing script... - -โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -=== Predefined Instances Example === - -Using predefined instance: freezone -Using predefined instance: my - -Creating note... -Note created: Predefined Instance Test - -Storing in freezone... -โœ“ Stored in freezone: 61ea54fe-504d-4f43-be50-6548a82338dd - -Storing in my... -โœ“ Stored in my: 61ea54fe-504d-4f43-be50-6548a82338dd - -โœ… Script completed successfully! -``` - -## ๐ŸŽฏ CLI Arguments - -### `--instance` (or `-i`) - -Define a predefined instance that will be available in your script. - -**Format:** `name:url:db_id` - -**Examples:** -```bash -# Single instance ---instance freezone:redis://localhost:6379:1 - -# Multiple instances ---instance freezone:redis://localhost:6379:1 \ ---instance my:redis://localhost:6379:2 \ ---instance production:redis://prod.example.com:6379:1 - -# Different hosts ---instance local:redis://localhost:6379:1 \ ---instance remote:redis://remote.example.com:6379:1 -``` - -**Parameters:** -- `name` - Instance name (will be available as a variable in scripts) -- `url` - HeroDB connection URL (redis://host:port) -- `db_id` - Database ID (0-15 typically) - -## ๐Ÿ“š Use Cases - -### 1. **Multi-Tenant Setup** - -```bash -cargo run --bin runner --features rhai-support -- runner1 \ - --instance tenant1:redis://localhost:6379:1 \ - --instance tenant2:redis://localhost:6379:2 \ - --instance tenant3:redis://localhost:6379:3 \ - --script-file process_tenants.rhai -``` - -```rhai -// Script automatically has tenant1, tenant2, tenant3 available -tenant1.put_note(note1); -tenant2.put_note(note2); -tenant3.put_note(note3); -``` - -### 2. **Environment Separation** - -```bash -cargo run --bin runner --features rhai-support -- runner1 \ - --instance dev:redis://dev:6379:1 \ - --instance staging:redis://staging:6379:1 \ - --instance prod:redis://prod:6379:1 \ - --script-file deploy.rhai -``` - -```rhai -// Test in dev first -dev.put_note(test_note); - -// Then staging -staging.put_note(test_note); - -// Finally production -prod.put_note(test_note); -``` - -### 3. **Data Migration** - -```bash -cargo run --bin runner --features rhai-support -- runner1 \ - --instance source:redis://old-server:6379:1 \ - --instance target:redis://new-server:6379:1 \ - --script-file migrate.rhai -``` - -```rhai -// Migrate data from source to target -let ids = source.query("notes", "tags:tag", "migrate=true"); -for id in ids { - let note = source.get_note("notes", id); - target.put_note(note); -} -``` - -### 4. **Freezone + Personal OSIRIS** - -```bash -cargo run --bin runner --features rhai-support -- runner1 \ - --instance freezone:redis://freezone.io:6379:1 \ - --instance my:redis://localhost:6379:1 \ - --script-file sync.rhai -``` - -```rhai -// Your exact use case! -let my_note = note("notes") - .title("Shared Note") - .content("Available in both instances"); - -freezone.put_note(my_note); -my.put_note(my_note); -``` - -## ๐Ÿ—๏ธ Architecture - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ CLI Arguments โ”‚ -โ”‚ --instance freezone:redis:...:1 โ”‚ -โ”‚ --instance my:redis:...:2 โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ”‚ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ OsirisConfig โ”‚ -โ”‚ Parse and validate instances โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ”‚ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Engine + Scope โ”‚ -โ”‚ Create instances and inject โ”‚ -โ”‚ into Rhai scope as constants โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ”‚ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Rhai Script โ”‚ -โ”‚ freezone.put_note(...) โ”‚ -โ”‚ my.put_note(...) โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -## โœจ Features - -### 1. **Zero Boilerplate** -No need to create instances in scripts - they're already there! - -```rhai -// Before (manual creation) -let freezone = osiris("freezone", "redis://localhost:6379", 1); -let my = osiris("my", "redis://localhost:6379", 2); - -// After (predefined) -// Just use them! -freezone.put_note(note); -my.put_note(note); -``` - -### 2. **Type Safety** -Instances are strongly typed and validated at startup. - -### 3. **Configuration as Code** -Instance configuration is explicit in the command line. - -### 4. **Multiple Instances** -Support unlimited predefined instances. - -### 5. **Named Access** -Access instances by their meaningful names. - -## ๐Ÿ”ง Advanced Usage - -### Combining Predefined and Dynamic Instances - -```bash -# Predefined instances -cargo run --bin runner --features rhai-support -- runner1 \ - --instance freezone:redis://localhost:6379:1 \ - --instance my:redis://localhost:6379:2 \ - --script-file script.rhai -``` - -```rhai -// Use predefined instances -freezone.put_note(note1); -my.put_note(note2); - -// Create additional dynamic instances -let temp = osiris("temp", "redis://localhost:6379", 3); -temp.put_note(note3); -``` - -### Environment Variables - -You can use environment variables in your shell: - -```bash -export FREEZONE_URL="redis://freezone.io:6379" -export MY_URL="redis://localhost:6379" - -cargo run --bin runner --features rhai-support -- runner1 \ - --instance freezone:${FREEZONE_URL}:1 \ - --instance my:${MY_URL}:1 \ - --script-file script.rhai -``` - -### Configuration File (Future Enhancement) - -```toml -# osiris.toml -[instances] -freezone = { url = "redis://localhost:6379", db_id = 1 } -my = { url = "redis://localhost:6379", db_id = 2 } -``` - -```bash -cargo run --bin runner --features rhai-support -- runner1 \ - --config osiris.toml \ - --script-file script.rhai -``` - -## ๐Ÿ’ก Best Practices - -### 1. **Use Descriptive Names** -```bash -# Good ---instance production:redis://prod:6379:1 ---instance staging:redis://staging:6379:1 - -# Less clear ---instance db1:redis://prod:6379:1 ---instance db2:redis://staging:6379:1 -``` - -### 2. **Consistent Naming** -Use the same instance names across all your scripts for consistency. - -### 3. **Document Your Instances** -Add comments in your scripts explaining what each instance is for: - -```rhai -// freezone: Public shared OSIRIS instance -// my: Personal local OSIRIS instance - -freezone.put_note(public_note); -my.put_note(private_note); -``` - -### 4. **Separate Databases** -Use different database IDs for different purposes: - -```bash ---instance notes:redis://localhost:6379:1 \ ---instance events:redis://localhost:6379:2 \ ---instance cache:redis://localhost:6379:3 -``` - -## ๐Ÿงช Testing - -### Test Script - -```bash -cargo run --bin runner --features rhai-support -- test1 \ - --instance freezone:redis://localhost:6379:1 \ - --instance my:redis://localhost:6379:2 \ - --script-file scripts/predefined_instances.rhai -``` - -### Expected Output - -``` -โœ“ Instance: freezone โ†’ redis://localhost:6379 (DB 1) -โœ“ Instance: my โ†’ redis://localhost:6379 (DB 2) -โœ“ Stored in freezone: 61ea54fe-504d-4f43-be50-6548a82338dd -โœ“ Stored in my: 61ea54fe-504d-4f43-be50-6548a82338dd -โœ… Script completed successfully! -``` - -## ๐ŸŽ‰ Success! - -Predefined instances are **fully operational** and ready for: -- โœ… Zero-boilerplate scripts -- โœ… Multi-tenant systems -- โœ… Environment separation -- โœ… Data migration -- โœ… Freezone + personal OSIRIS -- โœ… Production use - -Your exact use case is now supported: -```bash -cargo run --bin runner --features rhai-support -- runner1 \ - --instance freezone:redis://freezone.io:6379:1 \ - --instance my:redis://localhost:6379:1 \ - --script-file my_script.rhai -``` - -```rhai -// Just use them! -freezone.put_note(my_note); -my.put_note(my_note); -``` diff --git a/QUICKSTART.md b/QUICKSTART.md deleted file mode 100644 index f56b42d..0000000 --- a/QUICKSTART.md +++ /dev/null @@ -1,190 +0,0 @@ -# OSIRIS Quick Start Guide - -Get up and running with OSIRIS in 5 minutes! - -## Prerequisites - -- Rust toolchain (1.70+) -- HeroDB running on localhost:6379 - -## Step 1: Start HeroDB - -```bash -cd /path/to/herodb -cargo run --release -- --dir ./data --admin-secret mysecret --port 6379 -``` - -Keep this terminal open. - -## Step 2: Build OSIRIS - -Open a new terminal: - -```bash -cd /path/to/osiris -cargo build --release -``` - -## Step 3: Initialize OSIRIS - -```bash -./target/release/osiris init --herodb redis://localhost:6379 -``` - -Output: -``` -โœ“ OSIRIS initialized - Config: /Users/you/.config/osiris/config.toml -``` - -## Step 4: Create Your First Namespace - -```bash -./target/release/osiris ns create notes -``` - -Output: -``` -โœ“ Created namespace 'notes' (DB 1) -``` - -## Step 5: Add Your First Object - -```bash -echo "OSIRIS is awesome!" | \ - ./target/release/osiris put notes/first-note - \ - --title "My First Note" \ - --tags topic=osiris,mood=excited -``` - -Output: -``` -โœ“ Stored notes/first-note -``` - -## Step 6: Search for Your Object - -```bash -./target/release/osiris find "awesome" --ns notes -``` - -Output: -``` -Found 1 result(s): - -1. first-note (score: 0.50) - OSIRIS is awesome! -``` - -## Step 7: Retrieve Your Object - -```bash -./target/release/osiris get notes/first-note -``` - -Output (JSON): -```json -{ - "id": "first-note", - "ns": "notes", - "meta": { - "title": "My First Note", - "tags": { - "mood": "excited", - "topic": "osiris" - }, - "created": "2025-10-20T10:30:00Z", - "updated": "2025-10-20T10:30:00Z", - "size": 18 - }, - "text": "OSIRIS is awesome!" -} -``` - -## Step 8: Try More Features - -### Add a note from a file -```bash -echo "This is a longer note about OSIRIS features" > /tmp/note.txt -./target/release/osiris put notes/features /tmp/note.txt \ - --title "OSIRIS Features" \ - --tags topic=osiris,type=documentation -``` - -### Search with filters -```bash -./target/release/osiris find --ns notes --filter topic=osiris -``` - -### Get raw content -```bash -./target/release/osiris get notes/first-note --raw -``` - -### View statistics -```bash -./target/release/osiris stats --ns notes -``` - -### List all namespaces -```bash -./target/release/osiris ns list -``` - -## Common Commands Cheat Sheet - -```bash -# Initialize -osiris init --herodb redis://localhost:6379 - -# Namespace management -osiris ns create -osiris ns list -osiris ns delete - -# Object operations -osiris put / [--tags k=v,...] [--title "..."] [--mime "..."] -osiris get / [--raw] [--output file] -osiris del / - -# Search -osiris find "" --ns [--filter k=v,...] [--topk N] [--json] - -# Statistics -osiris stats [--ns ] -``` - -## What's Next? - -- **Read the [Examples](EXAMPLES.md)** for more use cases -- **Check the [README](README.md)** for detailed documentation -- **Review the [MVP Spec](docs/specs/osiris-mvp.md)** to understand the architecture -- **Explore the [source code](src/)** to see how it works - -## Troubleshooting - -### "Connection refused" -Make sure HeroDB is running on port 6379: -```bash -redis-cli -p 6379 PING -``` - -### "Namespace not found" -Create the namespace first: -```bash -osiris ns create -``` - -### "Config file not found" -Run `osiris init` first: -```bash -osiris init --herodb redis://localhost:6379 -``` - -## Need Help? - -- Check the [EXAMPLES.md](EXAMPLES.md) for detailed usage patterns -- Review the [README.md](README.md) for architecture details -- Look at the [docs/specs/osiris-mvp.md](docs/specs/osiris-mvp.md) for the full specification - -Happy organizing! ๐Ÿš€ diff --git a/README.md b/README.md index 5c7438a..10512a6 100644 --- a/README.md +++ b/README.md @@ -1,124 +1,251 @@ # OSIRIS -**Object Storage, Indexing & Retrieval Intelligent System** +**Object Storage with Rhai Scripting Integration** -OSIRIS is a Rust-native object storage and retrieval layer built on top of HeroDB, providing structured storage with metadata, field indexing, and search capabilities. +OSIRIS is a Rust-native object storage layer built on HeroDB, providing structured storage with automatic indexing, Rhai scripting support, and signatory-based access control. -## Features +## Overview -- **Object Storage**: Store structured objects with metadata (title, tags, MIME type, timestamps) -- **Namespace Management**: Organize objects into isolated namespaces -- **Field Indexing**: Fast filtering by tags and metadata fields -- **Text Search**: Simple keyword-based search across object content -- **CLI Interface**: Command-line tools for object management and search -- **9P Filesystem**: Mount OSIRIS as a filesystem (future) +OSIRIS provides a trait-based architecture for storing and retrieving typed objects with: +- **Automatic Indexing**: Fields marked with `#[index]` are automatically indexed +- **Rhai Integration**: Full scripting support with builder patterns +- **Context-Based Storage**: Multi-tenant contexts with signatory-based access control +- **Type Safety**: Compile-time guarantees through the `Object` trait +- **HeroDB Backend**: Built on top of HeroDB (Redis-compatible) ## Quick Start -### Prerequisites +### Build OSIRIS -Start HeroDB: ```bash -cd /path/to/herodb -cargo run --release -- --dir ./data --admin-secret mysecret --port 6379 +cargo build --release --features rhai-support ``` -### Installation +### Run a Rhai Script ```bash -cd /path/to/osiris -cargo build --release +cargo run --bin runner --features rhai-support -- runner1 \ + --redis-url redis://localhost:6379 \ + --db-id 1 \ + --script-file examples/engine/01_note.rhai ``` -### Initialize +### Example Script -```bash -# Create configuration -mkdir -p ~/.config/osiris -cat > ~/.config/osiris/config.toml < โ†’ serialized OsirisObject -field:: โ†’ Set of IDs (for equality filtering) -scan:index โ†’ list of IDs for text scan +OSIRIS +โ”œโ”€โ”€ objects/ โ€“ Domain objects (Note, Event, User, etc.) +โ”‚ โ”œโ”€โ”€ note/ +โ”‚ โ”‚ โ”œโ”€โ”€ mod.rs โ€“ Note struct and impl +โ”‚ โ”‚ โ””โ”€โ”€ rhai.rs โ€“ Rhai bindings +โ”‚ โ””โ”€โ”€ event/ +โ”‚ โ”œโ”€โ”€ mod.rs โ€“ Event struct and impl +โ”‚ โ””โ”€โ”€ rhai.rs โ€“ Rhai bindings +โ”œโ”€โ”€ store/ โ€“ Storage layer +โ”‚ โ”œโ”€โ”€ generic_store.rs โ€“ Type-safe storage +โ”‚ โ””โ”€โ”€ type_registry.rs โ€“ Custom type registration +โ”œโ”€โ”€ rhai/ โ€“ Rhai integration +โ”‚ โ”œโ”€โ”€ instance.rs โ€“ OsirisContext (multi-tenant) +โ”‚ โ””โ”€โ”€ engine.rs โ€“ Engine configuration +โ””โ”€โ”€ bin/ + โ””โ”€โ”€ runner.rs โ€“ Standalone script runner +``` + +### Object Trait + +All OSIRIS objects implement the `Object` trait: + +```rust +#[derive(Debug, Clone, Serialize, Deserialize, DeriveObject)] +pub struct Note { + pub base_data: BaseData, + + #[index] + pub title: Option, + + pub content: Option, + + #[index] + pub tags: BTreeMap, +} +``` + +The `#[derive(DeriveObject)]` macro automatically: +- Implements the `Object` trait +- Generates index keys from `#[index]` fields +- Provides serialization/deserialization + +## Key Features + +### 1. Signatory-Based Access Control + +Contexts use signatory-based access instead of owner-based permissions: + +```rhai +// Single participant +let ctx = get_context(["alice_pk"]); + +// Shared context (all must be signatories) +let ctx = get_context(["alice_pk", "bob_pk", "charlie_pk"]); +``` + +Access is granted only if all participants are signatories of the script. + +### 2. Automatic Indexing + +Fields marked with `#[index]` are automatically indexed in HeroDB: + +```rust +#[index] +pub title: Option, // Indexed for fast queries + +pub content: Option, // Not indexed +``` + +Query by indexed fields: +```rhai +let ids = ctx.query("notes", "title", "My Note"); +let ids = ctx.query("notes", "tags:tag", "topic=rust"); +``` + +### 3. Multi-Instance Support + +Create multiple OSIRIS instances pointing to different databases: + +```bash +cargo run --bin runner --features rhai-support -- runner1 \ + --instance freezone:redis://localhost:6379:1 \ + --instance my:redis://localhost:6379:2 \ + --script-file script.rhai +``` + +```rhai +// Instances are automatically available +freezone.save(note); +my.save(note); +``` + +### 4. Builder Pattern + +Fluent API for creating objects: + +```rhai +let event = event("calendar", "Team Meeting") + .description("Weekly sync") + .location("Conference Room A") + .category("meetings") + .all_day(false); + +ctx.save(event); +``` + +## Creating Custom Objects + +See [docs/CREATING_NEW_OBJECTS.md](docs/CREATING_NEW_OBJECTS.md) for a complete guide on creating new object types. + +Quick example: + +```rust +#[derive(Debug, Clone, Serialize, Deserialize, DeriveObject)] +pub struct Task { + pub base_data: BaseData, + + #[index] + pub title: String, + + pub completed: bool, +} +``` + +## Storage Model + +### HeroDB Keyspace + +``` +obj:: โ†’ JSON serialized object +idx::: โ†’ Set of object IDs +scan: โ†’ Set of all object IDs in namespace ``` Example: ``` -field:tag:project=osiris โ†’ {note_1, note_2} -field:mime:text/markdown โ†’ {note_1, note_3} +obj:notes:abc123 โ†’ {"base_data":{...},"title":"My Note",...} +idx:notes:title:My Note โ†’ {abc123, def456} +idx:notes:tag:topic:rust โ†’ {abc123, xyz789} +scan:notes โ†’ {abc123, def456, xyz789} ``` -## Future Enhancements +### Context Storage -- Content-addressable deduplication -- Vector embeddings for semantic search -- Relation graphs -- Full-text search with Tantivy -- 9P filesystem interface +Contexts store member privileges and metadata: +``` +ctx::members โ†’ Map of user_id โ†’ privileges +ctx::meta โ†’ Context metadata +``` + +## Examples + +The `examples/` directory contains comprehensive examples: + +- **`examples/engine/`** - Object creation and storage examples + - `01_note.rhai` - Note creation and querying + - `02_event.rhai` - Event management + - `03_user.rhai` - User objects + - And more... + +- **`examples/freezone/`** - Complete freezone registration flow + +Run examples: +```bash +cargo run --example engine examples/engine/01_note.rhai +``` + +## Documentation + +- **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** - Detailed architecture and design patterns +- **[docs/CREATING_NEW_OBJECTS.md](docs/CREATING_NEW_OBJECTS.md)** - Guide for creating custom objects + +## Building and Testing + +```bash +# Build with Rhai support +cargo build --features rhai-support + +# Run tests +cargo test --lib --features rhai-support + +# Build release binary +cargo build --release --features rhai-support --bin runner +``` + +## Integration + +OSIRIS is used by: +- **ZDFZ Backend** - Freezone company and resident management +- **Hero Actor System** - Distributed job execution with object storage ## License diff --git a/REFACTORING_COMPLETE.md b/REFACTORING_COMPLETE.md deleted file mode 100644 index 4f5de38..0000000 --- a/REFACTORING_COMPLETE.md +++ /dev/null @@ -1,221 +0,0 @@ -# OSIRIS Refactoring Complete! ๐ŸŽ‰ - -## Summary - -Successfully refactored OSIRIS with: -1. โœ… **Builder Pattern** for `OsirisContext` -2. โœ… **Type Registry** for custom struct registration -3. โœ… **Engine Module** moved to `rhai` module -4. โœ… **Simplified Runner** using the new architecture - ---- - -## 1. Builder Pattern - -### Before: -```rust -OsirisContext::new_with_registry(name, owner, url, db_id, registry) -``` - -### After: -```rust -let ctx = OsirisContext::builder() - .name("my_context") - .owner("user_123") - .herodb_url("redis://localhost:6379") - .db_id(1) - .registry(registry) // Optional - .build()?; -``` - -**Benefits:** -- Fluent, readable API -- Optional parameters -- Type-safe construction -- Backward compatible with `OsirisContext::new()` - ---- - -## 2. Type Registry - -### Architecture: -```rust -// 1. Create registry -let registry = TypeRegistry::new(); - -// 2. Register types (one line per type!) -registry.register_type::("residents")?; -registry.register_type::("companies")?; -registry.register_type::("invoices")?; - -// 3. Create context with registry -let ctx = OsirisContext::builder() - .name("zdfz") - .owner("admin") - .herodb_url(url) - .db_id(1) - .registry(Arc::new(registry)) - .build()?; - -// 4. Save uses the correct type automatically! -ctx.save("residents", "id123", resident_data)?; // Uses Resident type -ctx.save("companies", "id456", company_data)?; // Uses Company type -``` - -### How It Works: -1. **Registry maps collection โ†’ type** -2. **Single `save()` function** looks up the type -3. **Deserializes JSON** to the correct Rust struct -4. **Calls `store.put()`** with typed object -5. **Proper indexing** happens via `index_keys()` method - -**No callbacks, no multiple functions - just ONE save function!** ๐ŸŽฏ - ---- - -## 3. Engine Module - -### Moved from: -``` -src/bin/runner/engine.rs -``` - -### To: -``` -src/rhai/engine.rs -``` - -### New API: -```rust -use osiris::rhai::{ - OsirisEngineConfig, - create_osiris_engine, - create_osiris_engine_with_config, - create_osiris_engine, -}; - -// Simple engine -let (engine, scope) = create_osiris_engine("owner", "redis://localhost:6379", 1)?; - -// With config -let mut config = OsirisEngineConfig::new(); -config.add_context("ctx1", "owner1", "redis://localhost:6379", 1); -config.add_context("ctx2", "owner2", "redis://localhost:6379", 2); -let (engine, scope) = create_osiris_engine_with_config(config)?; - -// With context manager (dynamic contexts) -let engine = create_osiris_engine("redis://localhost:6379", 1)?; -``` - ---- - -## 4. Simplified Runner - -### New Structure: -``` -src/bin/runner.rs (single file!) -``` - -### Usage: -```bash -# Run a script -cargo run --bin runner --features rhai-support -- runner1 \ - --script "ctx.save('residents', 'id123', data);" - -# With custom contexts -cargo run --bin runner --features rhai-support -- runner1 \ - --instance freezone:redis://localhost:6379:1 \ - --instance backup:redis://localhost:6379:2 \ - --script "freezone.save('residents', 'id123', data);" -``` - ---- - -## File Structure - -``` -osiris/src/ -โ”œโ”€โ”€ rhai/ -โ”‚ โ”œโ”€โ”€ mod.rs # Exports -โ”‚ โ”œโ”€โ”€ instance.rs # OsirisContext + Builder + ContextManager -โ”‚ โ””โ”€โ”€ engine.rs # Engine creation functions -โ”œโ”€โ”€ store/ -โ”‚ โ”œโ”€โ”€ mod.rs -โ”‚ โ”œโ”€โ”€ generic_store.rs -โ”‚ โ””โ”€โ”€ type_registry.rs # Type registry for custom structs -โ””โ”€โ”€ bin/ - โ””โ”€โ”€ runner.rs # Simplified runner binary -``` - ---- - -## Exports - -From `osiris::rhai`: -- `OsirisContext` - Main context type -- `OsirisContextBuilder` - Builder for contexts -- `OsirisInstance` - Alias for backward compatibility -- `ContextManager` - Multi-tenant manager -- `Privilege`, `Member` - Access control types -- `OsirisEngineConfig` - Engine configuration -- `create_osiris_engine()` - Engine creation functions -- `register_context_api()` - Register context API in engine - -From `osiris::store`: -- `TypeRegistry` - Type registry for custom structs -- `GenericStore` - Generic storage layer -- `Object`, `Storable` - Traits - ---- - -## Usage in ZDFZ API - -```rust -use osiris::rhai::{OsirisContext, OsirisEngineConfig, create_osiris_engine_with_config}; -use osiris::store::TypeRegistry; -use std::sync::Arc; - -// 1. Create type registry -let registry = TypeRegistry::new(); -registry.register_type::("residents")?; -registry.register_type::("companies")?; -registry.register_type::("invoices")?; -let registry = Arc::new(registry); - -// 2. Create engine config -let mut config = OsirisEngineConfig::new(); -config.add_context("zdfz", "admin", "redis://localhost:6379", 1); - -// 3. Create engine -let (mut engine, scope) = create_osiris_engine_with_config(config)?; - -// 4. Register ZDFZ DSL functions -register_resident_api(&mut engine); -register_company_api(&mut engine); -register_invoice_api(&mut engine); - -// 5. Run scripts! -engine.eval_with_scope(&mut scope, r#" - let resident = create_resident(#{ - email: "test@example.com", - first_name: "John" - }); - - zdfz.save("residents", resident.id, resident); -"#)?; -``` - ---- - -## Benefits - -โœ… **Clean API** - Builder pattern for context creation -โœ… **Type-Safe** - Registry ensures correct types are used -โœ… **Flexible** - Applications register their own types -โœ… **Proper Indexing** - Each type's `index_keys()` is called -โœ… **Organized** - Engine in rhai module where it belongs -โœ… **Simple Runner** - Single file, uses library code - ---- - -**Status:** All refactoring complete and ready for use! ๐Ÿš€ diff --git a/RHAI_REFACTOR_COMPLETE.md b/RHAI_REFACTOR_COMPLETE.md deleted file mode 100644 index b8b48c4..0000000 --- a/RHAI_REFACTOR_COMPLETE.md +++ /dev/null @@ -1,153 +0,0 @@ -# OSIRIS Rhai Module Refactoring - Complete โœ… - -## Summary - -Successfully refactored and cleaned up the OSIRIS Rhai integration module: - -1. โœ… **Merged Context and Instance** - Combined into single unified `OsirisContext` -2. โœ… **Removed Type-Specific Methods** - Eliminated `put_note`, `get_note`, `put_event`, `get_event`, etc. -3. โœ… **Renamed Module** - `rhai_support` โ†’ `rhai` -4. โœ… **Merged Files** - Combined `context.rs` and `instance.rs` into single `instance.rs` -5. โœ… **Added Generic CRUD** - Implemented generic `save`, `get`, `delete`, `list`, `query` methods -6. โœ… **Added JSON Parsing** - Implemented `json_to_rhai` helper for proper JSON โ†’ Rhai conversion - -## Final Structure - -``` -herocode/osiris/src/rhai/ -โ”œโ”€โ”€ mod.rs # Module exports -โ””โ”€โ”€ instance.rs # Complete implementation (OsirisContext + ContextManager) -``` - -## What's in instance.rs - -### 1. **OsirisContext** - Complete context with storage + members -- **Member Management:** - - `add_member(user_id, privileges)` - Add member with privileges - - `remove_member(user_id)` - Remove member - - `has_privilege(user_id, privilege)` - Check privilege - - `list_members()` - List all members - - `get_member_privileges(user_id)` - Get member's privileges - -- **Generic CRUD Operations:** - - `save(collection, id, data)` - Save any Rhai object to HeroDB - - `get(collection, id)` - Get from HeroDB, parse to Rhai Map - - `delete(collection, id)` - Delete from HeroDB - - `list(collection)` - List all IDs in collection - - `query(collection, field, value)` - Query by index - -### 2. **ContextManager** - Multi-tenant context management -- `new(herodb_url, base_db_id)` - Create manager -- `get_context(context_id, owner_id)` - Get or create context -- `list_contexts()` - List all contexts -- `remove_context(context_id)` - Remove context - -### 3. **Helper Functions** -- `json_to_rhai(value)` - Convert serde_json::Value to rhai::Dynamic -- `register_context_api(engine, manager)` - Register in Rhai engine - -## Key Improvements - -### โœ… Generic Storage -```rust -// OLD: Type-specific methods -ctx.put_note(note); -ctx.get_note("ns", "id"); - -// NEW: Generic methods work with any data -ctx.save("residents", "id123", resident_data); -let data = ctx.get("residents", "id123"); -``` - -### โœ… Proper JSON Parsing -```rust -// Uses store.get_raw() to fetch raw JSON from HeroDB -// Parses JSON to serde_json::Value -// Converts to Rhai Map/Array/primitives via json_to_rhai() -``` - -### โœ… Clean Module Structure -```rust -// Single file with everything: -// - Privilege enum -// - Member struct -// - OsirisContext (main type) -// - ContextManager -// - Helper functions -// - Tests -``` - -## Usage Example - -```rhai -// Get a context (creates if doesn't exist) -let ctx = get_context("workspace_123", "owner_user_id"); - -// Add members with privileges -ctx.add_member("user2", ["read", "write"]); -ctx.add_member("user3", ["read"]); - -// Check access -if ctx.has_privilege("user2", "write") { - // Save data - let resident = #{ - email: "test@example.com", - first_name: "John", - last_name: "Doe" - }; - ctx.save("residents", "resident_123", resident); -} - -// Get data (returns as Rhai Map) -let data = ctx.get("residents", "resident_123"); -print(data.email); // "test@example.com" - -// Query -let ids = ctx.query("residents", "email", "test@example.com"); - -// List all -let all_ids = ctx.list("residents"); - -// Delete -ctx.delete("residents", "resident_123"); -``` - -## Exports - -From `osiris::rhai`: -- `OsirisContext` - Main context type -- `OsirisInstance` - Type alias for backward compatibility -- `Privilege` - Privilege enum (Read, Write, ManageMembers, Admin) -- `Member` - Member struct -- `ContextManager` - Multi-tenant manager -- `register_context_api` - Register in Rhai engine - -## Integration with ZDFZ API - -Updated `/Users/timurgordon/code/git.ourworld.tf/zdfz/api/src/engines/rhai.rs`: -```rust -// Re-export OSIRIS ContextManager -pub use osiris::rhai::ContextManager; -``` - -## Compilation Status - -โœ… **OSIRIS compiles successfully** with `--features rhai-support` -โœ… **All type-specific methods removed** -โœ… **Generic CRUD working** -โœ… **JSON parsing implemented** -โœ… **Module renamed to `rhai`** -โœ… **Files merged into single `instance.rs`** - -## Next Steps - -1. Update ZDFZ API to use the new generic CRUD methods -2. Remove any remaining references to old type-specific methods -3. Test end-to-end with HeroDB -4. Add proper JSON serialization for SDK models - ---- - -**Refactoring Complete!** ๐ŸŽ‰ - -The OSIRIS Rhai module is now clean, generic, and ready for production use. diff --git a/RUNNER.md b/RUNNER.md deleted file mode 100644 index 6ee2864..0000000 --- a/RUNNER.md +++ /dev/null @@ -1,328 +0,0 @@ -# OSIRIS Runner - Standalone Binary โœ… - -The OSIRIS runner is a standalone binary that executes Rhai scripts with full OSIRIS object support. - -## ๐ŸŽ‰ Status: FULLY OPERATIONAL - -``` -โœ… Binary created at src/bin/runner/ -โœ… Rhai engine with OSIRIS objects -โœ… Note and Event support -โœ… Automatic indexing -โœ… Query functionality -โœ… Test scripts working -``` - -## ๐Ÿš€ Quick Start - -### Run a Script File - -```bash -cargo run --bin runner --features rhai-support -- runner1 --script-file scripts/test_note.rhai -``` - -### Run Inline Script - -```bash -cargo run --bin runner --features rhai-support -- runner1 \ - --script 'let note = note("test").title("Hi"); print(note.get_title());' -``` - -## ๐Ÿ“ Example Output - -``` -๐Ÿš€ OSIRIS Runner -Runner ID: test1 -HeroDB: redis://localhost:6379 (DB 1) - -๐Ÿ“ Executing script... - -โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -=== OSIRIS Note Test === - -Creating note... -Note created: Test from OSIRIS Runner -Storing note... -โœ“ Note stored with ID: 46a064c7-9062-4858-a390-c11f0d5877a7 - -Retrieving note... -โœ“ Retrieved: Test from OSIRIS Runner - Content: This note was created using the OSIRIS standalone runner! - -Querying notes by tag... -โœ“ Found notes: - - 2c54e1ec-bed9-41ea-851c-f7313abbd7cd - - 392f3f7f-47e7-444f-ba11-db38d74b12af - - 46a064c7-9062-4858-a390-c11f0d5877a7 -=== Test Complete === -โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -โœ… Script completed successfully! -``` - -## ๐Ÿ“– Usage - -### Command Line Options - -``` -OSIRIS Rhai Script Runner - -Usage: runner [OPTIONS] - -Arguments: - Runner ID - -Options: - -r, --redis-url - HeroDB URL [default: redis://localhost:6379] - -d, --db-id - HeroDB database ID [default: 1] - -s, --script