@klex/cloud-api
v1.2.3
Published
Types, RPC client, and agent tunnel SDK for the Klex Cloud v1 public API.
Readme
@klex/cloud-api
Types, a Hono RPC client, and the Node.js agent tunnel SDK for the Klex Cloud v1 API.
The package includes the public V1AppType contract, the client factory, and the complete tunnel protocol. Agents do not need a separate protocol dependency. hono and ws remain runtime dependencies.
Install
pnpm add @klex/cloud-apiHTTP client
Pass the deployment's v1 base URL. The package does not hardcode an API host.
import { createCloudApiClient } from '@klex/cloud-api';
const client = createCloudApiClient('https://cloud.example.com/v1', {
headers: async () => ({
Authorization: `Bearer ${await getAccessToken()}`,
}),
});The package also exports V1AppType and the inferred CloudApiClient type.
Agent tunnel
Use startAgentTunnel() unless you are implementing a different tunnel protocol runtime. Opening the WebSocket transport alone does not start protocol handling.
startAgentTunnel() owns the complete protocol lifecycle:
- Opens and authenticates the WebSocket.
- Installs frame listeners before the handshake completes.
- Decodes WELCOME, request, control, and error frames.
- Answers protocol PING frames with PONG frames.
- Terminates silent connections when server heartbeats stop.
- Assembles each tunneled HTTP request and calls
onRequest. - Sends response and error frames.
- Closes protocol state when the transport closes.
- Reconnects after unexpected disconnects by default.
The agent owns application behavior inside onRequest, including routes, authorization, logging, and shutdown coordination.
Recommended integration
The request handler uses standard Request and Response objects. It is not tied to Hono.
import { startAgentTunnel } from '@klex/cloud-api';
const tunnel = await startAgentTunnel({
baseUrl: 'https://cloud.example.com/v1',
accessToken: () => getAccessToken(),
headers: { 'X-Agent-Version': '1.0.0' },
onRequest: async (request) => {
return adminApi.fetch(request);
},
onConnect: (agentId) => {
logger.info({ agentId }, 'agent tunnel connected');
},
onError: (error) => {
logger.error({ error }, 'agent tunnel error');
},
});
// During graceful shutdown:
await tunnel.stop();accessToken may be a string or a synchronous or asynchronous provider. The SDK calls the provider before every connection attempt and adds its result as Authorization: Bearer <accessToken>. It ignores a user-supplied Authorization header.
Set reconnect: false if the agent owns reconnection. Otherwise, the SDK reconnects with exponential backoff. Use reconnectDelayMs and maxReconnectDelayMs to configure that backoff.
After WELCOME, the SDK expects a server PING within heartbeatTimeoutMs, which defaults to 90,000 ms. Each PING refreshes the deadline. If it expires, the SDK terminates the socket, reports onClose(1001, 'server heartbeat timeout'), and reconnects unless reconnection is disabled or the tunnel was stopped. Ordinary request traffic does not refresh this deadline.
The Cloud server sends PINGs every 30,000 ms by default. If your server uses a longer interval, increase heartbeatTimeoutMs to leave enough margin for delayed heartbeats. The value must be an integer between 1 and 2,147,483,647 ms. The same option is available on AgentTunnelConnection for low-level integrations.
Hono compatibility
Existing consumers may pass a Hono app directly. This form remains supported for compatibility, but new integrations should use onRequest.
import { Hono } from 'hono';
import { startAgentTunnel } from '@klex/cloud-api';
const app = new Hono();
app.get('/health', (c) => c.json({ ok: true }));
const tunnel = await startAgentTunnel({
baseUrl: 'https://cloud.example.com/v1',
accessToken: () => getAccessToken(),
app,
});app may also be a factory. The SDK calls the factory for every connection and reconnect.
Low-level transport API
connectAgentTunnelTransport() opens and authenticates a WebSocket. It does not decode frames, answer PING messages, dispatch requests, or manage protocol state.
Do not use the transport function as the normal agent entry point. A transport-only integration can connect successfully while every request and PING times out.
import {
AgentTunnelConnection,
connectAgentTunnelTransport,
} from '@klex/cloud-api';
const transport = await connectAgentTunnelTransport(baseUrl, {
accessToken: () => getAccessToken(),
});
const protocol = new AgentTunnelConnection(transport, {
onRequest: (request) => adminApi.fetch(request),
onError: reportTunnelError,
});
protocol.start();Use this API only when you need direct transport or protocol control. The old connectAgentTunnel() name remains as a deprecated alias for compatibility.
License
MIT
