| Crates.io | valinor-domain |
| lib.rs | valinor-domain |
| version | 0.1.0 |
| created_at | 2026-01-09 14:51:38.467235+00 |
| updated_at | 2026-01-09 14:51:38.467235+00 |
| description | Domain models and types for MudWorld text-based virtual world platform |
| homepage | |
| repository | https://github.com/douglance/mudworld |
| max_upload_size | |
| id | 2032209 |
| size | 26,217 |
Core domain types and data structures for the MudWorld virtual world platform.
This crate defines the foundational data models shared across the MudWorld system. It provides pure, serializable types with no business logic dependencies, making it suitable as a dependency for any layer of the application.
The domain model represents a MUD-inspired virtual world where:
Use valinor-domain when you need to:
Do not use this crate for business logic, validation rules, or database operations. Those belong in higher-level crates like valinor-acl, valinor-validate, and valinor-db.
Add to your Cargo.toml:
[dependencies]
valinor-domain = { path = "../valinor-domain" }
Or if published:
[dependencies]
valinor-domain = "0.1"
Entity IDs follow a prefix convention for type safety and debugging:
| Entity | Prefix | Example |
|---|---|---|
| Principal | p_ |
p_abc123 |
| Session | s_ |
s_xyz789 |
| Agent | ag_ |
ag_player1 |
| Place | pl_ |
pl_tavern |
| Post | post_ |
post_notice1 |
m_ |
m_letter42 |
|
| Friendship | fr_ |
fr_bond99 |
| MeetOffer | mo_ |
mo_invite7 |
use valinor_domain::ids::{prefix, validate_id};
let agent_id = "ag_abc123";
assert!(validate_id(agent_id, prefix::AGENT));
Authentication identity tied to a public key.
use valinor_domain::Principal;
let principal = Principal {
principal_id: "p_abc123".to_string(),
pubkey: "ed25519-public-key-base64".to_string(),
created_at: 1704067200,
last_seen_at: Some(1704153600),
disabled: false,
};
User profile that exists in the world.
use valinor_domain::Agent;
let agent = Agent::new(
"ag_hero".to_string(),
"p_abc123".to_string(),
"Brave Hero".to_string(),
valinor_domain::now_seconds(),
);
A location with ownership and access control.
use valinor_domain::{Place, AccessControl};
let place = Place {
place_id: "pl_tavern".to_string(),
slug: "dragons-rest".to_string(),
title: "The Dragon's Rest Tavern".to_string(),
description: "A cozy tavern where adventurers gather.".to_string(),
owner_agent_id: "ag_innkeeper".to_string(),
acl: AccessControl::default(),
board_id: "board_tavern".to_string(),
created_at: 1704067200,
updated_at: 1704067200,
};
Bidirectional relationship between two agents.
use valinor_domain::Friendship;
let friendship = Friendship::new(
"fr_bond1".to_string(),
"ag_alice".to_string(),
"ag_bob".to_string(),
Some("pl_tavern".to_string()),
);
// Agent IDs are stored in sorted order for consistent lookups
assert_eq!(friendship.a_agent_id, "ag_alice");
assert_eq!(friendship.b_agent_id, "ag_bob");
// Find the other party in a friendship
let other = friendship.other_agent("ag_alice");
assert_eq!(other, Some("ag_bob"));
Time-limited invitation to form a friendship.
use valinor_domain::MeetOffer;
let offer = MeetOffer::new(
"mo_invite1".to_string(),
"ag_alice".to_string(),
"ag_bob".to_string(),
"pl_tavern".to_string(),
);
// Offers expire after 5 minutes (300 seconds)
assert!(!offer.is_expired(offer.created_at + 100));
assert!(offer.is_expired(offer.created_at + 300));
Fine-grained permissions for places and boards.
use valinor_domain::{AccessControl, AccessRule, AccessMode, Permission};
// Default: public discover/read/write, self-only admin
let acl = AccessControl::default();
// Custom access: friends can read, allowlist can write
let custom_acl = AccessControl {
discover: AccessRule { mode: AccessMode::Public, allow_agent_ids: vec![] },
read: AccessRule { mode: AccessMode::Friends, allow_agent_ids: vec![] },
write: AccessRule {
mode: AccessMode::Allowlist,
allow_agent_ids: vec!["ag_trusted".to_string()]
},
admin: AccessRule { mode: AccessMode::Self_, allow_agent_ids: vec![] },
};
Access Modes:
Public - Anyone can accessFriends - Only friends of the ownerAllowlist - Only agents in allow_agent_idsSelf_ - Only the ownerUnspecified - No explicit policyTyped events for real-time updates.
use valinor_domain::{Event, event_type};
use serde_json::json;
let event = Event {
event_id: 1,
ts: valinor_domain::now_millis(),
event_type: event_type::CHAT_SAY.to_string(),
place_id: Some("pl_tavern".to_string()),
agent_id: Some("ag_hero".to_string()),
data: json!({ "message": "Hello, everyone!" }),
};
Event Types:
presence.joined / presence.left - Agent enters/leaves a placeplace.updated - Place metadata changedchat.say / chat.emote - Chat messagesmeet.offered / meet.accepted - Friendship workflowboard.posted - New board postmail.received - Direct message receivedsystem.maintenance / system.broadcast - System announcementsuse valinor_domain::{now_seconds, now_millis};
let unix_seconds = now_seconds(); // For timestamps
let unix_millis = now_millis(); // For event ordering
| Crate | Purpose |
|---|---|
valinor-acl |
Access control evaluation logic |
valinor-validate |
Input validation rules |
valinor-db |
Database persistence layer |
valinor-auth |
Authentication and session management |
valinor-events |
Event streaming and subscriptions |
valinor-wire |
Wire protocol encoding/decoding |
valinor-proto |
Protobuf message definitions |
valinor-place |
Place management operations |
valinor-session |
Session lifecycle handling |
valinor-router |
Request routing |
valinor-worker |
Cloudflare Worker runtime |
valinor-cli |
Command-line interface |
MIT