8a6cd7f559
This commit adds 6 new documentation files to fill critical gaps: - CONTRIBUTING.md: Developer onboarding guide with setup, workflow, code style, testing, and adding features - TROUBLESHOOTING.md: Common issues and solutions for errors, model issues, tool issues, channel issues, gateway issues, configuration issues, and memory/database issues - docs/api/PROTOCOL.md: Gateway JSON-RPC protocol documentation with connection, authentication, message format, methods, events, error codes, and example client implementation - docs/api/TOOLS.md: Tools API documentation covering tool interface, input schema format, result format, tool patterns, tool registration, tool policy, execution flow, and builtin tools reference - docs/deployment/PRODUCTION.md: Production deployment guide covering Docker deployment, systemd service, security, configuration, monitoring, backup & recovery, and performance tuning - docs/performance/TUNING.md: Performance optimization guide covering context management, model routing, tool execution, memory & embeddings, session management, database performance, gateway performance, and resource usage These files complement the existing excellent documentation (README.md, AGENTS.md, ARCHITECTURE.md, STRUCTURE.md, CONVENTIONS.md) to provide complete coverage for users, developers, and operators.
1008 lines
16 KiB
Markdown
1008 lines
16 KiB
Markdown
# Gateway API Protocol
|
|
|
|
Flynn's gateway exposes a WebSocket-based JSON-RPC protocol for real-time communication with the AI agent. This document describes the protocol in detail.
|
|
|
|
## Table of Contents
|
|
|
|
- [Overview](#overview)
|
|
- [Connection](#connection)
|
|
- [Authentication](#authentication)
|
|
- [Message Format](#message-format)
|
|
- [Methods](#methods)
|
|
- [Events](#events)
|
|
- [Error Codes](#error-codes)
|
|
- [Example Client](#example-client)
|
|
|
|
## Overview
|
|
|
|
The gateway provides:
|
|
|
|
- **WebSocket Server**: Real-time bidirectional communication
|
|
- **JSON-RPC 2.0**: Structured request/response protocol
|
|
- **Streaming Events**: Real-time updates during agent processing
|
|
- **HTTP Server**: Serves static dashboard and handles webhook endpoints
|
|
|
|
### Base URL
|
|
|
|
- WebSocket: `ws://localhost:18800` (or `wss://` if using TLS)
|
|
- HTTP: `http://localhost:18800` (or `https://` if using TLS)
|
|
- Health check: `GET /health`
|
|
|
|
### Default Ports
|
|
|
|
- Gateway: `18800`
|
|
- Tailscale Serve (if enabled): `443` (HTTPS)
|
|
|
|
## Connection
|
|
|
|
### WebSocket Handshake
|
|
|
|
```javascript
|
|
// Browser
|
|
const ws = new WebSocket('ws://localhost:18800');
|
|
|
|
// Node.js (ws library)
|
|
const WebSocket = require('ws');
|
|
const ws = new WebSocket('ws://localhost:18800');
|
|
```
|
|
|
|
### Connection Lifecycle
|
|
|
|
1. Client connects to WebSocket endpoint
|
|
2. Server validates authentication (if configured)
|
|
3. Connection assigned unique ID
|
|
4. Client can start sending requests
|
|
5. Server sends responses and events asynchronously
|
|
|
|
### Disconnection
|
|
|
|
```javascript
|
|
ws.onclose = (event) => {
|
|
console.log('Disconnected:', event.code, event.reason);
|
|
};
|
|
```
|
|
|
|
Common close codes:
|
|
- `1000`: Normal closure
|
|
- `1001`: Endpoint going away
|
|
- `1006`: Abnormal closure (network issue)
|
|
|
|
## Authentication
|
|
|
|
### Bearer Token Auth
|
|
|
|
If `gateway.auth.token` is configured, all WebSocket connections must provide authentication:
|
|
|
|
```javascript
|
|
const ws = new WebSocket('ws://localhost:18800', {
|
|
headers: {
|
|
'Authorization': 'Bearer your-secret-token'
|
|
}
|
|
});
|
|
```
|
|
|
|
### Tailscale Identity
|
|
|
|
If `gateway.auth.trustTailscaleIdentity` is enabled, connections from Tailscale are trusted based on the `Tailscale-User-Login` header.
|
|
|
|
```javascript
|
|
// Automatic when connecting via Tailscale
|
|
// No additional auth required if trustTailscaleIdentity: true
|
|
```
|
|
|
|
### HTTP Auth
|
|
|
|
If `gateway.auth.applyToHttp` is `true` (default when token is set), HTTP requests also require bearer token:
|
|
|
|
```javascript
|
|
fetch('http://localhost:18800/api/health', {
|
|
headers: {
|
|
'Authorization': 'Bearer your-secret-token'
|
|
}
|
|
});
|
|
```
|
|
|
|
## Message Format
|
|
|
|
### Request (Client → Server)
|
|
|
|
```typescript
|
|
interface GatewayRequest {
|
|
id: number; // Unique request ID (integer)
|
|
method: string; // Method name (e.g., 'agent.send', 'system.info')
|
|
params?: Record<string, unknown>; // Method parameters (optional)
|
|
}
|
|
```
|
|
|
|
Example:
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"method": "agent.send",
|
|
"params": {
|
|
"message": "Hello, Flynn!",
|
|
"session": "telegram:123456"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Response (Server → Client)
|
|
|
|
```typescript
|
|
interface GatewayResponse {
|
|
id: number; // Request ID this responds to
|
|
result: unknown; // Method result
|
|
}
|
|
```
|
|
|
|
Example:
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"result": {
|
|
"sessionId": "telegram:123456",
|
|
"response": "Hello! How can I help you today?"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Error (Server → Client)
|
|
|
|
```typescript
|
|
interface GatewayError {
|
|
id: number;
|
|
error: {
|
|
code: ErrorCode; // Error code (integer)
|
|
message: string; // Human-readable error message
|
|
};
|
|
}
|
|
```
|
|
|
|
Example:
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"error": {
|
|
"code": 4,
|
|
"message": "Request cancelled by client"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Event (Server → Client)
|
|
|
|
```typescript
|
|
interface GatewayEvent {
|
|
id: number; // Request ID this relates to
|
|
event: EventType; // Event type string
|
|
data: unknown; // Event-specific data
|
|
}
|
|
```
|
|
|
|
Example:
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"event": "content",
|
|
"data": {
|
|
"text": "Hello! How can I help you today?"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Methods
|
|
|
|
### System Methods
|
|
|
|
#### `system.info`
|
|
|
|
Get gateway information.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"method": "system.info"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"result": {
|
|
"version": "0.1.0",
|
|
"uptime": 12345,
|
|
"connections": 2
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `system.disconnect`
|
|
|
|
Close the connection gracefully.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": 2,
|
|
"method": "system.disconnect"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": 2,
|
|
"result": {
|
|
"success": true
|
|
}
|
|
}
|
|
```
|
|
|
|
### Session Methods
|
|
|
|
#### `sessions.list`
|
|
|
|
List all sessions.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": 3,
|
|
"method": "sessions.list"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": 3,
|
|
"result": {
|
|
"sessions": [
|
|
{
|
|
"id": "telegram:123456",
|
|
"createdAt": "2025-02-13T10:00:00Z",
|
|
"lastActiveAt": "2025-02-13T12:00:00Z",
|
|
"messageCount": 42,
|
|
"connectionCount": 1
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `sessions.get`
|
|
|
|
Get session details.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": 4,
|
|
"method": "sessions.get",
|
|
"params": {
|
|
"sessionId": "telegram:123456"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": 4,
|
|
"result": {
|
|
"id": "telegram:123456",
|
|
"createdAt": "2025-02-13T10:00:00Z",
|
|
"lastActiveAt": "2025-02-13T12:00:00Z",
|
|
"history": [
|
|
{
|
|
"role": "user",
|
|
"content": "Hello"
|
|
},
|
|
{
|
|
"role": "assistant",
|
|
"content": "Hi there!"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `sessions.create`
|
|
|
|
Create or resume a session.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": 5,
|
|
"method": "sessions.create",
|
|
"params": {
|
|
"sessionId": "telegram:123456"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": 5,
|
|
"result": {
|
|
"sessionId": "telegram:123456",
|
|
"created": true
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `sessions.delete`
|
|
|
|
Delete a session.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": 6,
|
|
"method": "sessions.delete",
|
|
"params": {
|
|
"sessionId": "telegram:123456"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": 6,
|
|
"result": {
|
|
"success": true
|
|
}
|
|
}
|
|
```
|
|
|
|
### Agent Methods
|
|
|
|
#### `agent.send`
|
|
|
|
Send a message to the agent and stream response.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": 7,
|
|
"method": "agent.send",
|
|
"params": {
|
|
"message": "What's the weather?",
|
|
"sessionId": "telegram:123456",
|
|
"attachments": [
|
|
{
|
|
"mimeType": "image/jpeg",
|
|
"data": "base64encodedimage..."
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response (final):**
|
|
```json
|
|
{
|
|
"id": 7,
|
|
"result": {
|
|
"content": "I can't check the weather without access to weather APIs. Would you like me to help you with something else?",
|
|
"usage": {
|
|
"inputTokens": 25,
|
|
"outputTokens": 30
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Events (streamed during processing):**
|
|
|
|
`content` event:
|
|
```json
|
|
{
|
|
"id": 7,
|
|
"event": "content",
|
|
"data": {
|
|
"text": "I can't check the weather"
|
|
}
|
|
}
|
|
```
|
|
|
|
`tool_start` event:
|
|
```json
|
|
{
|
|
"id": 7,
|
|
"event": "tool_start",
|
|
"data": {
|
|
"tool": "shell.exec",
|
|
"args": {
|
|
"command": "echo 'Hello'"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
`tool_end` event:
|
|
```json
|
|
{
|
|
"id": 7,
|
|
"event": "tool_end",
|
|
"data": {
|
|
"tool": "shell.exec",
|
|
"result": {
|
|
"success": true,
|
|
"output": "Hello\n",
|
|
"error": null
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
`attachment` event:
|
|
```json
|
|
{
|
|
"id": 7,
|
|
"event": "attachment",
|
|
"data": {
|
|
"mimeType": "image/png",
|
|
"data": "base64encoded..."
|
|
}
|
|
}
|
|
```
|
|
|
|
`done` event:
|
|
```json
|
|
{
|
|
"id": 7,
|
|
"event": "done",
|
|
"data": {
|
|
"content": "Complete response here..."
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `agent.cancel`
|
|
|
|
Cancel the current agent operation.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": 8,
|
|
"method": "agent.cancel",
|
|
"params": {
|
|
"sessionId": "telegram:123456"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": 8,
|
|
"result": {
|
|
"cancelled": true
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `agent.setToolUseCallback`
|
|
|
|
Set callback for tool use events (for confirmation UI).
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": 9,
|
|
"method": "agent.setToolUseCallback",
|
|
"params": {
|
|
"sessionId": "telegram:123456",
|
|
"enabled": true
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": 9,
|
|
"result": {
|
|
"success": true
|
|
}
|
|
}
|
|
```
|
|
|
|
### Tool Methods
|
|
|
|
#### `tools.list`
|
|
|
|
List available tools.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": 10,
|
|
"method": "tools.list",
|
|
"params": {
|
|
"sessionId": "telegram:123456"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": 10,
|
|
"result": {
|
|
"tools": [
|
|
{
|
|
"name": "shell.exec",
|
|
"description": "Execute a shell command...",
|
|
"inputSchema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"command": { "type": "string" }
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `tools.execute`
|
|
|
|
Execute a tool directly (bypass agent).
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": 11,
|
|
"method": "tools.execute",
|
|
"params": {
|
|
"sessionId": "telegram:123456",
|
|
"tool": "shell.exec",
|
|
"args": {
|
|
"command": "echo 'Hello'"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": 11,
|
|
"result": {
|
|
"success": true,
|
|
"output": "Hello\n"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Config Methods
|
|
|
|
#### `config.get`
|
|
|
|
Get current configuration (secrets redacted).
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": 12,
|
|
"method": "config.get"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": 12,
|
|
"result": {
|
|
"models": {
|
|
"default": {
|
|
"anthropic": {
|
|
"apiKey": "***"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `config.reload`
|
|
|
|
Reload configuration from file.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": 13,
|
|
"method": "config.reload"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": 13,
|
|
"result": {
|
|
"success": true
|
|
}
|
|
}
|
|
```
|
|
|
|
### Pairing Methods
|
|
|
|
#### `pairing.generate`
|
|
|
|
Generate a pairing code for unknown senders.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": 14,
|
|
"method": "pairing.generate",
|
|
"params": {
|
|
"channel": "telegram"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": 14,
|
|
"result": {
|
|
"code": "ABC123",
|
|
"expiresAt": "2025-02-13T12:05:00Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `pairing.list`
|
|
|
|
List active pairing codes.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": 15,
|
|
"method": "pairing.list"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": 15,
|
|
"result": {
|
|
"codes": [
|
|
{
|
|
"code": "ABC123",
|
|
"channel": "telegram",
|
|
"createdAt": "2025-02-13T12:00:00Z",
|
|
"expiresAt": "2025-02-13T12:05:00Z"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
## Events
|
|
|
|
### Event Types
|
|
|
|
#### `content`
|
|
|
|
Streamed text content from the agent.
|
|
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"event": "content",
|
|
"data": {
|
|
"text": "Partial response..."
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `tool_start`
|
|
|
|
Tool execution started.
|
|
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"event": "tool_start",
|
|
"data": {
|
|
"tool": "shell.exec",
|
|
"args": {
|
|
"command": "echo 'test'"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `tool_end`
|
|
|
|
Tool execution completed.
|
|
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"event": "tool_end",
|
|
"data": {
|
|
"tool": "shell.exec",
|
|
"result": {
|
|
"success": true,
|
|
"output": "test\n"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `attachment`
|
|
|
|
Outbound attachment (image, audio, file).
|
|
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"event": "attachment",
|
|
"data": {
|
|
"mimeType": "image/jpeg",
|
|
"data": "base64encoded...",
|
|
"filename": "output.jpg"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `done`
|
|
|
|
Agent processing complete (final response).
|
|
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"event": "done",
|
|
"data": {
|
|
"content": "Complete final response..."
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `error`
|
|
|
|
Error occurred during processing.
|
|
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"event": "error",
|
|
"data": {
|
|
"code": 5,
|
|
"message": "Internal error: ..."
|
|
}
|
|
}
|
|
```
|
|
|
|
## Error Codes
|
|
|
|
| Code | Name | Description |
|
|
|------|------|-------------|
|
|
| -1 | `ParseError` | Invalid JSON in request |
|
|
| -2 | `InvalidRequest` | Missing required fields |
|
|
| -3 | `MethodNotFound` | Unknown method name |
|
|
| -4 | `AuthRequired` | Authentication required but not provided |
|
|
| -5 | `AuthFailed` | Authentication failed |
|
|
| 1 | `SessionNotFound` | Session ID doesn't exist |
|
|
| 2 | `ToolNotFound` | Tool name doesn't exist |
|
|
| 3 | `AgentBusy` | Agent is processing another request |
|
|
| 4 | `RequestCancelled` | Request was cancelled by client |
|
|
| 5 | `InternalError` | Unexpected server error |
|
|
|
|
## Example Client
|
|
|
|
### Browser Client
|
|
|
|
```javascript
|
|
class FlynnClient {
|
|
constructor(url, token) {
|
|
this.url = url;
|
|
this.token = token;
|
|
this.requestId = 0;
|
|
this.pending = new Map();
|
|
}
|
|
|
|
connect() {
|
|
const headers = {};
|
|
if (this.token) {
|
|
headers['Authorization'] = `Bearer ${this.token}`;
|
|
}
|
|
|
|
this.ws = new WebSocket(this.url, { headers });
|
|
|
|
this.ws.onopen = () => {
|
|
console.log('Connected to Flynn gateway');
|
|
};
|
|
|
|
this.ws.onmessage = (event) => {
|
|
const message = JSON.parse(event.data);
|
|
this.handleMessage(message);
|
|
};
|
|
|
|
this.ws.onerror = (error) => {
|
|
console.error('WebSocket error:', error);
|
|
};
|
|
|
|
this.ws.onclose = () => {
|
|
console.log('Disconnected from Flynn gateway');
|
|
};
|
|
}
|
|
|
|
sendRequest(method, params = {}) {
|
|
return new Promise((resolve, reject) => {
|
|
const id = ++this.requestId;
|
|
|
|
const request = {
|
|
id,
|
|
method,
|
|
params
|
|
};
|
|
|
|
this.ws.send(JSON.stringify(request));
|
|
|
|
// Store promise for response
|
|
this.pending.set(id, { resolve, reject });
|
|
|
|
// Set timeout
|
|
setTimeout(() => {
|
|
if (this.pending.has(id)) {
|
|
this.pending.delete(id);
|
|
reject(new Error('Request timeout'));
|
|
}
|
|
}, 30000);
|
|
});
|
|
}
|
|
|
|
handleMessage(message) {
|
|
// Response
|
|
if ('result' in message) {
|
|
const { id, result } = message;
|
|
const pending = this.pending.get(id);
|
|
if (pending) {
|
|
this.pending.delete(id);
|
|
pending.resolve(result);
|
|
}
|
|
}
|
|
|
|
// Error
|
|
else if ('error' in message) {
|
|
const { id, error } = message;
|
|
const pending = this.pending.get(id);
|
|
if (pending) {
|
|
this.pending.delete(id);
|
|
const err = new Error(error.message);
|
|
err.code = error.code;
|
|
pending.reject(err);
|
|
}
|
|
}
|
|
|
|
// Event
|
|
else if ('event' in message) {
|
|
this.handleEvent(message);
|
|
}
|
|
}
|
|
|
|
handleEvent(event) {
|
|
const { id, event: eventType, data } = event;
|
|
|
|
switch (eventType) {
|
|
case 'content':
|
|
console.log('Content:', data.text);
|
|
break;
|
|
case 'tool_start':
|
|
console.log('Tool started:', data.tool, data.args);
|
|
break;
|
|
case 'tool_end':
|
|
console.log('Tool completed:', data.tool, data.result);
|
|
break;
|
|
case 'attachment':
|
|
console.log('Attachment received:', data.mimeType);
|
|
break;
|
|
case 'done':
|
|
console.log('Done:', data.content);
|
|
break;
|
|
case 'error':
|
|
console.error('Error:', data.code, data.message);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Convenience methods
|
|
async systemInfo() {
|
|
return this.sendRequest('system.info');
|
|
}
|
|
|
|
async listSessions() {
|
|
return this.sendRequest('sessions.list');
|
|
}
|
|
|
|
async sendMessage(message, sessionId, attachments = []) {
|
|
return this.sendRequest('agent.send', {
|
|
message,
|
|
sessionId,
|
|
attachments
|
|
});
|
|
}
|
|
|
|
async listTools(sessionId) {
|
|
return this.sendRequest('tools.list', { sessionId });
|
|
}
|
|
}
|
|
|
|
// Usage
|
|
const client = new FlynnClient('ws://localhost:18800', 'your-token');
|
|
client.connect();
|
|
|
|
client.onopen = async () => {
|
|
const info = await client.systemInfo();
|
|
console.log('Gateway info:', info);
|
|
|
|
const response = await client.sendMessage('Hello, Flynn!', 'telegram:123456');
|
|
console.log('Response:', response);
|
|
};
|
|
```
|
|
|
|
### Node.js Client
|
|
|
|
```javascript
|
|
const WebSocket = require('ws');
|
|
|
|
class FlynnNodeClient extends FlynnClient {
|
|
connect() {
|
|
const options = {};
|
|
if (this.token) {
|
|
options.headers = { 'Authorization': `Bearer ${this.token}` };
|
|
}
|
|
|
|
this.ws = new WebSocket(this.url, options);
|
|
|
|
// ... same as browser client
|
|
}
|
|
}
|
|
|
|
// Usage
|
|
const client = new FlynnNodeClient('ws://localhost:18800', 'your-token');
|
|
client.connect();
|
|
```
|
|
|
|
### HTTP Fetch Example
|
|
|
|
```javascript
|
|
// Health check
|
|
async function checkHealth() {
|
|
const response = await fetch('http://localhost:18800/health', {
|
|
headers: {
|
|
'Authorization': 'Bearer your-token'
|
|
}
|
|
});
|
|
|
|
const status = await response.json();
|
|
console.log('Health:', status);
|
|
}
|
|
|
|
checkHealth();
|
|
```
|
|
|
|
---
|
|
|
|
For more implementation details, see:
|
|
- Protocol types: `src/gateway/protocol.ts`
|
|
- Handlers: `src/gateway/handlers/`
|
|
- Gateway server: `src/gateway/server.ts`
|