Skip to content

API Reference

Christopher Robison edited this page Dec 12, 2025 · 1 revision

LARC API Reference

Comprehensive API documentation for LARC (Lightweight Autonomous Reactive Components)

Table of Contents


Getting Started

Installation

LARC can be used in two ways:

1. Local Development (Zero Build)

<!DOCTYPE html>
<html>
<head>
  <title>My LARC App</title>
</head>
<body>
  <!-- Load autoloader -->
  <script type="module" src="/core/pan.mjs"></script>

  <!-- Use components - they load automatically -->
  <my-widget></my-widget>
  <pan-card>Hello World</pan-card>
</body>
</html>

2. CDN Usage

<!DOCTYPE html>
<html>
<head>
  <title>My LARC App</title>
</head>
<body>
  <!-- Configure for CDN -->
  <script type="module">
    window.panAutoload = {
      baseUrl: 'https://unpkg.com/@larcjs/core@latest/',
      extension: '.js'
    };
  </script>

  <!-- Load autoloader from CDN -->
  <script type="module" src="https://unpkg.com/@larcjs/core@latest/src/pan.mjs"></script>

  <!-- Components load from CDN -->
  <my-widget></my-widget>
</body>
</html>

Quick Example

<!DOCTYPE html>
<html>
<head>
  <title>Counter Demo</title>
</head>
<body>
  <script type="module" src="/core/pan.mjs"></script>

  <!-- Create a simple counter component -->
  <script type="module">
    import { PanClient } from '/core/pan-client.mjs';

    class CounterElement extends HTMLElement {
      constructor() {
        super();
        this.count = 0;
        this.client = new PanClient(this);
      }

      async connectedCallback() {
        await this.client.ready();

        // Subscribe to counter updates
        this.client.subscribe('counter.value', (msg) => {
          this.count = msg.data;
          this.render();
        }, { retained: true });

        this.render();

        // Publish initial value
        this.client.publish({
          topic: 'counter.value',
          data: this.count,
          retain: true
        });
      }

      increment() {
        this.count++;
        this.client.publish({
          topic: 'counter.value',
          data: this.count,
          retain: true
        });
      }

      render() {
        this.innerHTML = `
          <div>
            <h2>Count: ${this.count}</h2>
            <button onclick="this.parentElement.parentElement.increment()">
              Increment
            </button>
          </div>
        `;
      }
    }

    customElements.define('x-counter', CounterElement);
  </script>

  <x-counter></x-counter>
</body>
</html>

Core Package (@larcjs/core)

The core package provides three main APIs:

  1. PAN Autoloader - Automatic component loading
  2. PAN Bus - Message bus for pub/sub communication
  3. PAN Client - Simplified API for components

PAN Autoloader

The autoloader automatically discovers and loads Web Components as they appear in the DOM, eliminating manual imports and customElements.define() calls.

Overview

  • Progressive loading with IntersectionObserver
  • Automatic component discovery via MutationObserver
  • Configurable paths and file extensions
  • Support for custom component resolvers
  • Zero-build development workflow

Configuration

AutoloadConfig Interface

interface AutoloadConfig {
  baseUrl?: string | null;        // Full CDN URL (e.g., 'https://unpkg.com/pan@latest/')
  componentsPath?: string;        // Relative path from baseUrl (default: './')
  extension?: string;             // File extension (default: '.mjs')
  rootMargin?: number;            // IntersectionObserver margin in px (default: 600)
  resolvedComponentsPath?: string; // Computed full path (readonly)
}

Configuration Examples

Local Development

// Default configuration works out of the box
// Components loaded from ./components/ relative to pan.mjs

CDN Usage

<script type="module">
  window.panAutoload = {
    baseUrl: 'https://unpkg.com/@larcjs/core@2.0.0/',
    componentsPath: 'src/components/',
    extension: '.js'
  };
</script>
<script type="module" src="https://unpkg.com/@larcjs/core@2.0.0/src/pan.mjs"></script>

Custom Component Resolver

window.panAutoload = {
  resolveComponent(tagName) {
    // Custom logic to resolve component paths
    if (tagName.startsWith('my-')) {
      return `/custom/${tagName}.mjs`;
    }
    return null; // Use default resolution
  }
};

API Methods

maybeLoadFor(el: HTMLElement): Promise<void>

Manually loads a component module for a specific element.

import { maybeLoadFor } from '/core/pan.mjs';

const widget = document.createElement('my-widget');
document.body.appendChild(widget);
await maybeLoadFor(widget);

observeTree(root?: Document | Element): void

Observes a DOM tree for undefined custom elements and sets up progressive loading.

import { observeTree } from '/core/pan.mjs';

// Observe entire document (default)
observeTree();

// Observe specific subtree
const container = document.querySelector('#dynamic-content');
observeTree(container);

PAN Bus

The central message bus for publish/subscribe communication between components.

Note: As of v1.1.1, the PAN bus is automatically instantiated when you load pan.mjs. You no longer need to include a <pan-bus> element in your HTML.

Configuration Attributes

Attribute Type Default Description
max-retained number 1000 Maximum retained messages
max-message-size number 1048576 Max total message size (1MB)
max-payload-size number 524288 Max data payload size (512KB)
cleanup-interval number 30000 Cleanup interval in ms (30s)
rate-limit number 1000 Max messages per client per second
allow-global-wildcard boolean true Allow '*' subscriptions
debug boolean false Enable debug logging

Message Format

interface PanMessage<T = any> {
  topic: string;              // Topic name (required)
  data: T;                    // Message payload (required)
  id?: string;                // Unique message ID (auto-generated)
  ts?: number;                // Timestamp in ms (auto-generated)
  retain?: boolean;           // Retain for late subscribers
  replyTo?: string;           // Topic for replies
  correlationId?: string;     // Correlation ID for request/reply
  headers?: Record<string, string>; // Optional metadata
}

Topic Patterns

Exact Match

subscribe(['users.updated'], handler);

Wildcard Match

// Matches users.created, users.updated, users.deleted
subscribe(['users.*'], handler);

// Matches all messages
subscribe(['*'], handler); // Only if allow-global-wildcard=true

Key Events

Event Direction Purpose
pan:publish Component → Bus Publish a message
pan:subscribe Component → Bus Subscribe to topics
pan:unsubscribe Component → Bus Unsubscribe from topics
pan:deliver Bus → Component Deliver message to subscriber
pan:request Component → Bus Send request (expects reply)
pan:reply Component → Bus Send reply to request
pan:sys.ready Bus → Document Bus is ready
pan:sys.error Bus → Document Error occurred

PAN Client

A simplified, promise-based API for interacting with the PAN bus.

Constructor

new PanClient(host?: HTMLElement | Document, busSelector?: string)

Methods

ready(): Promise<void>

const client = new PanClient();
await client.ready();
// Bus is ready, safe to publish/subscribe

publish(message): void

client.publish({
  topic: 'user.updated',
  data: { id: 123, name: 'Alice' },
  retain: true  // Optional: retain for late subscribers
});

subscribe(topics, handler, options): UnsubscribeFunction

const unsub = client.subscribe('users.*', (msg) => {
  console.log('Received:', msg.topic, msg.data);
}, { retained: true });

// Later: unsub();

request(topic, data, options): Promise<PanMessage>

const response = await client.request('users.get', { id: 123 }, {
  timeoutMs: 5000
});
console.log('User:', response.data);

Complete Example

import { PanClient } from '/core/pan-client.mjs';

class UserListComponent extends HTMLElement {
  constructor() {
    super();
    this.client = new PanClient(this);
    this.users = [];
  }

  async connectedCallback() {
    await this.client.ready();

    this.unsubscribe = this.client.subscribe(
      ['users.*'],
      (msg) => this.handleUserEvent(msg),
      { retained: true }
    );

    this.render();
  }

  disconnectedCallback() {
    this.unsubscribe?.();
  }

  handleUserEvent(msg) {
    // Handle user events...
  }
}

customElements.define('user-list-component', UserListComponent);

TypeScript Support

LARC includes comprehensive TypeScript definitions.

Importing Types

import {
  PanClient,
  PanMessage,
  SubscribeOptions,
  RequestOptions
} from '/core/pan-client.mjs';

Generic Type Parameters

interface User {
  id: number;
  name: string;
}

// Typed publish
client.publish<User>({
  topic: 'users.created',
  data: { id: 123, name: 'Alice' }
});

// Typed subscribe
client.subscribe<User>('users.*', (msg) => {
  console.log(msg.data.name); // Type safe
});

Best Practices

  1. Always wait for bus ready before publishing/subscribing
  2. Clean up subscriptions in disconnectedCallback
  3. Use retained messages for state
  4. Namespace your topics (e.g., app.users.created)
  5. Use request/reply for RPC-style operations
  6. Validate message data in handlers
  7. Handle request timeouts gracefully
  8. Use debug mode during development

Common Pitfalls

  1. Forgetting to wait for bus ready - Messages may fail
  2. Memory leaks from uncleared subscriptions
  3. Publishing non-serializable data - DOM nodes, functions fail
  4. Exceeding message size limits - Chunk large data
  5. Rate limiting issues - Batch or throttle messages
  6. Circular message loops - Don't publish to subscribed topics
  7. Incorrect topic patterns - Test pattern matching

Additional Resources

Clone this wiki locally