Skip to content

Architecture Overview

This document provides a high-level overview of the ReX architecture, explaining the system’s structure, components, and design principles.

Architectural Principles

The ReX architecture is built on the following core principles:

  1. Composition Over Inheritance: Function composition as the primary mechanism for extending functionality
  2. Clear Layer Boundaries: Well-defined responsibilities and interfaces between layers
  3. Environmental Adaptability: Consistent API with environment-specific implementations
  4. Progressive Enhancement: Core functionality with optional advanced capabilities
  5. Pure Functions: Minimizing side effects and enhancing testability

System Layers

The system is organized into five distinct layers:

┌─────────────────────────────────┐
│       Integration Layer         │ React hooks, components, API surface
├─────────────────────────────────┤
│     Content Facade Layer        │ ContentStore, Registry interfaces
├─────────────────────────────────┤
│      Enhancement Layer          │ Middleware, composition functions
├─────────────────────────────────┤
│     Storage Adapter Layer       │ Environment-specific storage adapters
├─────────────────────────────────┤
│       Foundation Layer          │ Types, errors, utilities, telemetry
└─────────────────────────────────┘

Layer Details

1. Integration Layer

This layer connects ReX to application frameworks and environments:

  • React Integration: Hooks and components for React applications
  • Node.js Integration: Express middleware and server-side utilities
  • API Surface: Public JavaScript/TypeScript API

2. Content Facade Layer

This layer provides high-level interfaces for content operations:

  • ContentStore: Primary interface for content operations
  • ContentRegistry: Registry for managing multiple content stores
  • Operation Factories: Functions creating configured operations

3. Enhancement Layer

This layer enhances content operations through middleware:

  • Middleware Chain: Sequential execution of middleware functions
  • Context Propagation: Shared context for middleware execution
  • Composition Functions: Utilities for combining middleware and enhanced stores

4. Storage Adapter Layer

This layer abstracts storage backend details:

  • Environment-specific Adapters: Filesystem, IndexedDB, HTTP, etc.
  • Adapter Capability Detection: Runtime identification of available features
  • Serialization/Deserialization: Converting between content and storage formats

5. Foundation Layer

This layer provides core building blocks:

  • Type Definitions: Core types like Content, ContentMetadata, etc.
  • Error System: Specialized error classes with context
  • Utilities: Helper functions for common operations
  • Telemetry: Logging, tracing, and monitoring

Component Architecture

Core Components

The primary components of the system include:

ContentStore

The ContentStore is the primary interface for content operations:

typescript
interface ContentStore {
  // Core operations
  read(uri: string, options?: ContentReadOptions): Promise<Content>
  write(
    uri: string,
    content: Content,
    options?: ContentWriteOptions
  ): Promise<void>
  delete(uri: string, options?: ContentDeleteOptions): Promise<void>
  list(pattern: string, options?: ContentListOptions): Promise<string[]>
  exists(uri: string, options?: ContentExistsOptions): Promise<boolean>

  // Observation
  observe(
    observer: ContentChangeObserver,
    options?: ObserveOptions
  ): Unsubscribe

  // Resource management
  dispose(): Promise<void>
}

ContentAdapter

The ContentAdapter connects to specific storage backends:

typescript
interface ContentAdapter {
  // Core operations
  read(uri: string, options?: any): Promise<Content>
  write(uri: string, content: Content, options?: any): Promise<void>
  delete(uri: string, options?: any): Promise<void>
  list(pattern: string, options?: any): Promise<string[]>

  // Optional operations
  exists?(uri: string, options?: any): Promise<boolean>

  // Events (if supported)
  events?: EventEmitter

  // Resource management
  dispose(): Promise<void>
}

Middleware

Middleware functions enhance operations:

typescript
type Middleware<T = ContentContext> = (
  context: T,
  next: () => Promise<T>
) => Promise<T>

interface ContentContext {
  operation: string
  uri: string
  content?: Content
  options?: Record<string, any>
  result?: any
}

Data Flow

The standard data flow for a content operation:

┌──────────┐    ┌──────────┐    ┌──────────────┐    ┌──────────┐    ┌──────────┐
│  Client  │───▶│  Store   │───▶│  Middleware  │───▶│ Adapter  │───▶│ Storage  │
│          │◀───│          │◀───│     Chain    │◀───│          │◀───│          │
└──────────┘    └──────────┘    └──────────────┘    └──────────┘    └──────────┘
  1. Client calls store operation (e.g., store.read('blog/post.md'))
  2. Store prepares operation context and initiates middleware chain
  3. Middleware processes the context (validation, caching, etc.)
  4. Adapter translates to storage-specific operations
  5. Storage performs the physical operation
  6. Result flows back through adapter, middleware chain, and store
  7. Client receives the final result

Extension Mechanisms

Middleware

Middleware is the primary extension mechanism, enhancing content operations with additional capabilities:

typescript
// Create a simple logging middleware
function withLogging(options = {}): Middleware {
  return async (context, next) => {
    console.log(`Before ${context.operation}: ${context.uri}`)

    // Continue the middleware chain
    const result = await next()

    console.log(`After ${context.operation}: ${context.uri}`)
    return result
  }
}

// Apply middleware to a store
const enhancedStore = pipe(baseStore, withLogging(), withValidation(schema))

Custom Adapters

Custom adapters allow integration with different storage systems:

typescript
// Create custom adapter
const customAdapter = createAdapter({
  read: async uri => {
    // Custom read implementation
    const data = await customReadImplementation(uri)
    return {
      data,
      contentType: determineContentType(uri),
      metadata: {},
    }
  },

  write: async (uri, content) => {
    // Custom write implementation
    await customWriteImplementation(uri, content)
  },

  delete: async uri => {
    // Custom delete implementation
    await customDeleteImplementation(uri)
  },

  list: async pattern => {
    // Custom list implementation
    return customListImplementation(pattern)
  },
})

Environment Adapability

The system adapts to different runtime environments:

Node.js (Server)

In Node.js, the system leverages filesystem capabilities:

typescript
// Create content store with filesystem adapter
const store = createContentStore({
  adapter: createFileSystemAdapter({
    baseDir: './content',
    watch: true, // Enable real-time file watching
  }),
})

Browser

In browsers, the system uses IndexedDB, localStorage, or HTTP:

typescript
// Create content store with IndexedDB adapter
const store = createContentStore({
  adapter: createIndexedDBAdapter({
    dbName: 'content-store',
    storeName: 'content',
  }),
})

Service Worker

For offline capabilities, the system uses service worker caching:

typescript
// Create content store with service worker adapter
const store = createContentStore({
  adapter: createServiceWorkerAdapter({
    cacheStrategy: 'network-first',
  }),
})

Architectural Decisions

The key architectural decisions are documented in Architecture Decision Records (ADRs):

For more detailed information:

Released under the MIT License.