npm package: @klyntlabs/miniapp-sdk
Description: Mini-App SDK for Klynt IDE - provides registration, messaging, state isolation, and lifecycle management for mini-apps
Latest version: 0.0.7

# @klynt/miniapp-sdk

Mini-App SDK for the Klynt IDE platform. Provides the foundation for building reactive, isolated mini-applications within the workspace environment.

## Overview

The Mini-App SDK enables developers to create mini-apps that:
- Register with the workspace runtime via `defineMiniApp`
- Communicate through the `paneBus` message bus
- Maintain isolated state with `usePaneState`
- Handle lifecycle events and errors gracefully

## Installation

```bash
pnpm add @klynt/miniapp-sdk
```

## Quick Start

```typescript
import { useEffect } from 'react';
import {
  defineMiniApp,
  paneBus,
  usePaneState,
  MiniAppWrapper,
} from '@klynt/miniapp-sdk';

// Define your mini-app
const MyMiniApp = defineMiniApp({
  id: 'my-miniapp',
  name: 'My Mini App',
  capabilities: ['editor:read', 'workspace:layout:read'],
  component: MyComponent,
});

// Use state isolation
function MyComponent() {
  const [state, setState] = usePaneState('my-state', { count: 0 });

  // Subscribe to messages
  useEffect(() => {
    return paneBus.subscribe('editor.documentChanged', (msg) => {
      // Handle message
    });
  }, []);

  return <div>Count: {state.count}</div>;
}
```

## API Reference

### defineMiniApp(config)

Registers a mini-app with the workspace runtime.

```typescript
import { defineMiniApp } from '@klynt/miniapp-sdk';

const MyMiniApp = defineMiniApp({
  // Required fields
  id: 'my-editor-extension',  // kebab-case, lowercase
  name: 'My Editor Extension',
  component: MyComponent,

  // Optional fields
  description: 'An editor extension for code analysis',
  version: '1.0.0',
  capabilities: ['editor:read', 'editor:onChange'],
  optionalCapabilities: ['editor:write'],
  category: 'editor',
  allowMultiple: true,
  autoRegister: false,

  // Lifecycle hooks
  hooks: {
    onMount: (ctx) => {
      // Called when mini-app mounts
      // ctx: { paneId, capabilities, miniAppId, dimensions }
      return () => {
        // Optional cleanup function
      };
    },
    onUnmount: (ctx) => {
      // Called when mini-app unmounts
    },
    onFocus: (ctx) => {
      // Called when pane gains focus
    },
    onBlur: (ctx) => {
      // Called when pane loses focus
    },
    onMessage: (msg, ctx) => {
      // Called when paneBus message is received
    },
    onLayoutChange: (dimensions, ctx) => {
      // Called when pane is resized
    },
  },
});
```

**ID Validation Rules:**
- Must start with a lowercase letter
- Can contain lowercase letters, numbers, and hyphens
- Must not end with a hyphen
- Examples: `my-editor`, `terminal`, `challenge-runner-v2`

**Throws:**
- `MINIAPP.REGISTRATION.INVALID_ID` - Invalid ID format
- `MINIAPP.REGISTRATION.INVALID_MANIFEST` - Invalid config/capabilities
- `MINIAPP.REGISTRATION.INVALID_HOOK` - Non-function hook
- `MINIAPP.REGISTRATION.MISSING_COMPONENT` - Missing component
- `MINIAPP.REGISTRATION.DUPLICATE_ID` - ID already registered (when `autoRegister: true`)

### miniAppRegistry

Global registry for managing registered mini-apps:

```typescript
import { miniAppRegistry, defineMiniApp } from '@klynt/miniapp-sdk';

// Manual registration
const myApp = defineMiniApp({ id: 'my-app', name: 'My App', component: () => null });
miniAppRegistry.register(myApp);

// Or auto-register on creation
const autoApp = defineMiniApp({
  id: 'auto-app',
  name: 'Auto App',
  component: () => null,
  autoRegister: true,
});

// Query registry
miniAppRegistry.has('my-app');        // true
miniAppRegistry.get('my-app');        // MiniAppDefinition
miniAppRegistry.getAll();             // MiniAppDefinition[]
miniAppRegistry.size;                 // 2

// Unregister
miniAppRegistry.unregister('my-app'); // true
miniAppRegistry.clear();              // Clear all (useful for tests)
```

### paneBus

Message bus for cross-pane communication:
- `emit(topic, payload)` - Send a message
- `subscribe(topic, handler)` - Listen for messages
- `request(topic, payload)` - Request/response pattern

## Accessing PaneBus

### Recommended Patterns

#### Pattern 1: Import paneBus directly (simplest)

```typescript
import { paneBus } from '@klynt/miniapp-sdk';

paneBus.emit('topic', payload);
paneBus.subscribe('topic', handler);
```

#### Pattern 2: Use runtime hook (React components)

```typescript
import { useRuntime } from '@klynt/miniapp-sdk';

function MyComponent() {
  const { paneBus } = useRuntime();

  useEffect(() => {
    return paneBus.subscribe('topic', handler);
  }, [paneBus]);
}
```

#### Pattern 3: Get global runtime (non-React code)

```typescript
import { getGlobalRuntime } from '@klynt/miniapp-sdk';

const { paneBus } = getGlobalRuntime();
paneBus.emit('topic', payload);
```

### Debugging

The current runtime instance is available at `window.__KLYNT_PANEBUS_RUNTIME__` for debugging in browser DevTools:

```javascript
// In browser console
window.__KLYNT_PANEBUS_RUNTIME__.paneBus
window.__KLYNT_PANEBUS_RUNTIME__.debug?.getMessageHistory()
```

**IMPORTANT**: This is for debugging only. Application code should use the import patterns above.

### usePaneState(key, initialState)

Hook for pane-scoped state isolation.

### MiniAppWrapper

HOC providing error boundaries and lifecycle management.

## Capabilities

Mini-apps declare required capabilities in their manifest:

```typescript
const CAPABILITIES = {
  editor: ['read', 'write', 'onChange', 'subscribe'],
  terminal: ['read', 'execute', 'subscribe'],
  runtime: ['execute', 'logs', 'subscribe'],
  workspace: ['layout:read', 'layout:write'],
  lesson: ['read', 'navigate'],
  challenge: ['submit', 'validate'],
};
```

## Architecture

See the architecture documentation for details on:
- ADR-1: Mini-app registration model
- ADR-2: paneBus routing
- ADR-3: Capability enforcement
- ADR-4: State isolation
- ADR-5: Lifecycle hooks
- ADR-6: Error boundaries