# LiveComponents API Reference

**Complete API Documentation for LiveComponents System**

This reference covers all public classes, methods, attributes, and interfaces for building LiveComponents applications.

---

## Table of Contents

1. [LiveComponent Base Class](#livecomponent-base-class)
2. [Attributes](#attributes)
3. [HTTP Integration](#http-integration)
4. [JavaScript API](#javascript-api)
5. [Value Objects](#value-objects)
6. [Services](#services)
7. [Events](#events)

---

## LiveComponent Base Class

### `abstract class LiveComponent`

Base class for all LiveComponents. Provides lifecycle hooks, rendering, and state management.

#### Properties

```php
/**
 * Unique component instance ID
 * Auto-generated on component creation
 */
protected readonly string $id;

/**
 * Component name (class name without namespace)
 */
protected readonly string $name;
```

#### Lifecycle Methods

##### `public function mount(array $initialData = []): void`

Called when component is first created.

**Parameters**:
- `$initialData` - Initial data passed to component

**Usage**:
```php
public function mount(array $initialData = []): void
{
    $this->userId = $initialData['user_id'] ?? null;
    $this->loadUserData();
    $this->enableSse(); // Enable real-time updates
}
```

---

##### `public function hydrate(array $state): void`

Called on subsequent requests to restore component state.

**Parameters**:
- `$state` - Serialized component state from client

**Usage**:
```php
public function hydrate(array $state): void
{
    // State automatically restored to #[LiveProp] properties
    // Override for custom hydration logic
    parent::hydrate($state);
    $this->recalculateDerivedState();
}
```

---

##### `public function updated(string $property, mixed $oldValue, mixed $newValue): void`

Called when a property is updated via two-way binding.

**Parameters**:
- `$property` - Property name that changed
- `$oldValue` - Previous value
- `$newValue` - New value

**Usage**:
```php
public function updated(string $property, mixed $oldValue, mixed $newValue): void
{
    if ($property === 'searchTerm' && strlen($newValue) >= 3) {
        $this->performSearch();
    }
}
```

---

##### `public function unmount(): void`

Called when component is destroyed.

**Usage**:
```php
public function unmount(): void
{
    // Clean up resources
    $this->closeConnections();
    $this->clearCache();
}
```

---

#### Rendering

##### `abstract public function render(): string`

Render component to HTML.

**Returns**: HTML string

**Usage**:
```php
public function render(): string
{
    return $this->view('components/user-profile', [
        'user' => $this->user,
        'posts' => $this->posts
    ]);
}
```

---

##### `protected function view(string $template, array $data = []): string`

Render a template with data.

**Parameters**:
- `$template` - Template path (relative to views directory)
- `$data` - Data to pass to template

**Returns**: Rendered HTML

**Usage**:
```php
protected function render(): string
{
    return $this->view('components/product-list', [
        'products' => $this->products,
        'totalCount' => $this->totalCount
    ]);
}
```

---

#### State Management

##### `protected function getState(): array`

Get component state for serialization.

**Returns**: Associative array of state

**Usage**:
```php
protected function getState(): array
{
    return [
        'userId' => $this->userId,
        'filters' => $this->filters,
        'page' => $this->page
    ];
}
```

---

##### `protected function setState(array $state): void`

Restore component state.

**Parameters**:
- `$state` - State array to restore

---

#### Real-Time Updates

##### `protected function enableSse(array $channels = []): void`

Enable Server-Sent Events for real-time updates.

**Parameters**:
- `$channels` - Channels to subscribe to (default: component-specific channel)

**Usage**:
```php
public function mount(): void
{
    $this->enableSse([
        'user.updates',
        "team.{$this->teamId}.activity"
    ]);
}
```

---

##### `protected function broadcast(string $channel, array $data): void`

Broadcast update to all clients listening on channel.

**Parameters**:
- `$channel` - Channel name
- `$data` - Data to broadcast

**Usage**:
```php
#[LiveAction]
public function updateStatus(string $status): void
{
    $this->status = $status;

    // Broadcast to all team members
    $this->broadcast("team.{$this->teamId}.updates", [
        'type' => 'status_changed',
        'user' => $this->user->name,
        'status' => $status
    ]);
}
```

---

#### Static Factory

##### `public static function mount(string $componentClass, array $initialData = []): string`

Create and render component.

**Parameters**:
- `$componentClass` - Fully qualified class name
- `$initialData` - Initial data for component

**Returns**: Rendered component HTML

**Usage**:
```php
// In controller
public function dashboard(): ViewResult
{
    return new ViewResult('dashboard', [
        'statsWidget' => LiveComponent::mount(StatsWidget::class, [
            'user_id' => $currentUser->id
        ])
    ]);
}
```

---

## Attributes

### `#[LiveProp]`

Marks a property for automatic state synchronization.

**Usage**:
```php
use App\Framework\LiveComponents\Attributes\LiveProp;

final class SearchComponent extends LiveComponent
{
    #[LiveProp]
    public string $searchTerm = '';

    #[LiveProp]
    public array $filters = [];

    #[LiveProp]
    public int $page = 1;
}
```

**Options**:
- Properties are automatically serialized/deserialized
- Two-way binding with `data-lc-model`
- State preserved across requests

---

### `#[LiveAction]`

Marks a method as a LiveComponent action.

**Usage**:
```php
use App\Framework\LiveComponents\Attributes\LiveAction;

#[LiveAction]
public function search(): void
{
    $this->results = $this->searchService->search($this->searchTerm);
}

#[LiveAction]
public function addToCart(string $productId): void
{
    $this->cart->add($productId);
}
```

**Callable From Client**:
```html
<button data-lc-action="search">Search</button>
<button
    data-lc-action="addToCart"
    data-lc-params='{"productId": "123"}'
>
    Add to Cart
</button>
```

---

### `#[Fragment(string|array $names)]`

Marks action to only update specific fragments.

**Usage**:
```php
use App\Framework\LiveComponents\Attributes\Fragment;

#[LiveAction]
#[Fragment('search-results')]
public function search(): void
{
    $this->results = $this->searchService->search($this->searchTerm);
    // Only search-results fragment re-renders
}

#[LiveAction]
#[Fragment(['user-stats', 'activity-feed'])]
public function refreshDashboard(): void
{
    $this->updateStats();
    $this->loadActivity();
    // Both fragments re-render
}
```

---

### `#[RateLimit(int $requests, int $window)]`

Apply rate limiting to component or action.

**Usage**:
```php
use App\Framework\LiveComponents\Attributes\RateLimit;

#[RateLimit(requests: 10, window: 60)]
final class SearchComponent extends LiveComponent
{
    #[LiveAction]
    #[RateLimit(requests: 5, window: 60)]
    public function expensiveSearch(): void
    {
        // Limited to 5 requests per minute
    }
}
```

---

### `#[Authorize(array $roles = [], array $permissions = [])]`

Require authorization for action.

**Usage**:
```php
use App\Framework\LiveComponents\Attributes\Authorize;

#[LiveAction]
#[Authorize(roles: ['admin'])]
public function deleteUser(string $userId): void
{
    $this->userService->delete($userId);
}

#[LiveAction]
#[Authorize(permissions: ['users.edit'])]
public function updateUserRole(string $userId, string $role): void
{
    $this->userService->updateRole($userId, $role);
}
```

---

### `#[Idempotent]`

Ensure action executes exactly once (for critical operations).

**Usage**:
```php
use App\Framework\LiveComponents\Attributes\Idempotent;

#[LiveAction]
#[Idempotent]
public function processPayment(): void
{
    $this->paymentGateway->charge($this->amount);
    $this->orderService->createOrder($this->cartItems);
    // Guaranteed to execute only once even if request duplicated
}
```

---

### `#[Encrypted]`

Encrypt property value in client state.

**Usage**:
```php
use App\Framework\LiveComponents\Attributes\Encrypted;

final class PaymentForm extends LiveComponent
{
    #[LiveProp]
    #[Encrypted]
    public string $creditCardNumber = '';

    #[LiveProp]
    #[Encrypted]
    public string $cvv = '';

    #[LiveProp] // Not encrypted - safe to expose
    public string $cardholderName = '';
}
```

---

### `#[Optimistic(string $property, string $operation)]`

Enable optimistic UI updates for action.

**Usage**:
```php
use App\Framework\LiveComponents\Attributes\Optimistic;

#[LiveAction]
#[Optimistic(property: 'isLiked', operation: 'toggle')]
#[Optimistic(property: 'likeCount', operation: 'increment')]
public function toggleLike(): void
{
    $this->isLiked = !$this->isLiked;
    $this->likeCount += $this->isLiked ? 1 : -1;
}
```

**Operations**:
- `toggle` - Boolean toggle
- `increment` - Increment number
- `decrement` - Decrement number
- `set` - Set to specific value

---

## HTTP Integration

### LiveComponent HTTP Endpoint

**POST** `/livecomponent/{componentId}/{action}`

Execute a LiveComponent action.

**Request Headers**:
```http
Content-Type: application/json
X-CSRF-Token: {token}
X-Component-Checksum: {checksum}
```

**Request Body**:
```json
{
    "state": {
        "searchTerm": "laptop",
        "filters": ["electronics"],
        "page": 1
    },
    "params": {
        "productId": "123"
    }
}
```

**Response**:
```json
{
    "success": true,
    "html": "<div data-component-id=\"abc123\">...</div>",
    "fragments": {
        "search-results": "<div data-lc-fragment=\"search-results\">...</div>"
    },
    "redirect": null,
    "events": []
}
```

---

### Batch Endpoint

**POST** `/livecomponent/{componentId}/batch`

Execute multiple actions in single request.

**Request Body**:
```json
{
    "batch": [
        {
            "action": "incrementCounter",
            "params": {}
        },
        {
            "action": "updateName",
            "params": {"name": "John"}
        },
        {
            "action": "save",
            "params": {}
        }
    ],
    "state": {
        "count": 0,
        "name": ""
    }
}
```

**Response**:
```json
{
    "success": true,
    "results": [
        { "success": true, "html": "..." },
        { "success": true, "html": "..." },
        { "success": true, "html": "..." }
    ]
}
```

---

### Upload Endpoint

**POST** `/livecomponent/{componentId}/upload`

Upload file chunks.

**Request Headers**:
```http
Content-Type: multipart/form-data
X-Upload-ID: {unique-upload-id}
X-Chunk-Index: {chunk-number}
X-Total-Chunks: {total-chunks}
```

**Response**:
```json
{
    "success": true,
    "chunk_index": 0,
    "received_bytes": 1048576,
    "complete": false
}
```

---

### SSE Endpoint

**GET** `/livecomponent/sse/{componentId}`

Subscribe to Server-Sent Events.

**Response** (text/event-stream):
```
event: component-update
data: {"type":"fragment","fragment":"user-stats","html":"<div>...</div>"}

event: component-update
data: {"type":"full","html":"<div data-component-id=\"abc123\">...</div>"}

event: heartbeat
data: {"timestamp":1634567890}
```

---

## JavaScript API

### `LiveComponent` Global Object

Main JavaScript interface for LiveComponents.

#### Methods

##### `LiveComponent.mount(element: HTMLElement): void`

Initialize component on element.

**Usage**:
```javascript
const componentEl = document.querySelector('[data-component-id="abc123"]');
LiveComponent.mount(componentEl);
```

---

##### `LiveComponent.unmount(componentId: string): void`

Destroy component and clean up resources.

**Usage**:
```javascript
LiveComponent.unmount('abc123');
```

---

##### `LiveComponent.executeAction(componentId: string, action: string, params: object): Promise<void>`

Manually execute component action.

**Usage**:
```javascript
await LiveComponent.executeAction('abc123', 'search', {
    query: 'laptops'
});
```

---

##### `LiveComponent.getComponent(componentId: string): Component | null`

Get component instance.

**Returns**: Component object or null

**Usage**:
```javascript
const component = LiveComponent.getComponent('abc123');

console.log(component.state);
console.log(component.name);
```

---

##### `LiveComponent.getState(componentId: string): object | null`

Get component state.

**Returns**: State object or null

**Usage**:
```javascript
const state = LiveComponent.getState('abc123');

console.log(state.searchTerm);
console.log(state.filters);
```

---

##### `LiveComponent.setState(componentId: string, state: object): void`

Update component state (triggers server sync).

**Usage**:
```javascript
LiveComponent.setState('abc123', {
    searchTerm: 'new query',
    page: 2
});
```

---

##### `LiveComponent.refresh(componentId: string): Promise<void>`

Force component refresh from server.

**Usage**:
```javascript
await LiveComponent.refresh('abc123');
```

---

##### `LiveComponent.configure(options: object): void`

Configure global LiveComponent settings.

**Options**:
- `batchSize` - Max actions per batch (default: 10)
- `batchDebounce` - Debounce delay in ms (default: 50)
- `optimisticUI` - Enable optimistic updates (default: true)
- `csrfProtection` - Enable CSRF protection (default: true)
- `enableSSE` - Enable Server-Sent Events (default: true)

**Usage**:
```javascript
LiveComponent.configure({
    batchSize: 15,
    batchDebounce: 100,
    optimisticUI: true
});
```

---

#### Properties

##### `LiveComponent.components: Map<string, Component>`

All active components.

**Usage**:
```javascript
console.log(`Active components: ${LiveComponent.components.size}`);

LiveComponent.components.forEach((component, id) => {
    console.log(`${id}: ${component.name}`);
});
```

---

### Component Object

Individual component instance (returned by `getComponent()`).

#### Properties

```typescript
interface Component {
    id: string;              // Unique component ID
    name: string;            // Component class name
    state: object;           // Current state
    element: HTMLElement;    // DOM element
    isConnected: boolean;    // SSE connection status
    isPending: boolean;      // Has pending actions
}
```

---

### Data Attributes

#### `data-component-id`

Identifies component root element. **Required** on component container.

```html
<div data-component-id="{component_id}" data-component-name="SearchComponent">
    <!-- Component content -->
</div>
```

---

#### `data-lc-model`

Two-way data binding for inputs.

```html
<input
    type="text"
    data-lc-model="searchTerm"
    value="{searchTerm}"
/>

<select data-lc-model="category">
    <option value="electronics">Electronics</option>
    <option value="books">Books</option>
</select>

<input
    type="checkbox"
    data-lc-model="agreed"
    {agreed ? 'checked' : ''}
/>
```

**Modifiers**:
- `data-lc-model.debounce.500="searchTerm"` - Debounce 500ms
- `data-lc-model.lazy="bio"` - Update on blur instead of input

---

#### `data-lc-action`

Trigger action on click.

```html
<button data-lc-action="search">Search</button>

<button
    data-lc-action="addToCart"
    data-lc-params='{"productId": "123"}'
>
    Add to Cart
</button>
```

---

#### `data-lc-fragment`

Mark fragment for partial updates.

```html
<div data-lc-fragment="search-results">
    <!-- Only this section updates -->
    <for items="results" as="result">
        <div>{result.title}</div>
    </for>
</div>
```

---

#### `data-lc-submit`

Handle form submission.

```html
<form data-lc-submit="handleSubmit">
    <input type="text" name="email" />
    <button type="submit">Submit</button>
</form>
```

---

#### `data-optimistic`

Enable optimistic update for action.

```html
<button
    data-lc-action="toggleLike"
    data-optimistic="true"
>
    {isLiked ? '❤️' : '🤍'} Like
</button>
```

---

#### `data-lc-upload`

Enable chunked file upload.

```html
<input
    type="file"
    data-lc-upload="handleFileUpload"
    data-chunk-size="1048576"
    data-max-file-size="10485760"
/>

<div data-upload-progress>
    <div class="progress-bar" style="width: {uploadProgress}%"></div>
    <span>{uploadProgress}%</span>
</div>
```

---

## Value Objects

### `ComponentId`

Unique component identifier.

```php
final readonly class ComponentId
{
    public function __construct(public string $value) {}

    public static function generate(): self
    {
        return new self(bin2hex(random_bytes(16)));
    }

    public function toString(): string
    {
        return $this->value;
    }
}
```

---

### `ComponentState`

Component state snapshot.

```php
final readonly class ComponentState
{
    public function __construct(
        public array $properties,
        public string $checksum
    ) {}

    public function toArray(): array
    {
        return $this->properties;
    }

    public function verify(string $checksum): bool
    {
        return hash_equals($this->checksum, $checksum);
    }
}
```

---

### `FragmentName`

Fragment identifier.

```php
final readonly class FragmentName
{
    public function __construct(public string $value) {}

    public static function fromString(string $name): self
    {
        return new self($name);
    }
}
```

---

## Services

### `LiveComponentManager`

Core service for component lifecycle management.

```php
final readonly class LiveComponentManager
{
    public function create(
        string $componentClass,
        array $initialData = []
    ): LiveComponent;

    public function hydrate(
        string $componentClass,
        ComponentId $id,
        ComponentState $state
    ): LiveComponent;

    public function executeAction(
        LiveComponent $component,
        string $actionName,
        array $params = []
    ): ActionResult;

    public function render(LiveComponent $component): string;

    public function renderFragment(
        LiveComponent $component,
        FragmentName $fragment
    ): string;
}
```

---

### `LiveComponentState`

State management service.

```php
final readonly class LiveComponentState
{
    public function serialize(LiveComponent $component): ComponentState;

    public function deserialize(
        string $componentClass,
        array $state
    ): LiveComponent;

    public function generateChecksum(array $state): string;

    public function verifyChecksum(array $state, string $checksum): bool;
}
```

---

## Events

### Client-Side Events

#### `livecomponent:mount`

Fired when component is mounted.

```javascript
window.addEventListener('livecomponent:mount', (e) => {
    console.log('Component mounted:', e.detail);
    // { componentId, name, element }
});
```

---

#### `livecomponent:action-start`

Fired when action starts.

```javascript
window.addEventListener('livecomponent:action-start', (e) => {
    console.log('Action starting:', e.detail);
    // { componentId, action, params, optimistic }
});
```

---

#### `livecomponent:action-executed`

Fired when action completes.

```javascript
window.addEventListener('livecomponent:action-executed', (e) => {
    console.log('Action completed:', e.detail);
    // { componentId, action, duration, success }
});
```

---

#### `livecomponent:action-error`

Fired when action fails.

```javascript
window.addEventListener('livecomponent:action-error', (e) => {
    console.error('Action failed:', e.detail);
    // { componentId, action, error, response }
});
```

---

#### `livecomponent:fragment-updated`

Fired when fragment updates.

```javascript
window.addEventListener('livecomponent:fragment-updated', (e) => {
    console.log('Fragment updated:', e.detail);
    // { componentId, fragmentName, duration, nodesChanged }
});
```

---

#### `livecomponent:batch-sent`

Fired when batch request is sent.

```javascript
window.addEventListener('livecomponent:batch-sent', (e) => {
    console.log('Batch sent:', e.detail);
    // { componentId, actionsCount, payloadSize }
});
```

---

#### `livecomponent:optimistic-applied`

Fired when optimistic update is applied.

```javascript
window.addEventListener('livecomponent:optimistic-applied', (e) => {
    console.log('Optimistic update:', e.detail);
    // { componentId, action, stateBeforeOptimistic }
});
```

---

#### `livecomponent:optimistic-rollback`

Fired when optimistic update is rolled back.

```javascript
window.addEventListener('livecomponent:optimistic-rollback', (e) => {
    console.warn('Optimistic rollback:', e.detail);
    // { componentId, action, error, stateBeforeOptimistic }
});
```

---

#### `livecomponent:sse-connected`

Fired when SSE connection established.

```javascript
window.addEventListener('livecomponent:sse-connected', (e) => {
    console.log('SSE connected:', e.detail);
    // { componentId, channels }
});
```

---

#### `livecomponent:sse-disconnected`

Fired when SSE connection lost.

```javascript
window.addEventListener('livecomponent:sse-disconnected', (e) => {
    console.warn('SSE disconnected:', e.detail);
    // { componentId, reason }
});
```

---

#### `livecomponent:error`

Fired on any LiveComponent error.

```javascript
window.addEventListener('livecomponent:error', (e) => {
    console.error('LiveComponent error:', e.detail);
    // { componentId, type, message, code }

    if (e.detail.code === 'CSRF_TOKEN_EXPIRED') {
        LiveComponent.refreshCsrfToken();
    }
});
```

---

### Server-Side Events

Events dispatched during server-side processing (integrate with framework Event System).

#### `ComponentMountedEvent`

```php
final readonly class ComponentMountedEvent
{
    public function __construct(
        public string $componentClass,
        public ComponentId $componentId,
        public array $initialData
    ) {}
}
```

---

#### `ComponentActionExecutedEvent`

```php
final readonly class ComponentActionExecutedEvent
{
    public function __construct(
        public string $componentClass,
        public ComponentId $componentId,
        public string $actionName,
        public array $params,
        public float $duration,
        public bool $success
    ) {}
}
```

---

#### `ComponentUnmountedEvent`

```php
final readonly class ComponentUnmountedEvent
{
    public function __construct(
        public string $componentClass,
        public ComponentId $componentId
    ) {}
}
```

---

## Error Handling

### Common Errors

#### `ComponentNotFoundException`

Component class not found.

```php
throw ComponentNotFoundException::forClass('App\\Components\\NonExistent');
```

---

#### `ActionNotFoundException`

Action method not found on component.

```php
throw ActionNotFoundException::forAction('nonExistentAction', $componentClass);
```

---

#### `InvalidStateException`

Component state invalid or corrupted.

```php
throw InvalidStateException::checksumMismatch($expectedChecksum, $actualChecksum);
```

---

#### `RateLimitExceededException`

Rate limit exceeded for component/action.

```php
throw RateLimitExceededException::forAction($actionName, $retryAfter);
```

---

#### `UnauthorizedException`

User not authorized for action.

```php
throw UnauthorizedException::missingRole($requiredRole);
throw UnauthorizedException::missingPermission($requiredPermission);
```

---

## Type Definitions

### TypeScript Definitions

For TypeScript projects:

```typescript
// livecomponents.d.ts
declare global {
    interface Window {
        LiveComponent: {
            mount(element: HTMLElement): void;
            unmount(componentId: string): void;
            executeAction(
                componentId: string,
                action: string,
                params?: object
            ): Promise<void>;
            getComponent(componentId: string): Component | null;
            getState(componentId: string): object | null;
            setState(componentId: string, state: object): void;
            refresh(componentId: string): Promise<void>;
            configure(options: LiveComponentConfig): void;
            components: Map<string, Component>;
        };
    }

    interface Component {
        id: string;
        name: string;
        state: object;
        element: HTMLElement;
        isConnected: boolean;
        isPending: boolean;
    }

    interface LiveComponentConfig {
        batchSize?: number;
        batchDebounce?: number;
        optimisticUI?: boolean;
        csrfProtection?: boolean;
        enableSSE?: boolean;
    }
}

export {};
```

---

**Next**: [Advanced Features](advanced-features.md) →
