title: Diaryx Core Library
author: adammharris
audience:
- public
part_of: ../../README.md
Diaryx Core Library
This is the diaryx_core library! It contains shared code for the Diaryx clients.
Async-first Architecture
This library uses an async-first design. All core modules (Workspace, Validator, Exporter, Searcher, Publisher) use the AsyncFileSystem trait for filesystem operations.
For CLI/native code: Wrap a sync filesystem with SyncToAsyncFs and use futures_lite::future::block_on():
use ;
use Workspace;
let fs = new;
let workspace = new;
// Use block_on for sync contexts
let tree = block_on;
For WASM: Implement AsyncFileSystem directly using JS promises/IndexedDB.
Quick overview
diaryx_core
└── src
Provided functionality
Managing frontmatter
Full key-value operations for managing frontmatter properties:
set_frontmatter_propertyget_frontmatter_propertyrename_frontmatter_propertyremove_frontmatter_propertyget_all_frontmatter
Also, sorting frontmatter properties:
sort_frontmattersort_alphabeticallysort_by_pattern
Managing file content
Operations for managing content of markdown files separate from frontmatter:
set_contentget_contentappend_contentclear_content
Search
Search frontmatter or content separately:
SearchQuery::contentSearchQuery::frontmatter
Export
use ;
use ;
use Path;
let workspace_root = new;
let audience = "public";
let destination = new;
let fs = new;
let exporter = new;
// Use futures_lite::future::block_on for sync contexts
let plan = block_on.unwrap;
let force = false;
let keep_audience = false;
let options = ExportOptions ;
let result = block_on;
match result
Validation
The validate module provides functionality to check workspace link integrity and automatically fix issues.
Validator
The Validator struct checks part_of and contents references within a workspace:
use Validator;
use ;
use Path;
let fs = new;
let validator = new;
// Validate entire workspace starting from root index
// The second parameter controls orphan detection depth:
// - Some(2) matches tree view depth (recommended for UI)
// - None for unlimited depth (full workspace scan)
let root_path = new;
let result = block_on.unwrap;
// Or validate a single file
let file_path = new;
let result = block_on.unwrap;
if result.is_ok else
Validation Errors
BrokenPartOf- A file'spart_ofpoints to a non-existent fileBrokenContentsRef- An index'scontentsreferences a non-existent fileBrokenAttachment- A file'sattachmentsreferences a non-existent file
Validation Warnings
OrphanFile- A markdown file not referenced by any indexUnlinkedEntry- A file/directory not in the contents hierarchyUnlistedFile- A markdown file in a directory but not in the index's contentsCircularReference- Circular reference detected in workspace hierarchyNonPortablePath- A path contains absolute paths or./..componentsMultipleIndexes- Multiple index files in the same directoryOrphanBinaryFile- A binary file not referenced by any attachmentsMissingPartOf- A non-index file has nopart_ofproperty
ValidationFixer
The ValidationFixer struct provides methods to automatically fix validation issues:
use ;
use ;
use Path;
let fs = new;
let validator = new;
let fixer = new;
// Validate workspace (use None for full depth when fixing)
let root_path = new;
let result = block_on.unwrap;
// Fix all issues at once
let = block_on;
for fix in error_fixes.iter.chain
// Or fix individual issues (all methods are async)
block_on;
CRDT (Real-time Collaboration)
The crdt module provides conflict-free replicated data types for real-time collaboration, built on yrs (Rust port of Yjs). This module is feature-gated and must be enabled explicitly.
Feature Flags
[]
= { = "0.1", = ["crdt"] }
# For SQLite-based persistent storage
= { = "0.1", = ["crdt", "crdt-sqlite"] }
Architecture
The CRDT system uses two document types:
- WorkspaceCrdt - A single Y.Doc that stores file hierarchy metadata (file paths, titles, audiences, etc.)
- BodyDoc - Per-file Y.Docs that store document content (body text and frontmatter)
Both document types support:
- Real-time synchronization via Y-sync protocol (compatible with Hocuspocus server)
- Version history with time travel capabilities
- Pluggable storage backends (in-memory or SQLite)
WorkspaceCrdt
Manages the workspace file hierarchy as a CRDT:
use ;
use Arc;
let storage = new;
let workspace = new;
// Set file metadata
let metadata = FileMetadata ;
workspace.set_file;
// Get file metadata
if let Some = workspace.get_file
// List all files
let files = workspace.list_files;
// Remove a file
workspace.remove_file;
BodyDoc
Manages individual document content:
use ;
use Arc;
let storage = new;
let doc = new;
// Set body content
doc.set_body;
// Get body content
let content = doc.get_body;
// Collaborative editing operations
doc.insert_at;
doc.delete_range;
// Frontmatter operations
doc.set_frontmatter;
doc.set_frontmatter;
let title = doc.get_frontmatter;
doc.remove_frontmatter;
BodyDocManager
Manages multiple BodyDocs with lazy loading:
use ;
use Arc;
let storage = new;
let manager = new;
// Get or create a BodyDoc for a file
let doc = manager.get_or_create;
doc.set_body;
// Check if a doc exists
if manager.has_doc
// Remove a doc from the manager
manager.remove_doc;
Sync Protocol
The sync module implements Y-sync protocol for real-time collaboration with Hocuspocus or other Y.js-compatible servers:
use ;
use Arc;
let storage = new;
let workspace = new;
// Get sync state for initial handshake
let state_vector = workspace.get_sync_state;
// Apply remote update from server
let remote_update: = /* from WebSocket */;
workspace.apply_update;
// Encode state for sending to server
let full_state = workspace.encode_state;
// Encode incremental update since a state vector
let diff = workspace.encode_state_as_update;
Version History
All local changes are automatically recorded in the storage backend, enabling version history and time travel:
use ;
use Arc;
let storage = new;
let workspace = new;
// Make some changes
workspace.set_file;
workspace.set_file;
// Get version history
let history: = storage.get_all_updates.unwrap;
for entry in &history
// Time travel to a specific version
workspace.restore_to_version;
Storage Backends
MemoryStorage
In-memory storage for WASM/web and testing:
use MemoryStorage;
use Arc;
let storage = new;
SqliteStorage (requires crdt-sqlite feature)
Persistent storage using SQLite:
use SqliteStorage;
use Arc;
let storage = new;
Command API
CRDT operations are also available through the unified command API (used by WASM and Tauri):
use ;
let diaryx = with_crdt;
// Execute CRDT commands
let result = diaryx.execute;
let result = diaryx.execute;
let result = diaryx.execute;
Publish
Templates
Workspaces
Date parsing
Shared errors
Configuration
Filesystem abstraction
The fs module provides filesystem abstraction through two traits: FileSystem (synchronous) and AsyncFileSystem (asynchronous).
Note: As of the async-first refactor, all core modules (Workspace, Validator, Exporter, Searcher, Publisher) use AsyncFileSystem. For synchronous contexts (CLI, tests), wrap a sync filesystem with SyncToAsyncFs and use futures_lite::future::block_on().
FileSystem trait
The synchronous FileSystem trait provides basic implementations:
RealFileSystem- Native filesystem usingstd::fs(not available on WASM)InMemoryFileSystem- In-memory implementation, useful for WASM and testing
use ;
use Path;
// Create an in-memory filesystem
let fs = new;
// Write a file (sync)
fs.write_file.unwrap;
// Read it back
let content = fs.read_to_string.unwrap;
assert_eq!;
AsyncFileSystem trait (Primary API)
The AsyncFileSystem trait is the primary API for all core modules:
- WASM environments where JavaScript APIs (like IndexedDB) are async
- Native code using async runtimes like tokio
- All workspace operations (Workspace, Validator, Exporter, etc.)
use ;
use Workspace;
use Path;
// Wrap a sync filesystem for use with async APIs
let sync_fs = new;
let async_fs = new;
// Use with Workspace (async)
let workspace = new;
// For sync contexts, use block_on
let tree = block_on;
SyncToAsyncFs adapter
The SyncToAsyncFs struct wraps any synchronous FileSystem implementation to provide an AsyncFileSystem interface. This is the recommended way to use the async-first API in synchronous contexts:
use ;
use Workspace;
// For native code
let fs = new;
let workspace = new;
// For tests/WASM
let fs = new;
let workspace = new;
// Access the inner sync filesystem if needed
// let inner = async_fs.inner();