npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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-api

HTTP 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