valinor-domain

Crates.iovalinor-domain
lib.rsvalinor-domain
version0.1.0
created_at2026-01-09 14:51:38.467235+00
updated_at2026-01-09 14:51:38.467235+00
descriptionDomain models and types for MudWorld text-based virtual world platform
homepage
repositoryhttps://github.com/douglance/mudworld
max_upload_size
id2032209
size26,217
doug (douglance)

documentation

README

valinor-domain

Core domain types and data structures for the MudWorld virtual world platform.

Purpose

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:

  • Principals authenticate via public keys
  • Agents are user profiles that interact in the world
  • Places are locations agents can visit
  • Friendships form between agents who meet
  • Events track everything that happens

When to Use

Use valinor-domain when you need to:

  • Define API request/response types
  • Persist or retrieve entities from storage
  • Pass domain objects between crates
  • Serialize data for wire transmission (JSON, protobuf)
  • Validate entity ID formats

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.

Installation

Add to your Cargo.toml:

[dependencies]
valinor-domain = { path = "../valinor-domain" }

Or if published:

[dependencies]
valinor-domain = "0.1"

API Overview

ID Prefixes

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
Mail 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));

Core Types

Principal

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,
};

Agent

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(),
);

Place

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,
};

Friendship

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"));

MeetOffer

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));

Access Control

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 access
  • Friends - Only friends of the owner
  • Allowlist - Only agents in allow_agent_ids
  • Self_ - Only the owner
  • Unspecified - No explicit policy

Events

Typed 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 place
  • place.updated - Place metadata changed
  • chat.say / chat.emote - Chat messages
  • meet.offered / meet.accepted - Friendship workflow
  • board.posted - New board post
  • mail.received - Direct message received
  • system.maintenance / system.broadcast - System announcements

Utilities

use valinor_domain::{now_seconds, now_millis};

let unix_seconds = now_seconds();  // For timestamps
let unix_millis = now_millis();    // For event ordering

Related Crates

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

License

MIT

Commit count: 0

cargo fmt