Skip to content

MDX System Implementation TODO

Core Architecture

Our MDX system follows these principles:

  1. Clean Separation of Concerns: ✅

    • Component layer: Displays MDX content, no implementation details ✅
    • Hook layer: Coordinates content requests and component creation ✅
    • Registry layer: Determines content source and handles caching ⚠️ (Partially Implemented)
    • Processor layer: Handles compilation and frontmatter extraction ✅
    • Adapter layer: Fetches raw content from different sources ✅
  2. Data Flow: ✅

    • Data flows from inner modules upward ✅
    • Inner modules make decisions about their domain ✅
    • Each module returns fully-processed data to its caller ✅
  3. Features Implemented:

    • Enhanced MDX component factory with modern React patterns ✅
    • Basic content type enhancements ✅
    • Content watching capabilities in adapters (but not in registry) ⚠️
    • Robust error handling with proper boundaries ✅
    • Integration with MDX v3 ✅
    • Telemetry with logging and tracing throughout ✅
    • Content loading with React hooks ✅
  4. Features Planned But Not Implemented:

    • Advanced registry capabilities (watching, paths, metadata) ⏳
    • Registry capabilities interface ⏳
    • Enhanced content type system with SEO metadata ⏳
    • Content identifier interface for precise lookup ⏳
    • Comprehensive testing ⏳

Implementation Tasks

1. Fix UnifiedRegistry Implementation ⚠️ (Partially Complete)

  1. UnifiedRegistry in /src/lib/content/registries/registry.ts manages both static and dynamic content, but is missing some features:

    typescript
    export class UnifiedRegistry implements ContentRegistry {
      private static instance: UnifiedRegistry
      private staticRegistry: StaticRegistry
      private dynamicRegistry: DynamicRegistry
      private cache: Map<string, MdxData> = new Map()
    
      constructor(baseUrl?: string) {
        this.staticRegistry = new StaticRegistry()
        this.dynamicRegistry = new DynamicRegistry(baseUrl)
      }
    
      static getInstance(baseUrl?: string): UnifiedRegistry {
        if (!UnifiedRegistry.instance) {
          UnifiedRegistry.instance = new UnifiedRegistry(baseUrl)
        }
        return UnifiedRegistry.instance
      }
    
      /**
       * Check if content is available in any registry
       */
      isContentAvailable = traceAsync(
        'isContentAvailable',
        async (path: string): Promise<boolean> => {
          logger.debug('Checking content availability', { path })
    
          // Check cache first
          if (this.cache.has(path)) {
            logger.debug('Content found in cache', { path })
            return true
          }
    
          // Try static registry
          if (await this.staticRegistry.isContentAvailable(path)) {
            logger.debug('Content found in static registry', { path })
            return true
          }
    
          // Try dynamic registry as fallback
          const isDynamicAvailable =
            await this.dynamicRegistry.isContentAvailable(path)
          logger.debug('Content availability check complete', {
            path,
            isDynamicAvailable,
          })
    
          return isDynamicAvailable
        }
      )
    
      /**
       * Get content from the most appropriate registry
       */
      getContent = traceAsync(
        'getContent',
        async (path: string, options?: ContentOptions): Promise<MdxData> => {
          const timer = logger.startTimer('getContent')
    
          try {
            // Check cache unless force refresh requested
            if (!options?.forceRefresh && this.cache.has(path)) {
              logger.debug('Returning cached content', { path })
              timer.end('success', { source: 'cache' })
              return this.cache.get(path)!
            }
    
            let mdxData: MdxData
            let source: RegistrySource
    
            // Try static registry first
            if (await this.staticRegistry.isContentAvailable(path)) {
              logger.debug('Loading from static registry', { path })
              mdxData = await this.staticRegistry.getContent(path)
              source = 'static'
            } else {
              // Fall back to dynamic registry
              logger.debug('Loading from dynamic registry', { path })
              mdxData = await this.dynamicRegistry.getContent(path)
              source = 'dynamic'
            }
    
            // Cache the result
            this.cache.set(path, mdxData)
    
            logger.debug('Content retrieved successfully', {
              path,
              source,
              codeLength: mdxData.code.length,
              frontmatterKeys: Object.keys(mdxData.frontmatter),
            })
    
            timer.end('success', { source })
            return mdxData
          } catch (error) {
            logger.error('Error getting content', error as Error, { path })
            timer.end('error')
            throw error
          }
        }
      )
    }

    TODO:

    • Add content watching capabilities - missing watchContent method that forwards to dynamic registry
    • Add content listing with getContentPaths method
    • Add registry capabilities interface

2. Implement MDX Compiler ✅

  1. Completed the MDX compiler in /src/lib/mdx/processor/compiler.ts:

    typescript
    export const compileMdx = traceAsync(
      'compileMdx',
      async (
        source: VFileCompatible,
        metadata: ContentMeta = {}
      ): Promise<MdxData> => {
        const timer = logger.startTimer('compileMdx')
    
        try {
          // Get source length for logging
          const sourceLength =
            typeof source === 'string'
              ? source.length
              : source instanceof Uint8Array
                ? source.length
                : typeof source === 'object' &&
                    source !== null &&
                    'toString' in source
                  ? source.toString().length
                  : 0
    
          logger.debug('Compiling MDX content', {
            contentLength: sourceLength,
            metadataKeys: Object.keys(metadata),
          })
    
          // Compile MDX to JavaScript with our default options
          const result = await compile(source, {
            outputFormat: 'function-body',
            development: isDevelopment(),
            remarkPlugins: [
              remarkFrontmatter,
              [remarkMdxFrontmatter, { name: 'frontmatter' }],
            ],
          })
    
          // Get the compiled code
          const code = String(result)
    
          // Create the final MDX data object
          const mdxData: MdxData = {
            code,
            frontmatter: metadata,
            source: typeof source === 'string' ? source : String(source),
            compilationMode: 'function-body',
            timestamp: Date.now(),
          }
    
          logger.debug('MDX compilation successful', {
            codeLength: code.length,
            frontmatterKeys: Object.keys(metadata),
          })
    
          timer.end('success')
          return mdxData
        } catch (error) {
          timer.end('error')
          logger.error('Error compiling MDX content', error as Error)
          throw error
        }
      }
    )

    Enhancements Added:

    • Support for different MDX output formats
    • Added timestamp tracking for cache invalidation
    • Added support for MDX v3 compilation options
    • Integrated proper error handling with telemetry

3. Implement Component Factory ✅

  1. Created a modern MDX component factory in /src/lib/mdx/processor/component-factory.tsx:

    typescript
    export const createMdxComponent = traceSync(
      'createMdxComponent',
      (code: string, options: ComponentOptions = {}): MdxComponent => {
        const timer = logger.startTimer('createMdxComponent')
    
        try {
          if (!code) {
            logger.warn('No code provided to createMdxComponent')
            timer.end('error', { reason: 'empty_code' })
            return () => <div>Error: No content available&lt;/div&gt;
          }
    
          logger.debug('Creating MDX component', {
            codeLength: code.length,
            hasExportDefault: code.includes('export default'),
            hasModuleExports: code.includes('module.exports'),
          })
    
          // For precompiled MDX (with export default or module.exports)
          if (code.includes('export default') || code.includes('module.exports')) {
            const component = getMDXComponent(code, options.scope)
            timer.end('success', { compilationType: 'precompiled' })
            return component
          }
    
          // For function-body MDX (MDX v3 compiler with function-body output)
          const MDXContentWrapper: MdxComponent = (props) => {
            // Get components from context and props
            const mdxComponents = useMDXComponents({
              ...options.components,
              ...props.components
            })
    
            try {
              // MDX v3 needs these runtime variables
              const Fragment = runtime.Fragment
              const jsx = runtime.jsx
              const jsxs = runtime.jsxs
              const jsxDEV = isDevelopment() ? runtime.jsxDEV || runtime.jsx : undefined
    
              // MDX v3 component provider function
              const _provideComponents = () => mdxComponents
    
              try {
                // Execute the MDX code to get the component function
                const mdxFunction = new Function(
                  'React',
                  'Fragment',
                  'jsx',
                  'jsxs',
                  'jsxDEV',
                  '_provideComponents',
                  `
                  ${code}
    
                  // Return the MDXContent function (created by the MDX compiler)
                  return typeof MDXContent === 'function' ? MDXContent : null;
                  `
                )(
                  React,
                  Fragment,
                  jsx,
                  jsxs,
                  jsxDEV,
                  _provideComponents
                )
    
                // Execute the component with props
                if (typeof mdxFunction === 'function') {
                  return mdxFunction({
                    ...props,
                    components: mdxComponents
                  })
                } else {
                  logger.error('Invalid MDX output: not a function', {
                    type: typeof mdxFunction
                  })
                  return <div className="mdx-error">Invalid MDX component&lt;/div&gt;
                }
              } catch (execError) {
                logger.error('Error executing MDX function', execError as Error)
                return (
                  <div className="mdx-error">
                    <h2>Error Rendering MDX&lt;/h2&gt;
                    <p>{execError instanceof Error ? execError.message : String(execError)}</p>
                  </div>
                )
              }
            } catch (error) {
              logger.error('Error rendering MDX', error as Error)
              return (
                <div className="mdx-error">
                  <h2>MDX Component Error&lt;/h2&gt;
                  <p>{error instanceof Error ? error.message : String(error)}</p>
                </div>
              )
            }
          }
    
          timer.end('success', { compilationType: 'function-body' })
          return MDXContentWrapper
        } catch (error) {
          logger.error('Error creating MDX component', error as Error)
          timer.end('error')
          return () => (
            <div className="mdx-error">
              <h2>Error Creating MDX Component&lt;/h2&gt;
              <p>{error instanceof Error ? error.message : String(error)}</p>
            </div>
          )
        }
      }
    )

    Enhancements Added:

    • Support for both MDX v3 compilation modes (function-body and program)
    • Robust error handling with detailed error boundaries
    • Debug information for development mode
    • Proper component display names for better debugging
    • Integration with telemetry for performance tracking

4. Implement Clean MDX Hook ✅

  1. Created enhanced hooks in /src/lib/mdx/loader/hooks.tsx with proper lifecycle management:

    typescript
    /**
     * Hook to load MDX content from the registry
     */
    export function useMdxContent(
      contentPath: string,
      options?: ContentOptions
    ): ContentLoadResult {
      const [state, setState] = useState & lt
      ContentLoadState & gt
      ;({
        content: null,
        isLoading: true,
        error: null,
        status: 'loading',
      })
    
      const refresh = useCallback(async () => {
        if (!contentPath) return
    
        setState(prev => ({ ...prev, isLoading: true, status: 'loading' }))
        const timer = logger.startTimer('useMdxContent.refresh')
    
        try {
          // Normalize path (remove .mdx extension if present)
          const normalizedPath = contentPath.replace(/\.mdx$/, '')
    
          // Check if content is available in any registry
          const isAvailable =
            await contentRegistry.isContentAvailable(normalizedPath)
    
          if (!isAvailable) {
            throw new Error(`Content not found: ${normalizedPath}`)
          }
    
          // Get content from registry (handles static vs dynamic automatically)
          const mdxData = await contentRegistry.getContent(normalizedPath, {
            forceRefresh: options?.forceRefresh,
          })
    
          logger.debug('Content loaded successfully', {
            path: normalizedPath,
            frontmatterKeys: Object.keys(mdxData.frontmatter),
            codeLength: mdxData.code.length,
          })
    
          setState({
            content: mdxData,
            isLoading: false,
            error: null,
            status: 'success',
          })
    
          timer.end('success')
        } catch (err) {
          const error = err instanceof Error ? err : new Error(String(err))
          logger.error(`Failed to load content: ${contentPath}`, error, {
            options,
          })
    
          setState({
            content: null,
            isLoading: false,
            error,
            status: 'error',
          })
    
          timer.end('error')
        }
      }, [contentPath, options?.forceRefresh, options?.baseUrl])
    
      // Setup content watching if adapter supports it
      useEffect(() => {
        let unsubscribe: (() => void) | undefined
        let isMounted = true
    
        // Initial content load
        refresh()
    
        // Setup watching if supported and requested
        if (options?.watch && contentRegistry.watchContent) {
          try {
            unsubscribe = contentRegistry.watchContent(
              contentPath,
              updatedContent => {
                if (isMounted) {
                  logger.debug('Content updated via watcher', { contentPath })
                  setState({
                    content: updatedContent,
                    isLoading: false,
                    error: null,
                    status: 'success',
                  })
                }
              }
            )
          } catch (err) {
            logger.warn('Failed to setup content watching', err as Error)
          }
        }
    
        return () => {
          isMounted = false
          if (unsubscribe) {
            unsubscribe()
          }
        }
      }, [contentPath, refresh, options?.watch])
    
      return {
        ...state,
        refresh,
      }
    }
    
    /**
     * Hook to check if content is available
     */
    export function useContentAvailability(
      contentPath: string,
      options?: ContentOptions
    ): { isAvailable: boolean; isLoading: boolean; error: Error | null } {
      const [state, setState] = useState<{
        isAvailable: boolean
        isLoading: boolean
        error: Error | null
      }>({
        isAvailable: false,
        isLoading: true,
        error: null,
      })
    
      useEffect(() => {
        let isMounted = true
    
        async function checkAvailability() {
          try {
            if (!contentPath) {
              if (isMounted) {
                setState({ isAvailable: false, isLoading: false, error: null })
              }
              return
            }
    
            // Normalize path
            const normalizedPath = contentPath.replace(/\.mdx$/, '')
    
            // Check availability
            const isAvailable =
              await contentRegistry.isContentAvailable(normalizedPath)
    
            if (isMounted) {
              setState({
                isAvailable,
                isLoading: false,
                error: null,
              })
            }
          } catch (err) {
            if (isMounted) {
              setState({
                isAvailable: false,
                isLoading: false,
                error: err instanceof Error ? err : new Error(String(err)),
              })
            }
          }
        }
    
        checkAvailability()
    
        return () => {
          isMounted = false
        }
      }, [contentPath, options?.baseUrl])
    
      return state
    }

    Enhancements Added:

    • Extended hook system with useContentAvailability and useContentPaths
    • Added content watching capabilities via adapter pattern
    • Improved memory management with proper cleanup functions
    • Added support for manual content refresh via refresh function
    • Enhanced error handling with detailed error states

5. Simplify MdxContent Component ✅

  1. Enhanced the MdxContent component in /src/components/content/MdxContent.tsx with advanced features:

    typescript
    export default function MdxContent({
      contentPath,
      components = {},
      fallback = <div>Loading content...</div>,
      source,
      baseUrl,
      forceRefresh,
      scope = {},
      rawContent,
      onContentRendered,
      onError,
      debug = isDevelopment(),
    }: MdxContentProps) {
      // Configure content loading options
      const contentOptions: ContentOptions = {
        source,
        baseUrl,
        forceRefresh,
        watch: true,  // Enable content watching
      };
    
      // Use raw content directly if provided
      const useRawContent = Boolean(rawContent);
    
      // Load MDX content using the hook if no rawContent provided
      const { content, isLoading, error, status, refresh } = useRawContent
        ? {
            content: rawContent ? {
              code: rawContent,
              frontmatter: {},
              source: 'direct-injection',
              timestamp: Date.now()
            } : null,
            isLoading: false,
            error: null,
            status: rawContent ? 'success' as const : 'error' as const,
            refresh: () => Promise.resolve()
          }
        : useMdxContent(contentPath, contentOptions);
    
      // Create MDX component if content is available
      const MdxComponent = useMemo(() => {
        if (!content?.code) {
          return null;
        }
    
        try {
          // Combine provided scope with frontmatter
          const mergedScope = {
            ...content.frontmatter,
            ...scope,
            contentPath,
            refreshContent: refresh
          };
    
          // Create component from the MDX code
          return createMdxComponent(content.code, {
            scope: mergedScope,
            components
          });
        } catch (err) {
          const error = err instanceof Error ? err : new Error(String(err));
          logger.error('Error creating MDX component', error, { contentPath });
    
          if (onError) {
            onError(error);
          }
    
          return null;
        }
      }, [content?.code, content?.frontmatter, components, scope, contentPath, refresh, onError]);
    
      // Call onContentRendered callback when content is available
      useEffect(() => {
        if (content && onContentRendered) {
          onContentRendered(content);
        }
      }, [content, onContentRendered]);
    
      // Handle loading state
      if (isLoading) {
        return <>{fallback}</>;
      }
    
      // Handle error state
      if (error || !MdxComponent) {
        const displayError = error || new Error('Failed to create MDX component');
    
        if (onError && error) {
          onError(displayError);
        }
    
        return (
          <div className="mdx-error">
            <h2>Error Loading Content&lt;/h2&gt;
            <p>{displayError.message}</p>
            {debug && (
              <details>
                <summary>Technical Details&lt;/summary&gt;
                <pre>
                  {JSON.stringify(
                    {
                      contentPath,
                      source,
                      status,
                      error: displayError.toString(),
                      stack: displayError.stack
                    },
                    null,
                    2
                  )}
                </pre>
              </details>
            )}
            {debug && (
              <button onClick={refresh} className="mdx-refresh-button">
                Retry Loading
              </button>
            )}
          </div>
        );
      }
    
      try {
        // Render the MDX content with provided components
        return <MdxComponent components={components} />;
      } catch (renderError) {
        const displayError = renderError instanceof Error
          ? renderError
          : new Error(String(renderError));
    
        logger.error('Error rendering MDX content', displayError, { contentPath });
    
        if (onError) {
          onError(displayError);
        }
    
        return (
          <div className="mdx-error">
            <h2>Error Rendering Content&lt;/h2&gt;
            <p>{displayError.message}</p>
            {debug && (
              <details>
                <summary>Technical Details&lt;/summary&gt;
                <pre>
                  {JSON.stringify(
                    {
                      contentPath,
                      source,
                      error: displayError.toString(),
                      stack: displayError.stack
                    },
                    null,
                    2
                  )}
                </pre>
              </details>
            )}
          </div>
        );
      }
    }

    Enhancements Added:

    • Support for raw MDX content injection
    • Debug mode for development environments
    • Callback hooks for content rendering and error handling
    • Content refresh button in error states
    • Extended component props for better customization
    • Enhanced error display with technical details
    • Content change watching via adapter interfaces

6. Update Types and Interfaces ⚠️ (Partially Complete)

  1. Types in /src/lib/mdx/processor/types.ts have been updated, but are less comprehensive than planned:

    typescript
    /**
     * Interface for MDX content data
     */
    export interface MdxData {
      /** Compiled MDX code ready for component creation */
      code: string
    
      /** Frontmatter metadata extracted from the content */
      frontmatter: ContentMeta
    
      /** Original source path or content identifier */
      source: string
    
      /** Optional compilation mode information */
      compilationMode?: 'function-body' | 'program' | 'precompiled'
    
      /** Optional source type */
      sourceType?: ContentSource
    
      /** Timestamp for when the content was compiled/fetched */
      timestamp?: number
    }
    
    /**
     * Options for MDX component creation
     */
    export interface ComponentOptions {
      /** Component mapping to use for MDX rendering */
      components?: MDXComponents
    
      /** Variables to make available in MDX scope */
      scope?: Record&lt;string, unknown&gt;
    
      /** Development mode flag */
      development?: boolean
    
      /** Display name for debugging */
      displayName?: string
    }
    
    /**
     * MDX component function type
     */
    export type MdxComponent = ComponentType&lt;PropsWithChildren&lt;MDXProps&gt;&gt;
  2. Content registry interface in /src/lib/content/registries/types.ts is missing planned features:

    typescript
    /**
     * Content registry interface
     */
    export interface ContentRegistry {
      /**
       * Check if content is available in this registry
       *
       * @param path Content path to check
       * @returns Boolean indicating if the content exists
       */
      isContentAvailable(path: string): Promise&lt;boolean&gt;
    
      /**
       * Get content from this registry
       *
       * @param path Content path to retrieve
       * @param options Optional settings for content retrieval
       * @returns Promise resolving to the processed MDX data
       */
      getContent(path: string, options?: ContentOptions): Promise&lt;MdxData&gt;
    }
    
    /**
     * Options for content retrieval
     */
    export interface ContentOptions {
      /**
       * Whether to bypass the cache and force a fresh retrieval
       */
      forceRefresh?: boolean
    }
  3. Content adapter types in /src/lib/content/adapters/types.ts have been updated with watch support:

    typescript
    /**
     * Content Adapter Types
     *
     * This module defines the interfaces and types for content adapters.
     */
    
    import { ContentMediaType } from '@lib/content/types'
    
    /**
     * Raw content interface representing unprocessed content
     */
    export interface RawContent {
      content: string
      contentType: ContentMediaType
    }
    
    /**
     * Callback function type for content watchers
     */
    export type ContentUpdate = (content: RawContent) => void
    
    /**
     * Unsubscribe function type for content watchers
     */
    export type Unsubscribe = () => void
    
    /**
     * Base content adapter interface
     */
    export interface ContentAdapter {
      /**
       * Get content from this source
       *
       * @param id Content identifier/path
       * @returns Promise resolving to raw content
       */
      getContent(id: string): Promise&lt;RawContent&gt;
    
      /**
       * Subscribe to content changes (optional)
       *
       * @param id Content identifier/path
       * @param callback Function to call when content changes
       * @returns Unsubscribe function
       */
      watchContent?(
        id: string,
        callback: (content: RawContent) => void
      ): Unsubscribe
    
      /**
       * Whether this adapter supports real-time updates
       */
      readonly supportsRealtime: boolean
    }

    TODO:

    • Enhance ContentRegistry interface with watchContent method
    • Add getContentPaths and getContentMeta to ContentRegistry interface
    • Add registry capabilities interface with getCapabilities method
    • Add ContentIdentifier interface for precise content lookup

7. Testing and Verification ⏳

  1. TODO: Add tests for the registry to verify correct behavior:

    typescript
    // Test the UnifiedRegistry in isolation
    describe('UnifiedRegistry', () => {
      it('checks static registry first', async () => {
        const registry = new UnifiedRegistry()
        const mockStaticResult = { default: 'static content', title: 'Static' }
    
        // Mock dependencies
        registry['staticRegistry'].isContentAvailable = jest
          .fn()
          .mockResolvedValue(true)
        registry['staticRegistry'].getContent = jest
          .fn()
          .mockResolvedValue(mockStaticResult)
        registry['dynamicRegistry'].isContentAvailable = jest.fn()
    
        const result = await registry.getContent('test/path')
    
        expect(registry['staticRegistry'].isContentAvailable).toHaveBeenCalled()
        expect(
          registry['dynamicRegistry'].isContentAvailable
        ).not.toHaveBeenCalled()
        expect(result.frontmatter.title).toBe('Static')
      })
    
      it('falls back to dynamic registry when static fails', async () => {
        const registry = new UnifiedRegistry()
        const mockDynamicResult = {
          default: 'dynamic content',
          title: 'Dynamic',
        }
    
        // Mock dependencies
        registry['staticRegistry'].isContentAvailable = jest
          .fn()
          .mockResolvedValue(false)
        registry['dynamicRegistry'].isContentAvailable = jest
          .fn()
          .mockResolvedValue(true)
        registry['dynamicRegistry'].getContent = jest
          .fn()
          .mockResolvedValue(mockDynamicResult)
    
        const result = await registry.getContent('test/path')
    
        expect(registry['staticRegistry'].isContentAvailable).toHaveBeenCalled()
        expect(registry['dynamicRegistry'].isContentAvailable).toHaveBeenCalled()
        expect(result.frontmatter.title).toBe('Dynamic')
      })
    })
  2. TODO: Add an E2E test for the MDX rendering flow:

    typescript
    it('renders MDX content from the registry', async () => {
      // Mock the contentRegistry
      const mockMdxData = {
        code: 'function MDXContent() { return jsx("h1", { children: "Hello World" }); }',
        frontmatter: { title: 'Test Page' },
        source: 'test'
      }
    
      contentRegistry.isContentAvailable = jest.fn().mockResolvedValue(true)
      contentRegistry.getContent = jest.fn().mockResolvedValue(mockMdxData)
    
      // Render the component with React Testing Library
      const { findByText } = render(<MdxContent contentPath="test/path" />)
    
      // Verify content renders
      expect(await findByText('Hello World')).toBeInTheDocument()
    })

8. Integration Testing ⏳

  1. TODO: Test these scenarios in the browser:

    • Static content rendering
    • Dynamic content rendering
    • Error handling
    • Component mapping/overrides
  2. TODO: Verify the data flow with browser devtools:

    • Registry caching
    • Component creation
    • Frontmatter extraction

Implementation Guidelines

  1. Error Handling: ✅ Thorough error handling has been implemented across all modules
  2. Logging: ✅ Contextual logging with proper telemetry integration
  3. Typings: ⚠️ Some interfaces and types still need enhancement
  4. Performance: ⚠️ Basic caching implemented, but needs more optimization
  5. Clean Code: ✅ Maintained good separation of concerns throughout

Post-Implementation

  1. Documentation: ⏳ TODO: Update project docs with the new architecture

    • Update /docs/content/ with implementation details
    • Create diagrams showing the content flow
    • Document the registry and adapter patterns
  2. Examples: ⏳ TODO: Create example content for different scenarios

    • Add example for static content rendering
    • Add example for dynamic content loading
    • Add example for content watching
  3. Performance Testing: ⏳ TODO: Verify caching behavior works as expected

    • Test with large content sets
    • Measure render times
    • Profile memory usage

April 2025 Updates

Architectural Review & Refactoring Plan

  1. Architecture Assessment

    • Analyzed the dependency relationships
    • Identified API mismatches and inconsistent implementations
    • Documented type safety issues and interface inconsistencies
    • Assessed the adapter and registry implementation patterns
  2. New Architecture Proposal

    • Designed cleaner top-down architecture: React Components → Registry → Loader → (Processor | Adapter)
    • Planned Registry as Facade pattern
    • Designed Loader as Strategy Provider pattern
    • Outlined pluggable processor and adapter registry system
    • Created React hook factory pattern for component integration
  3. Identified Implementation Issues

    • ContentAdapter interface missing essential methods
    • Inconsistent implementations of ContentRegistry interface
    • Parameter type mismatches in strategy implementations
    • Missing or incorrect typings for core interfaces
    • Multiple interface/type definition inconsistencies
  4. Next Steps Planned

    • Created detailed implementation plan for the new architecture
    • Documented standardized interfaces for the new system
    • Outlined phase-based migration approach
    • Created new ADR for the architectural changes
    • Updated architecture documentation with the proposed design

Released under the MIT License.