Skip to content

Latest commit

 

History

History
102 lines (74 loc) · 3.46 KB

File metadata and controls

102 lines (74 loc) · 3.46 KB

@agentruntimecontrolprotocol/node

Attach the ARCP WebSocket upgrade to an existing Node http.Server or https.Server. The lowest-level host integration — every other Node-based middleware (@agentruntimecontrolprotocol/express, @agentruntimecontrolprotocol/fastify, @agentruntimecontrolprotocol/hono) layers on top of this one.

Install

pnpm add @agentruntimecontrolprotocol/node @agentruntimecontrolprotocol/runtime

Use

import { createServer } from "node:http";
import { ARCPServer } from "@agentruntimecontrolprotocol/runtime";
import { attachArcpUpgrade } from "@agentruntimecontrolprotocol/node";

const httpServer = createServer((req, res) => {
  // your regular HTTP handler (REST, static, etc.)
  res.end("hello");
});

const arcp = new ARCPServer({
  /* ... */
});

const handle = attachArcpUpgrade(httpServer, {
  path: "/arcp",
  allowedHosts: ["api.example.com"],
  onTransport: (transport, req) => arcp.accept(transport),
});

httpServer.listen(3000);

// later:
await handle.close();

API

attachArcpUpgrade(server, options)

function attachArcpUpgrade(
  server: HttpServer,
  options: AttachArcpUpgradeOptions,
): ArcpUpgradeHandle;

Wires an "upgrade" listener on the given server. Returns a handle with close() to detach.

AttachArcpUpgradeOptions

Field Default Notes
path?: string "/arcp" URL path that should upgrade. Other paths fall through.
allowedHosts?: readonly string[] none If set, rejects upgrades whose Host header isn't in the list (DNS-rebind protection).
onTransport: (transport, req) => void Receives a paired Transport and the original IncomingMessage. Typically calls server.accept(transport).

ArcpUpgradeHandle

Field Notes
close(): Promise<void> Detach the upgrade listener; existing transports are unaffected.

DNS-rebind protection

Without allowedHosts, the upgrade accepts any Host header. For public-facing servers, set it to the bare hostnames you serve from (the matcher strips the port from the request's Host before comparing, so don't include :port in the list):

attachArcpUpgrade(httpServer, {
  allowedHosts: ["arcp.example.com", "127.0.0.1"],
  onTransport: (t) => arcp.accept(t),
});

A mismatch returns 403 Forbidden to the upgrading client.

Multiple paths

To host multiple ARCP namespaces on one server, attach more than once — path is a literal exact match (no prefix or glob routing), and unmatched paths fall through to other listeners:

attachArcpUpgrade(httpServer, { path: "/arcp/v1", onTransport: forV1 });
attachArcpUpgrade(httpServer, { path: "/arcp/v2", onTransport: forV2 });

For tenant routing inside a single path, parse req.url inside onTransport and dispatch to the right ARCPServer instance.

Source

packages/middleware/node/src/.