Home / guides / TROUBLESHOOTING

LARC Troubleshooting Guide

Version: 1.0 Last Updated: November 2024 Status: Production Ready

Comprehensive troubleshooting guide for LARC (Lightweight Asynchronous Relay Core). This guide provides practical solutions to common issues, debugging techniques, and step-by-step diagnostic workflows.


Table of Contents

  • Quick Reference: Common Issues
  • Components Not Loading
  • Messages Not Being Delivered
  • Bus Not Ready Errors
  • Module Resolution Failures
  • Memory Leaks and Performance
  • CORS and CDN Issues
  • CSP Violations
  • Debugging Tools and Techniques
  • Error Messages Reference
  • Browser Compatibility Issues
  • Integration Issues
  • Development vs Production Issues
  • Diagnostic Workflows
  • Getting Help

  • 1. Quick Reference: Common Issues

    1.1 Most Common Problems

    | Problem | Quick Fix | Section | |---------|-----------|---------| | Component not loading | Check data-module attribute, verify path | 2.1 | | Messages not received | Wait for bus.ready(), check topic pattern | 3.1 | | Bus not ready | Ensure element exists in DOM | 4.1 | | CDN 404 error | Pin CDN version, check URL format | 7.1 | | CSP blocking scripts | Add CDN to script-src directive | 8.1 | | Retained messages not working | Use { retained: true } in subscribe options | 3.3 | | Memory growing | Unsubscribe when done, avoid circular refs | 6.1 | | Request timeout | Verify responder is subscribed, increase timeout | 3.5 |

    1.2 Emergency Checklist

    If LARC isn't working at all, check these in order:

  • [ ] Is in the DOM?
  • [ ] Are browser DevTools showing any console errors?
  • [ ] Is the browser modern enough? (Chrome 90+, Firefox 88+, Safari 14+)
  • [ ] Are module scripts loading? (Check Network tab)
  • [ ] Is CSP blocking resources?
  • [ ] Is CDN accessible? (Try loading URL directly)

  • 2. Components Not Loading

    2.1 Component Not Defined

    Problem: Custom element appears but doesn't render. Console shows: Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry' Symptoms:
    • Element shows as :not(:defined) in DevTools
    • Component appears as plain text in DOM
    • No functionality
    Common Causes:

    #### 2.1.1 Component File Not Found

    <!-- Wrong: File doesn't exist -->
    <my-component></my-component>
    <!-- Autoloader looks for: ./components/my-component.mjs -->
    Solution:
    # Verify file exists
    ls ./components/my-component.mjs
    
    # Or specify explicit path
    <my-component data-module="/path/to/component.mjs"></my-component>

    #### 2.1.2 Component Path Configuration

    // Check autoloader configuration
    console.log(window.panAutoload.config);
    // Should show:
    // {
    //   baseUrl: "...",
    //   componentsPath: "./components/",
    //   extension: ".mjs"
    // }
    
    // Fix configuration before loading pan.mjs
    window.panAutoload = {
      baseUrl: '/static/',
      componentsPath: './components/',
      extension: '.mjs'
    };

    #### 2.1.3 Component Not Exported Properly

    // ❌ WRONG: No export
    class MyComponent extends HTMLElement {
      // ...
    }
    customElements.define('my-component', MyComponent);
    
    // ✅ CORRECT: Export as default
    class MyComponent extends HTMLElement {
      // ...
    }
    export default MyComponent;

    #### 2.1.4 Naming Mismatch

    // ❌ WRONG: Tag name doesn't match class
    <my-widget></my-widget>
    // File: my-component.mjs (name doesn't match tag)
    
    // ✅ CORRECT: Match tag name to filename
    <my-widget></my-widget>
    // File: my-widget.mjs
    Debugging Steps:
  • Check console for errors
  • // Look for module loading errors
       // Open DevTools Console and check for 404s or import errors
  • Verify autoloader saw the element
  • // Check if element was observed
       const el = document.querySelector('my-component');
       console.log('Is custom tag:', el.tagName.includes('-'));
       console.log('Is defined:', customElements.get(el.localName));
  • Manually load component
  • // Force load to see error
       await window.panAutoload.maybeLoadFor(
         document.querySelector('my-component')
       );
  • Check Network tab
  • - Look for 404 errors on .mjs files - Verify correct URL is being requested - Check CORS headers if loading from CDN

    2.2 Module Import Errors

    Problem: Component file loads but import fails Symptoms:
    Uncaught SyntaxError: Cannot use import statement outside a module
    Solutions:

    #### 2.2.1 Missing type="module"

    <!-- ❌ WRONG -->
    <script src="./pan.mjs"></script>
    
    <!-- ✅ CORRECT -->
    <script type="module" src="./pan.mjs"></script>

    #### 2.2.2 Relative Import Path Issues

    // ❌ WRONG: Relative import without extension
    import { PanClient } from './pan-client';
    
    // ✅ CORRECT: Include extension
    import { PanClient } from './pan-client.mjs';
    
    // ✅ ALSO CORRECT: Absolute or CDN URL
    import { PanClient } from 'https://unpkg.com/@larcjs/core@3.0.1/pan-client.mjs';

    2.3 Autoloader Not Running

    Problem: Components never load, no errors in console Symptoms:
    • Elements remain :not(:defined)
    • Network tab shows no component requests
    • window.panAutoload is undefined
    Solutions:

    #### 2.3.1 Check Autoloader Loaded

    // Verify autoloader is present
    if (!window.panAutoload) {
      console.error('Autoloader not loaded!');
      // Check if pan.mjs was loaded correctly
    }

    #### 2.3.2 Check IntersectionObserver Support

    // Verify browser support
    if (!('IntersectionObserver' in window)) {
      console.error('IntersectionObserver not supported');
      // Load polyfill or manually load components
    }

    #### 2.3.3 Manually Trigger Observation

    // Force observation of element
    const container = document.querySelector('#dynamic-content');
    window.panAutoload.observeTree(container);

    2.4 Dynamic Components Not Loading

    Problem: Components added via JavaScript don't auto-load Solution:
    // After adding elements dynamically, trigger observation
    const container = document.querySelector('#app');
    container.innerHTML = '<my-component></my-component>';
    
    // Trigger autoloader
    window.panAutoload.observeTree(container);
    
    // OR manually load
    const el = container.querySelector('my-component');
    await window.panAutoload.maybeLoadFor(el);

    3. Messages Not Being Delivered

    3.1 Subscriber Not Receiving Messages

    Problem: Published messages don't reach subscriber Debugging Steps:

    #### 3.1.1 Verify Bus is Ready

    // ❌ WRONG: Publish before bus ready
    const client = new PanClient();
    client.publish({ topic: 'test', data: {} }); // May be lost
    
    // ✅ CORRECT: Wait for ready
    const client = new PanClient();
    await client.ready();
    client.publish({ topic: 'test', data: {} });

    #### 3.1.2 Check Topic Matching

    // Debug topic matching
    const topic = 'users.item.updated';
    const pattern = 'users.*';
    
    // Check if pattern matches
    console.log('Matches:', PanClient.matches(topic, pattern));
    // false - pattern only matches one segment
    
    // Fix: Use correct pattern
    const correctPattern = 'users.item.*'; // or 'users.*.updated'
    console.log('Matches:', PanClient.matches(topic, correctPattern)); // true

    #### 3.1.3 Verify Subscription

    // Add debug logging to subscription
    client.subscribe('users.*', (msg) => {
      console.log('Received message:', msg);
      // If you see this, subscription works
    });
    
    // Test with a publish
    client.publish({
      topic: 'users.test',
      data: { test: true }
    });

    #### 3.1.4 Check Element Still in DOM

    // If subscribing from a component, ensure it's still connected
    class MyComponent extends HTMLElement {
      connectedCallback() {
        this.client = new PanClient(this);
    
        this.unsub = this.client.subscribe('data.*', (msg) => {
          if (!this.isConnected) {
            console.warn('Component disconnected but still receiving messages!');
            this.unsub(); // Clean up
          }
        });
      }
    
      disconnectedCallback() {
        // IMPORTANT: Unsubscribe when component removed
        if (this.unsub) this.unsub();
      }
    }

    3.2 Wildcard Subscriptions Not Working

    Problem: Wildcard patterns don't match expected topics Pattern Rules:
    // Single segment wildcard
    'users.*'         // Matches: users.list, users.item
                      // NOT: users.item.updated (2 segments after users)
    
    // Multiple wildcards
    '*.updated'       // Matches: users.updated, posts.updated
    'users.*.state'   // Matches: users.list.state, users.item.state
    
    // Global wildcard
    '*'               // Matches: ALL topics (use carefully!)
    Testing Patterns:
    // Test your patterns
    const testPatterns = [
      ['users.item.updated', 'users.*'],           // false
      ['users.item.updated', 'users.item.*'],      // true
      ['users.item.updated', '*.updated'],         // false
      ['users.item.updated', '*.*.updated'],       // true
      ['users.item.updated', 'users.*.updated'],   // true
      ['users.item.updated', '*'],                 // true
    ];
    
    testPatterns.forEach(([topic, pattern]) => {
      console.log(`${topic} ~ ${pattern} = ${PanClient.matches(topic, pattern)}`);
    });

    3.3 Retained Messages Not Delivered

    Problem: New subscriber doesn't receive retained message Solutions:

    #### 3.3.1 Enable Retained Option

    // ❌ WRONG: No retained option
    client.subscribe('app.state', (msg) => {
      // Won't receive retained message
    });
    
    // ✅ CORRECT: Request retained messages
    client.subscribe('app.state', (msg) => {
      // Will receive current state immediately
    }, { retained: true });

    #### 3.3.2 Verify Message Was Published with Retain

    // ❌ WRONG: No retain flag
    client.publish({
      topic: 'app.state',
      data: { theme: 'dark' }
      // Missing: retain: true
    });
    
    // ✅ CORRECT: Set retain flag
    client.publish({
      topic: 'app.state',
      data: { theme: 'dark' },
      retain: true  // Store for late subscribers
    });

    #### 3.3.3 Check Retention Limits

    // If using pan-bus with memory limits
    // Check if retained message was evicted
    document.querySelector('pan-bus').dispatchEvent(
      new CustomEvent('pan:sys.stats', { bubbles: true })
    );
    
    // Listen for stats
    document.addEventListener('pan:deliver', (e) => {
      if (e.detail.topic === 'pan:sys.stats') {
        console.log('Retained messages:', e.detail.data.retained);
        console.log('Evicted count:', e.detail.data.retainedEvicted);
      }
    }, { once: true });

    3.4 Messages Delayed or Out of Order

    Problem: Messages arrive late or in wrong order Causes & Solutions:

    #### 3.4.1 Heavy Processing in Handler

    // ❌ PROBLEM: Blocking handler
    client.subscribe('data.*', (msg) => {
      // Expensive synchronous operation blocks other messages
      const result = processHeavyData(msg.data); // Takes 100ms
      updateUI(result);
    });
    
    // ✅ SOLUTION: Use async processing
    client.subscribe('data.*', async (msg) => {
      // Process asynchronously
      const result = await processHeavyDataAsync(msg.data);
      updateUI(result);
    });
    
    // OR: Defer processing
    client.subscribe('data.*', (msg) => {
      setTimeout(() => {
        const result = processHeavyData(msg.data);
        updateUI(result);
      }, 0);
    });

    #### 3.4.2 Race Conditions

    // ❌ PROBLEM: Race condition
    let userData = null;
    client.subscribe('user.loaded', (msg) => {
      userData = msg.data; // May arrive after other messages
    });
    
    client.subscribe('user.action', (msg) => {
      // userData might still be null!
      processAction(userData, msg.data);
    });
    
    // ✅ SOLUTION: Use retained messages
    client.publish({
      topic: 'user.loaded',
      data: currentUser,
      retain: true  // Late subscribers get it immediately
    });
    
    client.subscribe('user.loaded', (msg) => {
      userData = msg.data;
    }, { retained: true }); // Get current user immediately

    3.5 Request Timeout

    Problem: client.request() times out Symptoms:
    Error: PAN request timeout
    Solutions:

    #### 3.5.1 Verify Responder is Subscribed

    // Make sure someone is listening!
    // Responder side:
    client.subscribe('api.user.get', (msg) => {
      if (!msg.replyTo) return; // Not a request
    
      // Process and reply
      const user = getUser(msg.data.id);
      client.publish({
        topic: msg.replyTo,
        data: { ok: true, item: user },
        correlationId: msg.correlationId
      });
    });
    
    // Requester side:
    try {
      const response = await client.request('api.user.get', { id: 123 });
      console.log('User:', response.data.item);
    } catch (err) {
      console.error('No responder available');
    }

    #### 3.5.2 Increase Timeout

    // Default timeout is 5000ms
    const response = await client.request('api.slow.operation', data, {
      timeoutMs: 10000  // Increase to 10 seconds
    });

    #### 3.5.3 Check for Reply Errors

    // Responder: Always send a reply, even on error
    client.subscribe('api.user.get', async (msg) => {
      if (!msg.replyTo) return;
    
      try {
        const user = await getUser(msg.data.id);
        client.publish({
          topic: msg.replyTo,
          data: { ok: true, item: user },
          correlationId: msg.correlationId
        });
      } catch (err) {
        // Send error reply instead of silence
        client.publish({
          topic: msg.replyTo,
          data: { ok: false, error: err.message },
          correlationId: msg.correlationId
        });
      }
    });

    4. Bus Not Ready Errors

    4.1 PAN Bus Element Missing

    Problem: window.__panReady is undefined, pan:sys.ready event never fires Symptoms:
    await client.ready(); // Never resolves
    Solutions:

    #### 4.1.1 Add Bus Element

    <!DOCTYPE html>
    <html>
    <head>
      <script type="module" src="./src/pan.mjs"></script>
    </head>
    <body>
      <!-- ✅ Add this -->
      <pan-bus></pan-bus>
    
      <my-app></my-app>
    </body>
    </html>

    #### 4.1.2 Ensure Bus Loads First

    // If creating bus programmatically
    import { ensureBus } from './src/pan.mjs';
    
    // Create bus before using client
    ensureBus();
    
    const client = new PanClient();
    await client.ready();

    #### 4.1.3 Check Bus is Defined

    // Verify bus custom element is defined
    if (!customElements.get('pan-bus')) {
      console.error('pan-bus not defined!');
      // Check if pan.mjs loaded correctly
    }
    
    // Check if bus exists in DOM
    const bus = document.querySelector('pan-bus');
    if (!bus) {
      console.error('pan-bus element not in DOM!');
    }

    4.2 Bus Ready Race Condition

    Problem: Client created before bus is ready Solution:
    // ❌ PROBLEM: Create client too early
    const client = new PanClient(); // Bus might not exist yet
    
    // ✅ SOLUTION 1: Wait for DOM ready
    document.addEventListener('DOMContentLoaded', async () => {
      const client = new PanClient();
      await client.ready();
      // Now safe to use
    });
    
    // ✅ SOLUTION 2: Wait for bus ready event
    document.addEventListener('pan:sys.ready', () => {
      const client = new PanClient();
      // Bus is guaranteed ready
    }, { once: true });
    
    // ✅ SOLUTION 3: Always await ready()
    const client = new PanClient();
    await client.ready(); // Waits for bus if needed
    client.publish({ topic: 'app.started', data: {} });

    4.3 Multiple Bus Elements

    Problem: Multiple elements in DOM Symptoms:
    • Duplicate message delivery
    • Unexpected behavior
    • Messages delivered multiple times
    Solution:
    // Check for multiple buses
    const buses = document.querySelectorAll('pan-bus');
    if (buses.length > 1) {
      console.error(`Found ${buses.length} bus elements! Should be 1.`);
      // Remove extras
      buses.forEach((bus, i) => {
        if (i > 0) bus.remove();
      });
    }

    5. Module Resolution Failures

    5.1 Relative Path Issues

    Problem: Module imports fail with 404 Symptoms:
    GET http://localhost/pan-client.mjs 404 (Not Found)
    Solutions:

    #### 5.1.1 Always Include Extension

    // ❌ WRONG: Missing .mjs extension
    import { PanClient } from './components/pan-client';
    
    // ✅ CORRECT: Include extension
    import { PanClient } from './components/pan-client.mjs';

    #### 5.1.2 Use Absolute Paths or Import Maps

    <!-- Import map for cleaner imports -->
    <script type="importmap">
    {
      "imports": {
        "larc": "/static/larc/pan.mjs",
        "larc/": "/static/larc/"
      }
    }
    </script>
    
    <script type="module">
    import { PanClient } from 'larc';
    import { PanBus } from 'larc/components/pan-bus.mjs';
    </script>

    5.2 CDN Module Resolution

    Problem: Components can't load when using CDN for core Solution:
    <script type="module">
      // Configure autoloader for CDN
      window.panAutoload = {
        baseUrl: 'https://unpkg.com/@larcjs/core@3.0.1/',
        componentsPath: './',
        extension: '.mjs'
      };
    </script>
    <script type="module" src="https://unpkg.com/@larcjs/core@3.0.1/src/pan.mjs"></script>

    5.3 Path Resolution with data-module

    Problem: Custom component paths not resolving Solutions:
    <!-- Relative to current page -->
    <my-component data-module="./widgets/my-component.mjs"></my-component>
    
    <!-- Absolute path -->
    <my-component data-module="/static/components/my-component.mjs"></my-component>
    
    <!-- CDN URL -->
    <my-component data-module="https://unpkg.com/my-package/component.mjs"></my-component>

    6. Memory Leaks and Performance

    6.1 Memory Leaks

    Problem: Memory usage grows over time Common Causes:

    #### 6.1.1 Subscriptions Not Cleaned Up

    // ❌ PROBLEM: Subscriptions leak
    class MyComponent extends HTMLElement {
      connectedCallback() {
        this.client = new PanClient(this);
        this.client.subscribe('data.*', this.handleData);
        // No cleanup when component removed!
      }
    
      handleData = (msg) => {
        this.render(msg.data);
      }
    }
    
    // ✅ SOLUTION: Always unsubscribe
    class MyComponent extends HTMLElement {
      connectedCallback() {
        this.client = new PanClient(this);
        // Store unsubscribe function
        this.unsub = this.client.subscribe('data.*', this.handleData);
      }
    
      disconnectedCallback() {
        // Clean up subscription
        if (this.unsub) this.unsub();
      }
    
      handleData = (msg) => {
        this.render(msg.data);
      }
    }
    
    // ✅ BETTER: Use AbortSignal
    class MyComponent extends HTMLElement {
      connectedCallback() {
        this.client = new PanClient(this);
        this.abortController = new AbortController();
    
        // Auto-cleanup with signal
        this.client.subscribe('data.*', this.handleData, {
          signal: this.abortController.signal
        });
      }
    
      disconnectedCallback() {
        // Unsubscribe all at once
        this.abortController.abort();
      }
    
      handleData = (msg) => {
        this.render(msg.data);
      }
    }

    #### 6.1.2 Circular References in Messages

    // ❌ PROBLEM: Circular reference
    const obj = { name: 'test' };
    obj.self = obj; // Circular!
    
    client.publish({
      topic: 'data.update',
      data: obj // Will fail validation
    });
    
    // ✅ SOLUTION: Only send serializable data
    client.publish({
      topic: 'data.update',
      data: { name: 'test' } // Plain object
    });

    #### 6.1.3 Large Retained Messages

    // ❌ PROBLEM: Retaining huge datasets
    client.publish({
      topic: 'users.list',
      data: { users: largeArrayOf10000Users },
      retain: true // Stored in memory!
    });
    
    // ✅ SOLUTION: Paginate or use pagination topic
    client.publish({
      topic: 'users.list.page.1',
      data: { users: first100Users, total: 10000 },
      retain: true
    });

    6.2 Performance Issues

    #### 6.2.1 Too Many Subscribers

    Problem: Performance degrades with many subscribers Solution:
    // ❌ PROBLEM: Each element subscribes individually
    class ListItem extends HTMLElement {
      connectedCallback() {
        // 1000 items = 1000 subscriptions!
        this.unsub = client.subscribe('item.update', this.handleUpdate);
      }
    }
    
    // ✅ SOLUTION: Subscribe once at parent level
    class ItemList extends HTMLElement {
      connectedCallback() {
        // One subscription for all items
        this.unsub = client.subscribe('item.update', (msg) => {
          const item = this.querySelector(`[data-id="${msg.data.id}"]`);
          if (item) item.update(msg.data);
        });
      }
    }

    #### 6.2.2 Message Rate Limiting

    Problem: Publishing too many messages causes performance issues Solution:
    // ❌ PROBLEM: Publish on every input event
    input.addEventListener('input', (e) => {
      client.publish({
        topic: 'search.query',
        data: { query: e.target.value }
      }); // Publishes hundreds of times per second!
    });
    
    // ✅ SOLUTION: Debounce
    let debounceTimer;
    input.addEventListener('input', (e) => {
      clearTimeout(debounceTimer);
      debounceTimer = setTimeout(() => {
        client.publish({
          topic: 'search.query',
          data: { query: e.target.value }
        });
      }, 300); // Only publish after 300ms of no input
    });

    #### 6.2.3 Heavy Message Processing

    Problem: Message handlers block UI Solution:
    // ❌ PROBLEM: Synchronous heavy processing
    client.subscribe('data.process', (msg) => {
      const result = heavyComputation(msg.data); // Blocks UI!
      updateUI(result);
    });
    
    // ✅ SOLUTION: Use Web Workers
    const worker = new Worker('/workers/process.js');
    
    client.subscribe('data.process', (msg) => {
      worker.postMessage(msg.data);
    });
    
    worker.onmessage = (e) => {
      updateUI(e.data);
    };

    6.3 Monitoring Memory Usage

    // Monitor memory usage
    function logMemoryUsage() {
      if (performance.memory) {
        const { usedJSHeapSize, totalJSHeapSize } = performance.memory;
        console.log('Memory:', {
          used: `${(usedJSHeapSize / 1024 / 1024).toFixed(2)} MB`,
          total: `${(totalJSHeapSize / 1024 / 1024).toFixed(2)} MB`,
          percentage: `${((usedJSHeapSize / totalJSHeapSize) * 100).toFixed(1)}%`
        });
      }
    }
    
    // Check periodically
    setInterval(logMemoryUsage, 10000);
    
    // Check PAN bus stats
    function checkBusStats() {
      const bus = document.querySelector('pan-bus');
      if (bus && bus.stats) {
        console.log('Bus stats:', bus.stats);
      }
    }

    7. CORS and CDN Issues

    7.1 CDN Resources Not Loading

    Problem: CDN modules fail to load with CORS or 404 errors Symptoms:
    Access to script at 'https://unpkg.com/...' from origin 'http://localhost' has been blocked by CORS policy
    Solutions:

    #### 7.1.1 Pin CDN Versions

    <!-- ❌ WRONG: Unpinned version can break -->
    <script type="module" src="https://unpkg.com/@larcjs/core/pan.mjs"></script>
    
    <!-- ✅ CORRECT: Pinned version -->
    <script type="module" src="https://unpkg.com/@larcjs/core@3.0.1/src/pan.mjs"></script>

    #### 7.1.2 CDN Failover

    // Implement automatic failover
    const CDN_SOURCES = [
      'https://unpkg.com/@larcjs/core@3.0.1/src/pan.mjs',
      'https://cdn.jsdelivr.net/npm/@larcjs/core@3.0.1/src/pan.mjs',
      '/static/larc/pan.mjs' // Local fallback
    ];
    
    async function loadWithFailover(sources) {
      for (const src of sources) {
        try {
          await import(src);
          console.log(`Loaded from: ${src}`);
          return;
        } catch (err) {
          console.warn(`Failed to load from ${src}:`, err);
        }
      }
      throw new Error('Failed to load from all sources');
    }
    
    await loadWithFailover(CDN_SOURCES);

    #### 7.1.3 Check CDN Status

    // Test CDN availability
    async function testCDN(url) {
      try {
        const response = await fetch(url, { method: 'HEAD' });
        return response.ok;
      } catch (err) {
        return false;
      }
    }
    
    const cdnAvailable = await testCDN('https://unpkg.com/@larcjs/core@3.0.1/src/pan.mjs');
    console.log('CDN available:', cdnAvailable);

    7.2 Mixed Content Errors

    Problem: HTTPS page loading HTTP resources Symptoms:
    Mixed Content: The page at 'https://example.com' was loaded over HTTPS, but requested an insecure script 'http://unpkg.com/...'
    Solution:
    <!-- ❌ WRONG: HTTP URL -->
    <script type="module" src="http://unpkg.com/@larcjs/core@3.0.1/src/pan.mjs"></script>
    
    <!-- ✅ CORRECT: HTTPS URL -->
    <script type="module" src="https://unpkg.com/@larcjs/core@3.0.1/src/pan.mjs"></script>
    
    <!-- ✅ BETTER: Protocol-relative (not recommended for modules) -->
    <script type="module" src="//unpkg.com/@larcjs/core@3.0.1/src/pan.mjs"></script>

    7.3 CDN Cache Issues

    Problem: Old version cached, new version not loading Solutions:
    // Clear service worker cache
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.getRegistrations().then(registrations => {
        registrations.forEach(reg => reg.unregister());
      });
    
      caches.keys().then(names => {
        names.forEach(name => caches.delete(name));
      });
    }
    
    // Force reload bypassing cache
    location.reload(true);
    
    // Or use cache-busting query param
    const timestamp = Date.now();
    const script = document.createElement('script');
    script.type = 'module';
    script.src = `./pan.mjs?v=${timestamp}`;
    document.head.appendChild(script);

    8. CSP Violations

    8.1 Scripts Blocked by CSP

    Problem: Console shows CSP violation errors Symptoms:
    Refused to load the script 'https://unpkg.com/...' because it violates the following Content Security Policy directive: "script-src 'self'"
    Solutions:

    #### 8.1.1 Update CSP Header

    <!-- Add CDN to allowed sources -->
    <meta http-equiv="Content-Security-Policy" content="
      default-src 'self';
      script-src 'self' https://unpkg.com https://cdn.jsdelivr.net;
      script-src-elem 'self' https://unpkg.com;
      connect-src 'self';
      style-src 'self' 'unsafe-inline';
    ">

    #### 8.1.2 Nginx CSP Configuration

    add_header Content-Security-Policy "
      default-src 'self';
      script-src 'self' https://unpkg.com https://cdn.jsdelivr.net;
      script-src-elem 'self' https://unpkg.com;
      connect-src 'self';
      style-src 'self' 'unsafe-inline';
      img-src 'self' data: https:;
      font-src 'self' data:;
      worker-src 'self' blob:;
    " always;

    #### 8.1.3 Test CSP Locally

    // Check what's being blocked
    window.addEventListener('securitypolicyviolation', (e) => {
      console.error('CSP Violation:', {
        directive: e.violatedDirective,
        blocked: e.blockedURI,
        document: e.documentURI
      });
    });

    8.2 Unsafe-inline Required

    Problem: Inline event handlers or styles blocked Solution:
    // ❌ AVOID: Inline event handlers
    <button onclick="handleClick()">Click</button>
    
    // ✅ USE: Proper event listeners
    <button id="myBtn">Click</button>
    <script type="module">
      document.getElementById('myBtn').addEventListener('click', handleClick);
    </script>

    8.3 Worker CSP Issues

    Problem: Web Workers blocked by CSP Solution:
    <meta http-equiv="Content-Security-Policy" content="
      worker-src 'self' blob:;
    ">

    9. Debugging Tools and Techniques

    9.1 Enable Debug Mode

    <!-- Enable debug logging -->
    <pan-bus debug="true"></pan-bus>
    // Or enable programmatically
    const bus = document.querySelector('pan-bus');
    if (bus) {
      bus.setAttribute('debug', 'true');
    }
    
    // Check debug output in console
    // [PAN Bus] Published {topic: "test", retain: false, delivered: 2}

    9.2 Browser DevTools

    #### 9.2.1 Check Component Registration

    // In DevTools Console:
    
    // List all defined custom elements
    customElements.getName(MyComponent); // Returns tag name
    
    // Check if element is defined
    customElements.get('my-component'); // Returns constructor or undefined
    
    // Get all custom elements in page
    document.querySelectorAll('*').forEach(el => {
      if (el.tagName.includes('-')) {
        console.log(el.tagName, customElements.get(el.localName) ? '✅' : '❌');
      }
    });

    #### 9.2.2 Monitor Network Requests

    // Enable verbose logging for module loads
    // Chrome DevTools: Network tab
    // Filter: .mjs
    // Look for:
    // - Status codes (404 = not found, 200 = OK)
    // - Timing (slow loading?)
    // - Size (large modules?)
    // - CORS headers

    #### 9.2.3 Inspect Event Listeners

    // Get event listeners on bus
    getEventListeners(document.querySelector('pan-bus'));
    
    // Check message deliveries
    monitorEvents(document, 'pan:deliver');
    // Now see all pan:deliver events in console

    9.3 Message Logging

    // Log all messages
    const client = new PanClient();
    
    client.subscribe('*', (msg) => {
      console.log(`[${msg.topic}]`, msg.data, {
        id: msg.id,
        ts: new Date(msg.ts).toISOString(),
        retain: msg.retain,
        correlationId: msg.correlationId
      });
    });

    9.4 Performance Profiling

    // Profile message throughput
    let messageCount = 0;
    let startTime = Date.now();
    
    client.subscribe('*', () => {
      messageCount++;
    });
    
    setInterval(() => {
      const elapsed = (Date.now() - startTime) / 1000;
      const rate = (messageCount / elapsed).toFixed(2);
      console.log(`Message rate: ${rate} msg/sec (${messageCount} total)`);
    }, 5000);

    9.5 Check Bus Statistics

    // Request bus stats
    function getBusStats() {
      return new Promise((resolve) => {
        const listener = (e) => {
          if (e.detail.topic === 'pan:sys.stats') {
            document.removeEventListener('pan:deliver', listener);
            resolve(e.detail.data);
          }
        };
    
        document.addEventListener('pan:deliver', listener);
        document.dispatchEvent(
          new CustomEvent('pan:sys.stats', { bubbles: true })
        );
      });
    }
    
    // Use it
    const stats = await getBusStats();
    console.log('Bus Stats:', stats);
    // {
    //   published: 1234,
    //   delivered: 5678,
    //   dropped: 0,
    //   subscriptions: 12,
    //   clients: 3,
    //   retained: 5
    // }

    9.6 Test Component Loading

    // Test component load
    async function testComponentLoad(tagName) {
      console.log(`Testing: ${tagName}`);
    
      const el = document.createElement(tagName);
      document.body.appendChild(el);
    
      try {
        await window.panAutoload.maybeLoadFor(el);
    
        if (customElements.get(tagName)) {
          console.log(`✅ ${tagName} loaded successfully`);
          return true;
        } else {
          console.error(`❌ ${tagName} failed to define`);
          return false;
        }
      } catch (err) {
        console.error(`❌ ${tagName} load error:`, err);
        return false;
      } finally {
        el.remove();
      }
    }
    
    // Test multiple components
    await testComponentLoad('my-component');
    await testComponentLoad('my-widget');

    10. Error Messages Reference

    10.1 Bus Error Codes

    | Code | Message | Cause | Solution | |------|---------|-------|----------| | RATE_LIMIT_EXCEEDED | Too many messages | Client exceeded rate limit | Reduce publish frequency or increase limit | | MESSAGE_INVALID | Message validation failed | Data not serializable or too large | Check message data, avoid circular refs | | SUBSCRIPTION_INVALID | Subscription rejected | Invalid pattern or global wildcard disabled | Fix pattern or enable global wildcards | | PAYLOAD_SIZE_EXCEEDED | Payload too large | Data exceeds maxPayloadSize | Reduce data size or increase limit |

    10.2 Component Loading Errors

    // "Failed to load module"
    // Cause: 404 on component file
    // Solution: Check file path, verify file exists
    
    // "Uncaught SyntaxError: Cannot use import statement outside a module"
    // Cause: Missing type="module"
    // Solution: Add type="module" to script tag
    
    // "Failed to execute 'define' on 'CustomElementRegistry'"
    // Cause: Element already defined or invalid name
    // Solution: Check for duplicate definitions, verify tag name has dash
    
    // "The provided value is not of type 'Function'"
    // Cause: Component didn't export a class
    // Solution: Export class as default
    
    // "Uncaught TypeError: Cannot read property 'prototype' of undefined"
    // Cause: Module didn't load correctly
    // Solution: Check network tab, verify import path

    10.3 Message Errors

    // "PAN request timeout"
    // Cause: No responder or responder too slow
    // Solution: Verify responder subscribed, increase timeout
    
    // "Data must be JSON-serializable"
    // Cause: Circular reference or function in data
    // Solution: Only send plain objects, arrays, primitives
    
    // "Message size exceeds limit"
    // Cause: Message too large (default 1MB)
    // Solution: Reduce data size or increase maxMessageSize
    
    // "Topic must be a non-empty string"
    // Cause: Missing or invalid topic
    // Solution: Provide valid topic string

    10.4 Browser-Specific Errors

    #### Safari

    // "ReferenceError: Can't find variable: customElements"
    // Cause: Safari < 10.1
    // Solution: Update Safari or load polyfill
    
    // "TypeError: IntersectionObserver is not a constructor"
    // Cause: Safari < 12.1
    // Solution: Load IntersectionObserver polyfill

    #### Firefox

    // "Import declarations may only appear at top level of a module"
    // Cause: Dynamic import() in wrong context
    // Solution: Use static imports or ensure module context

    11. Browser Compatibility Issues

    11.1 Check Browser Support

    import { Features } from './src/utils/features.mjs';
    
    // Check if browser is compatible
    if (!Features.hasCoreFeatuers()) {
      console.error('Browser not supported!');
    
      // Show upgrade message
      const report = Features.getReport();
      console.log('Missing features:', report.core);
      console.log('Recommendations:', report.recommendations);
    }
    
    // Check specific features
    if (!Features.has.intersectionObserver()) {
      console.warn('IntersectionObserver not supported, components will load immediately');
    }

    11.2 Safari-Specific Issues

    #### 11.2.1 Module Caching

    Problem: Safari aggressively caches modules Solution:
    // Add cache-busting to avoid stale modules
    const version = '1.0.2';
    const script = document.createElement('script');
    script.type = 'module';
    script.src = `./pan.mjs?v=${version}`;

    #### 11.2.2 Private File System

    Problem: Safari doesn't support OPFS Solution:
    // Check support and use fallback
    if (!Features.has.opfs()) {
      console.log('OPFS not available, using IndexedDB fallback');
      // Use alternative storage
    }

    11.3 Firefox Issues

    #### 11.3.1 Dynamic Imports

    Problem: Firefox strict about dynamic imports Solution:
    // Use static imports when possible
    import { PanClient } from './pan-client.mjs';
    
    // Or ensure dynamic imports are properly contextualized
    async function loadComponent(name) {
      const module = await import(`./components/${name}.mjs`);
      return module.default;
    }

    11.4 Older Browser Support

    Problem: Need to support older browsers Solution:
    <!-- Load polyfills for older browsers -->
    <script src="https://unpkg.com/@webcomponents/webcomponentsjs@2.8.0/webcomponents-loader.js"></script>
    <script src="https://unpkg.com/intersection-observer@0.12.2/intersection-observer.js"></script>
    
    <!-- Then load LARC -->
    <script type="module" src="./pan.mjs"></script>

    12. Integration Issues

    12.1 React Integration

    Problem: Components not rendering in React Solution:
    import { useEffect, useRef } from 'react';
    
    function MyReactComponent() {
      const ref = useRef();
    
      useEffect(() => {
        // Wait for custom element to be defined
        if (customElements.get('my-component')) {
          ref.current.setAttribute('data', JSON.stringify({ value: 'test' }));
        } else {
          customElements.whenDefined('my-component').then(() => {
            ref.current.setAttribute('data', JSON.stringify({ value: 'test' }));
          });
        }
      }, []);
    
      return <my-component ref={ref}></my-component>;
    }

    12.2 Vue Integration

    Problem: Vue tries to parse custom elements Solution:
    // vue.config.js or vite.config.js
    export default {
      compilerOptions: {
        isCustomElement: tag => tag.includes('-')
      }
    }
    
    // Or in Vue 3 app
    app.config.compilerOptions.isCustomElement = tag => tag.includes('-');

    12.3 Shadow DOM Conflicts

    Problem: Styles don't apply to custom elements Solution:
    // Custom element with open shadow DOM
    class MyComponent extends HTMLElement {
      constructor() {
        super();
        this.attachShadow({ mode: 'open' });
      }
    
      connectedCallback() {
        // Add styles to shadow root
        this.shadowRoot.innerHTML = `
          <style>
            :host {
              display: block;
            }
            /* Component styles */
          </style>
          <div>Content</div>
        `;
      }
    }

    13. Development vs Production Issues

    13.1 Works in Dev, Not in Production

    #### 13.1.1 CDN Version Mismatch

    // Development
    <script type="module" src="./pan.mjs"></script>
    
    // Production - ensure version matches!
    <script type="module" src="https://unpkg.com/@larcjs/core@3.0.1/src/pan.mjs"></script>

    #### 13.1.2 Path Resolution

    // Dev: Relative paths work
    import { PanClient } from './components/pan-client.mjs';
    
    // Prod: May need absolute paths or import map
    import { PanClient } from '/static/larc/components/pan-client.mjs';

    #### 13.1.3 Caching Issues

    // Clear production cache
    // Add cache-busting headers
    // Nginx:
    add_header Cache-Control "public, max-age=0, must-revalidate";
    
    // Or use versioned URLs
    <script type="module" src="/static/pan.mjs?v=1.0.2"></script>

    13.2 Minification Breaking Code

    Problem: Minified code doesn't work Solution:
    // Ensure minifier preserves ES modules
    // Using esbuild:
    esbuild.build({
      entryPoints: ['src/pan.mjs'],
      outfile: 'dist/pan.min.mjs',
      bundle: false,
      minify: true,
      format: 'esm',  // Keep as ES module
      target: 'es2020'
    });

    13.3 Source Maps Missing

    Problem: Can't debug production issues Solution:
    // Generate source maps
    esbuild.build({
      entryPoints: ['src/pan.mjs'],
      outfile: 'dist/pan.min.mjs',
      minify: true,
      sourcemap: true,
      sourcesContent: true
    });
    
    // Deploy source maps
    // Nginx: Serve .map files with correct headers
    location ~ \.map$ {
      add_header Content-Type application/json;
    }

    14. Diagnostic Workflows

    14.1 Component Not Appearing

    1. Is component in DOM?
       ├─ No → Check HTML, verify element added
       └─ Yes → Continue
    
    2. Is component :defined?
       ├─ No → Continue to step 3
       └─ Yes → Check component's connectedCallback, styles
    
    3. Check console for errors
       ├─ 404 error → Fix file path (step 4)
       ├─ CORS error → Fix CDN/headers (section 7)
       ├─ CSP error → Update CSP (section 8)
       └─ No errors → Continue to step 4
    
    4. Check component file path
       ├─ Has data-module? → Verify path exists
       └─ No data-module → Check autoloader config
    
    5. Check autoloader configuration
       └─ console.log(window.panAutoload.config)
    
    6. Manually load component
       └─ await window.panAutoload.maybeLoadFor(element)
    
    7. Check Network tab
       └─ Look for .mjs requests, check status codes

    14.2 Messages Not Flowing

    1. Is bus ready?
       ├─ No → Wait for pan:sys.ready event
       └─ Yes → Continue
    
    2. Check publisher
       ├─ await client.ready() called? → Yes/Continue
       └─ No → Add await client.ready()
    
    3. Check subscriber
       ├─ Subscription before publish? → Yes/Continue
       ├─ Pattern matches topic? → Test with PanClient.matches()
       └─ Element still in DOM? → Check isConnected
    
    4. Enable debug mode
       └─ <pan-bus debug="true"></pan-bus>
    
    5. Log all messages
       └─ client.subscribe('*', msg => console.log(msg))
    
    6. Check bus stats
       └─ await getBusStats()
    
    7. Verify no errors in console

    14.3 Performance Degradation

    1. Check memory usage
       └─ console.log(performance.memory)
    
    2. Check subscription count
       └─ await getBusStats() → Check subscriptions count
    
    3. Profile message rate
       └─ Monitor msg/sec (section 9.4)
    
    4. Check for subscription leaks
       └─ Are components cleaning up? (section 6.1.1)
    
    5. Check message size
       └─ Log message size, check for large payloads
    
    6. Check handler performance
       └─ Profile handlers with Performance tab
    
    7. Consider rate limiting
       └─ Debounce frequent publishes (section 6.2.2)

    14.4 Minimal Reproduction

    To report a bug, create minimal reproduction:

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <title>LARC Issue Reproduction</title>
    </head>
    <body>
      <pan-bus debug="true"></pan-bus>
    
      <script type="module">
        import { PanClient } from 'https://unpkg.com/@larcjs/core@3.0.1/src/pan.mjs';
    
        const client = new PanClient();
        await client.ready();
    
        // Minimal code to reproduce issue
        client.subscribe('test', msg => {
          console.log('Received:', msg);
        });
    
        client.publish({
          topic: 'test',
          data: { value: 123 }
        });
    
        // Expected: See message in console
        // Actual: [describe what happens]
      </script>
    </body>
    </html>

    15. Getting Help

    15.1 Before Asking for Help

    15.2 Information to Include

    When reporting an issue, include:

  • LARC Version
  • // Check version
       // From CDN URL or package.json
  • Browser & Version
  • // Copy from DevTools
       console.log(navigator.userAgent);
    
       // Or use feature detection
       const report = Features.getReport();
       console.log(report.browser);
  • Error Messages
  • Copy exact error from console, including stack trace
  • Reproduction Steps
  • 1. Create component with...
       2. Subscribe to topic...
       3. Publish message...
       4. Error occurs
  • Expected vs Actual Behavior
  • Expected: Message delivered to subscriber
       Actual: Subscriber never receives message
  • Configuration
  • // Copy your config
       console.log(window.panAutoload.config);

    15.3 Resources

    15.4 Community Guidelines

    • Search before posting
    • Be specific and provide details
    • Include minimal reproduction
    • Be respectful and patient
    • Help others when you can

    Appendix: Quick Debugging Snippets

    A1. Test Everything

    // Comprehensive test script
    // Paste in browser console
    
    console.log('=== LARC Debug Report ===');
    
    // 1. Check bus
    const bus = document.querySelector('pan-bus');
    console.log('Bus exists:', !!bus);
    console.log('Bus ready:', window.__panReady);
    
    // 2. Check autoloader
    console.log('Autoloader:', !!window.panAutoload);
    if (window.panAutoload) {
      console.log('Config:', window.panAutoload.config);
    }
    
    // 3. Check features
    if (window.Features) {
      const report = window.Features.getReport();
      console.log('Browser:', report.browser);
      console.log('Compatible:', report.compatible);
      console.log('Recommendations:', report.recommendations);
    }
    
    // 4. List custom elements
    const customElements = [];
    document.querySelectorAll('*').forEach(el => {
      if (el.tagName.includes('-')) {
        customElements.push({
          tag: el.tagName,
          defined: !!window.customElements.get(el.localName),
          connected: el.isConnected
        });
      }
    });
    console.log('Custom elements:', customElements);
    
    // 5. Test message flow
    const testClient = new PanClient();
    await testClient.ready();
    
    let received = false;
    testClient.subscribe('debug.test', () => {
      received = true;
      console.log('✅ Message flow working!');
    });
    
    testClient.publish({ topic: 'debug.test', data: {} });
    
    setTimeout(() => {
      if (!received) {
        console.error('❌ Message flow broken!');
      }
    }, 100);
    
    console.log('=== End Debug Report ===');

    A2. Monitor All Activity

    // Log everything LARC does
    const client = new PanClient();
    await client.ready();
    
    // Log all messages
    client.subscribe('*', (msg) => {
      console.log(`📨 [${msg.topic}]`, msg);
    });
    
    // Monitor bus events
    ['pan:publish', 'pan:subscribe', 'pan:unsubscribe', 'pan:deliver'].forEach(type => {
      document.addEventListener(type, (e) => {
        console.log(`🚌 ${type}:`, e.detail);
      }, true);
    });
    
    // Monitor custom element definitions
    const originalDefine = customElements.define;
    customElements.define = function(name, constructor, options) {
      console.log(`📦 Defined: ${name}`);
      return originalDefine.call(this, name, constructor, options);
    };
    
    console.log('Monitoring enabled');

    A3. Performance Monitor

    // Track performance metrics
    const metrics = {
      messages: 0,
      requests: 0,
      errors: 0,
      startTime: Date.now()
    };
    
    client.subscribe('*', (msg) => {
      metrics.messages++;
      if (msg.replyTo) metrics.requests++;
    });
    
    window.addEventListener('error', () => {
      metrics.errors++;
    });
    
    setInterval(() => {
      const elapsed = (Date.now() - metrics.startTime) / 1000;
      console.log('Performance:', {
        uptime: `${elapsed.toFixed(0)}s`,
        messageRate: `${(metrics.messages / elapsed).toFixed(2)}/s`,
        totalMessages: metrics.messages,
        requests: metrics.requests,
        errors: metrics.errors
      });
    }, 10000);

    Last Updated: November 2024 Version: 1.0

    For the latest documentation, visit: https://larcjs.com/