Key Concepts
This document provides an overview of the key concepts in ReX’s content system. Understanding these concepts is essential for working effectively with the system.
Core Concepts
Content Model
The foundation of ReX is the unified Content model, which has three main components:
interface Content<T = string> {
// The actual content data (generic to support different representations)
data: T
// MIME type of the content
contentType: string
// Metadata about the content
metadata: ContentMetadata
}
interface ContentMetadata {
// Standard metadata fields
title?: string
description?: string
createdAt?: Date
updatedAt?: Date
// Custom metadata (extensible)
[key: string]: any
}
The Content<T>
interface uses a generic type parameter to support different content representations:
Content<string>
: Text-based content (default)Content<Buffer>
: Binary contentContent<object>
: Structured dataContent<T>
: Custom data types
URI System
All content is identified by a URI (Uniform Resource Identifier), not a path or ID. URIs provide a consistent addressing system across different storage backends:
scheme:[//authority]/path[?query][#fragment]
Examples:
content:blog/posts/hello-world.md
: Content in the default storefile:/content/blog/posts/hello-world.md
: File system contentmemory:temporary/draft.md
: In-memory contenthttp://api.example.com/content/post-123
: Remote content
Content Operations
The system provides five core content operations:
- Read: Retrieve content by URI
- Write: Create or update content at a URI
- Delete: Remove content from a URI
- List: Find content URIs matching a pattern
- Exists: Check if content exists at a URI
In addition, content changes can be observed:
- Observe: Register an observer for content changes
Architectural Concepts
Compositional Architecture
ReX uses a compositional architecture based on function composition rather than inheritance. This approach:
- Builds complex behavior from simple, focused functions
- Promotes reuse through composition
- Creates a flexible, adaptable system
Example:
// Create base store
const baseStore = createContentStore({ adapter })
// Enhance with middleware
const enhancedStore = pipe(
baseStore,
withValidation(schema),
withCaching({ maxAge: 3600 }),
withLogging({ level: 'info' })
)
Layer Boundaries
The system is organized into distinct layers with clear responsibilities:
- Integration Layer: React hooks, components, API surface
- Content Facade Layer: ContentStore, Registry interfaces
- Enhancement Layer: Middleware, composition functions
- Storage Adapter Layer: Environment-specific storage implementations
- Foundation Layer: Types, errors, utilities
Each layer has well-defined boundaries and interfaces, enhancing modularity and maintainability.
Middleware Pattern
The middleware pattern enables extensibility through function composition:
type Middleware<T = ContentContext> = (
context: T,
next: () => Promise<T>
) => Promise<T>
Middleware functions:
- Receive a context object with operation details
- Can modify the context before passing to the next middleware
- Can process the result after the next middleware completes
- Can short-circuit the chain (not calling next)
Common middleware includes:
- Validation: Validate content against schemas
- Caching: Cache content for performance
- Logging: Log operations for debugging
- Transformation: Transform content during operations
Environment Adaptability
The system adapts to different runtime environments:
- Node.js: Full filesystem access, server operations
- Browser: IndexedDB/localStorage, fetch API
- Service Worker: Offline capabilities, background sync
Environment detection allows the system to use the appropriate implementations automatically.
Storage Adapters
Storage adapters abstract the details of specific storage backends:
- FileSystemAdapter: Node.js filesystem storage
- MemoryAdapter: In-memory storage (all environments)
- IndexedDBAdapter: Browser persistent storage
- HttpAdapter: Remote content via fetch API
- ServiceWorkerAdapter: Offline-capable storage
Each adapter implements the common ContentAdapter
interface but may provide additional capabilities.
Event System
Content Change Notification
The system uses an observer pattern for content change notifications:
// Register observer
const unsubscribe = store.observe((uri, content, changeType) => {
// Handle change notification
console.log(`${changeType} event for ${uri}`)
}, options)
// Later, unsubscribe to prevent memory leaks
unsubscribe()
Change types include:
created
: Content was createdupdated
: Content was updateddeleted
: Content was deletedmoved
: Content was moved (URI changed)
Observer Options
Observation can be filtered by pattern and change type:
store.observe(observer, {
// Only observe content matching this pattern
pattern: 'blog/**/*.md',
// Only observe these change types
types: ['created', 'updated'],
})
Error Handling
The system uses specialized error classes for different scenarios:
- ContentError: Base error class for all content errors
- ContentNotFoundError: Content doesn’t exist
- ContentAccessError: Permission issues accessing content
- ContentFormatError: Invalid content format
- ContentValidationError: Content failed validation
Errors include context for troubleshooting:
try {
await store.read('non-existent.md')
} catch (error) {
if (error instanceof ContentNotFoundError) {
console.log(`Content not found at URI: ${error.uri}`)
}
}
Environment Support
Isomorphic Design
The system is designed to work consistently across environments:
- Same API interface in all environments
- Environment-specific implementations are abstracted
- Capability detection for feature availability
Capability Detection
Rather than environment detection, the system uses capability detection:
import { hasFileSystemAccess, hasIndexedDB } from '@ReX/core/utils/env'
// Choose adapter based on capabilities
const adapter = hasFileSystemAccess()
? createFileSystemAdapter({ baseDir: './content' })
: hasIndexedDB()
? createIndexedDBAdapter({ dbName: 'content' })
: createMemoryAdapter()
This approach focuses on what the environment can do rather than what it is.
Next Steps
After understanding these key concepts:
- Explore the Architecture Overview for system design details
- Read the Getting Started guide for practical examples
- Review specific API details in the Reference documentation
- Check the Glossary for standardized terminology