@agentproto/relay 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts","../src/daemon-client.ts","../src/rate-limiter.ts","../src/timing-safe.ts","../src/server.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Startup config, read once from env at process boot. Deliberately\n * fails loud (throws) on anything that would otherwise leave the relay\n * running in an unsafe or ambiguous state — this service is designed to\n * sit on the public internet behind a tunnel, so there is no such thing\n * as a \"harmless\" missing setting here.\n */\n\nexport type TargetVia = \"agent\" | \"terminal\"\n\nexport interface RateLimitConfig {\n /** Max requests allowed per window. */\n max: number\n /** Window size in milliseconds. */\n windowMs: number\n}\n\nexport interface RelayConfig {\n /** The ONE session id/name this relay instance may wake up. Never\n * accepted as a request parameter — baked in at startup only. */\n targetSession: string\n /** How `text` gets delivered to the target session. */\n targetVia: TargetVia\n /** Shared-secret bearer token gating POST /relay/inbound. */\n token: string\n /** Base URL of the agentproto daemon this relay talks to. */\n daemonUrl: string\n rateLimit: RateLimitConfig\n}\n\nconst DEFAULT_DAEMON_URL = \"http://127.0.0.1:18790\"\nconst DEFAULT_TARGET_VIA: TargetVia = \"agent\"\nconst DEFAULT_RATE_LIMIT_MAX = 20\nconst DEFAULT_RATE_LIMIT_WINDOW_MS = 60_000\n\nexport function loadConfigFromEnv(env: NodeJS.ProcessEnv = process.env): RelayConfig {\n const targetSession = (env.AGENTPROTO_RELAY_TARGET_SESSION ?? \"\").trim()\n if (!targetSession) {\n throw new Error(\n \"AGENTPROTO_RELAY_TARGET_SESSION is required — set it to the id or name of \" +\n \"the ONE session this relay is allowed to wake up. It is never accepted as \" +\n \"a request parameter, by design.\",\n )\n }\n\n const rawVia = (env.AGENTPROTO_RELAY_TARGET_VIA ?? DEFAULT_TARGET_VIA).trim()\n if (rawVia !== \"agent\" && rawVia !== \"terminal\") {\n throw new Error(\n `AGENTPROTO_RELAY_TARGET_VIA must be \"agent\" or \"terminal\" (got \"${rawVia}\").`,\n )\n }\n\n const token = env.AGENTPROTO_RELAY_TOKEN ?? \"\"\n if (!token) {\n throw new Error(\n \"AGENTPROTO_RELAY_TOKEN is required — refusing to start without a shared \" +\n \"secret. This service is designed to be exposed publicly; there is no \" +\n \"no-auth fallback.\",\n )\n }\n\n const daemonUrl = (env.AGENTPROTO_DAEMON_URL || DEFAULT_DAEMON_URL).replace(/\\/+$/, \"\")\n\n return {\n targetSession,\n targetVia: rawVia,\n token,\n daemonUrl,\n rateLimit: {\n max: parsePositiveInt(env.AGENTPROTO_RELAY_RATE_LIMIT, DEFAULT_RATE_LIMIT_MAX),\n windowMs: parsePositiveInt(\n env.AGENTPROTO_RELAY_RATE_WINDOW_MS,\n DEFAULT_RATE_LIMIT_WINDOW_MS,\n ),\n },\n }\n}\n\nfunction parsePositiveInt(raw: string | undefined, fallback: number): number {\n if (!raw) return fallback\n const n = Number(raw)\n return Number.isInteger(n) && n > 0 ? n : fallback\n}\n","/**\n * Thin HTTP(S)/WS client for the ONE thing this relay needs from an\n * agentproto daemon: \"is my configured target session alive, and can I\n * push text into it.\" Talks to the daemon purely over its public\n * REST/WS surface — this package is not an MCP client and does not\n * link against @agentproto/runtime.\n */\n\nimport { readFile } from \"node:fs/promises\"\nimport { homedir } from \"node:os\"\nimport { join } from \"node:path\"\nimport WebSocket from \"ws\"\n\nexport interface SessionAliveResult {\n ok: boolean\n /** Canonical session id, resolved from id-or-name by the daemon. */\n id?: string\n status?: string\n /** Present when ok is false — human-readable cause. */\n reason?: string\n}\n\nexport interface DeliveryResult {\n ok: boolean\n status?: number\n message?: string\n}\n\nconst DEAD_STATUSES = new Set([\"exited\", \"killed\", \"error\"])\n\n/**\n * GET /sessions/:id — resolves id-or-name to a canonical session, and\n * confirms it's actually alive (not exited/killed/errored, process\n * still running). Read-only route, no daemon auth token needed.\n */\nexport async function checkSessionAlive(\n daemonUrl: string,\n target: string,\n fetchImpl: typeof fetch = fetch,\n): Promise<SessionAliveResult> {\n let res: Response\n try {\n res = await fetchImpl(`${daemonUrl}/sessions/${encodeURIComponent(target)}`, {\n signal: AbortSignal.timeout(10_000),\n })\n } catch (err) {\n return {\n ok: false,\n reason: `could not reach daemon at ${daemonUrl}: ${err instanceof Error ? err.message : String(err)}`,\n }\n }\n if (res.status === 404) {\n return { ok: false, reason: `no session \"${target}\" on the daemon` }\n }\n if (!res.ok) {\n return { ok: false, reason: `daemon returned HTTP ${res.status} for GET /sessions/${target}` }\n }\n let desc: { id?: unknown; status?: unknown; processAlive?: unknown }\n try {\n desc = (await res.json()) as { id?: unknown; status?: unknown; processAlive?: unknown }\n } catch {\n return { ok: false, reason: \"daemon returned a non-JSON session descriptor\" }\n }\n if (typeof desc.id !== \"string\") {\n return { ok: false, reason: \"daemon's session descriptor is missing an id\" }\n }\n const status = typeof desc.status === \"string\" ? desc.status : undefined\n if (status && DEAD_STATUSES.has(status)) {\n return { ok: false, id: desc.id, status, reason: `session \"${target}\" has status \"${status}\"` }\n }\n if (desc.processAlive === false) {\n return { ok: false, id: desc.id, status, reason: `session \"${target}\" process is not alive` }\n }\n return { ok: true, id: desc.id, status }\n}\n\ninterface RegistryMetaLike {\n pid?: unknown\n token?: unknown\n}\n\nfunction isPidAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch (err) {\n return (err as NodeJS.ErrnoException).code === \"EPERM\"\n }\n}\n\n/**\n * A daemon publishes its per-boot bearer token in two places (see\n * @agentproto/runtime's agentproto-dir.ts): a workspace-scoped\n * `<workspace>/.agentproto/runtime.json`, and a workspace-independent\n * `~/.agentproto/daemons/<port>.json`. The central one is keyed purely\n * by port, so we check it first; the workspace one requires an extra\n * round trip to /health to learn the workspace path, and is a\n * best-effort write on the daemon's side (it can be absent even for a\n * live, otherwise-healthy daemon), so it's the fallback.\n */\nexport async function resolveDaemonToken(\n daemonUrl: string,\n opts: { fetchImpl?: typeof fetch; homeDir?: string } = {},\n): Promise<string | undefined> {\n const fetchImpl = opts.fetchImpl ?? fetch\n const homeDir = opts.homeDir ?? homedir()\n\n const fromRegistry = await readRegistryToken(daemonUrl, homeDir)\n if (fromRegistry) return fromRegistry\n return readWorkspaceToken(daemonUrl, fetchImpl)\n}\n\nasync function readRegistryToken(daemonUrl: string, homeDir: string): Promise<string | undefined> {\n let port: string\n try {\n port = new URL(daemonUrl).port\n } catch {\n return undefined\n }\n if (!port) return undefined\n try {\n const raw = await readFile(join(homeDir, \".agentproto\", \"daemons\", `${port}.json`), \"utf8\")\n const meta = JSON.parse(raw) as RegistryMetaLike\n if (typeof meta.pid === \"number\" && !isPidAlive(meta.pid)) return undefined\n return typeof meta.token === \"string\" && meta.token ? meta.token : undefined\n } catch {\n return undefined\n }\n}\n\nasync function readWorkspaceToken(\n daemonUrl: string,\n fetchImpl: typeof fetch,\n): Promise<string | undefined> {\n try {\n const res = await fetchImpl(`${daemonUrl}/health`, { signal: AbortSignal.timeout(5_000) })\n if (!res.ok) return undefined\n const health = (await res.json()) as { workspace?: unknown }\n if (typeof health.workspace !== \"string\" || !health.workspace) return undefined\n const raw = await readFile(join(health.workspace, \".agentproto\", \"runtime.json\"), \"utf8\")\n const meta = JSON.parse(raw) as RegistryMetaLike\n return typeof meta.token === \"string\" && meta.token ? meta.token : undefined\n } catch {\n return undefined\n }\n}\n\n/**\n * POST /sessions/:id/prompt?wait=false — the REST equivalent of the\n * `agent_prompt` MCP tool. Fire-and-forget on purpose: an external\n * webhook sender may have a short timeout, and there's no reason to\n * hold its connection open for an entire LLM turn just to relay one\n * message in.\n */\nexport async function sendAgentPrompt(\n daemonUrl: string,\n sessionId: string,\n text: string,\n token: string | undefined,\n fetchImpl: typeof fetch = fetch,\n): Promise<DeliveryResult> {\n try {\n const res = await fetchImpl(\n `${daemonUrl}/sessions/${encodeURIComponent(sessionId)}/prompt?wait=false`,\n {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n ...(token ? { authorization: `Bearer ${token}` } : {}),\n },\n body: JSON.stringify({ prompt: text }),\n signal: AbortSignal.timeout(15_000),\n },\n )\n if (res.ok) return { ok: true, status: res.status }\n return { ok: false, status: res.status, message: await describeErrorResponse(res) }\n } catch (err) {\n return { ok: false, message: err instanceof Error ? err.message : String(err) }\n }\n}\n\nasync function describeErrorResponse(res: Response): Promise<string> {\n try {\n const body = (await res.json()) as { message?: unknown; error?: unknown }\n if (typeof body.message === \"string\") return body.message\n if (typeof body.error === \"string\") return body.error\n return JSON.stringify(body)\n } catch {\n return `HTTP ${res.status}`\n }\n}\n\n/**\n * Writes text to a live PTY session's stdin. Unlike `agent_prompt`,\n * there is no plain-HTTP REST route for `terminal_input` on the\n * daemon — the only transport is the WebSocket upgrade at\n * /sessions/:id/pty (JSON frames), so this is the one delivery path\n * that isn't a simple fetch() call.\n */\nexport async function sendTerminalInput(\n daemonUrl: string,\n sessionId: string,\n text: string,\n token: string | undefined,\n timeoutMs = 10_000,\n): Promise<DeliveryResult> {\n const wsUrl = `${daemonUrl.replace(/^http/, \"ws\")}/sessions/${encodeURIComponent(sessionId)}/pty`\n return new Promise<DeliveryResult>(resolvePromise => {\n let settled = false\n const settle = (result: DeliveryResult): void => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n resolvePromise(result)\n }\n\n const ws = new WebSocket(wsUrl, {\n headers: token ? { authorization: `Bearer ${token}` } : {},\n })\n const timer = setTimeout(() => {\n ws.terminate()\n settle({ ok: false, message: \"terminal_input: timed out connecting to the daemon\" })\n }, timeoutMs)\n\n ws.once(\"open\", () => {\n ws.send(JSON.stringify({ kind: \"input\", text }))\n ws.close(1000)\n settle({ ok: true })\n })\n ws.once(\"unexpected-response\", (_req, res) => {\n ws.terminate()\n settle({\n ok: false,\n status: res.statusCode,\n message: `terminal_input: daemon rejected the WebSocket upgrade with HTTP ${res.statusCode}`,\n })\n })\n ws.once(\"error\", err => {\n settle({ ok: false, message: err instanceof Error ? err.message : String(err) })\n })\n })\n}\n","/**\n * Global (not per-caller) in-memory sliding-window rate limiter for\n * POST /relay/inbound. Global rather than per-IP on purpose: this relay\n * has exactly one legitimate caller by design (whoever holds the\n * bearer token), and keying by a client-supplied/proxy-supplied IP\n * (e.g. X-Forwarded-For behind a tunnel) would let a caller grow an\n * unbounded map of fake keys — a memory-exhaustion vector worse than\n * the abuse it would prevent.\n */\n\nexport interface RateLimiter {\n /** Returns true if the call is allowed under the current window. */\n allow(): boolean\n}\n\nexport interface RateLimiterOptions {\n /** Max calls allowed per window. */\n max: number\n /** Window size in milliseconds. */\n windowMs: number\n /** Injectable clock — tests pass a fake one. Defaults to Date.now. */\n now?: () => number\n}\n\nexport function createRateLimiter(opts: RateLimiterOptions): RateLimiter {\n const { max, windowMs } = opts\n const now = opts.now ?? Date.now\n const timestamps: number[] = []\n\n return {\n allow(): boolean {\n const t = now()\n const cutoff = t - windowMs\n while (timestamps.length > 0 && (timestamps[0] as number) <= cutoff) {\n timestamps.shift()\n }\n if (timestamps.length >= max) return false\n timestamps.push(t)\n return true\n },\n }\n}\n","/**\n * Constant-time string equality for comparing a caller-supplied bearer\n * token against the configured secret. `crypto.timingSafeEqual` alone\n * isn't enough here — it throws on mismatched buffer lengths, and a\n * caller can measure that throw (vs. a full compare) to learn the\n * secret's length one guess at a time. HMAC-blinding both inputs to a\n * fixed-size digest first removes the length signal entirely: any two\n * strings, of any length, produce same-length digests to compare.\n */\n\nimport { createHmac, randomBytes, timingSafeEqual } from \"node:crypto\"\n\nexport function timingSafeEqualStrings(a: string, b: string): boolean {\n const key = randomBytes(32)\n const digestA = createHmac(\"sha256\", key).update(a, \"utf8\").digest()\n const digestB = createHmac(\"sha256\", key).update(b, \"utf8\").digest()\n return timingSafeEqual(digestA, digestB)\n}\n","/**\n * The relay's own HTTP surface:\n *\n * POST /relay/inbound auth + rate-limited; wakes the ONE configured\n * target session with the request's `text`.\n * GET /relay/health trivial healthcheck, no auth.\n *\n * The target session is never a request parameter — it's baked into\n * `config.targetSession` at process startup (see config.ts) and that's\n * the only session this server will ever touch.\n */\n\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\"\nimport * as defaultDaemonClient from \"./daemon-client.js\"\nimport type { DeliveryResult, SessionAliveResult } from \"./daemon-client.js\"\nimport { createRateLimiter, type RateLimiter } from \"./rate-limiter.js\"\nimport { timingSafeEqualStrings } from \"./timing-safe.js\"\nimport type { RelayConfig } from \"./config.js\"\n\nexport interface DaemonClient {\n checkSessionAlive(daemonUrl: string, target: string): Promise<SessionAliveResult>\n resolveDaemonToken(daemonUrl: string): Promise<string | undefined>\n sendAgentPrompt(\n daemonUrl: string,\n sessionId: string,\n text: string,\n token: string | undefined,\n ): Promise<DeliveryResult>\n sendTerminalInput(\n daemonUrl: string,\n sessionId: string,\n text: string,\n token: string | undefined,\n ): Promise<DeliveryResult>\n}\n\nexport interface CreateRelayServerOptions {\n config: RelayConfig\n daemonClient?: DaemonClient\n rateLimiter?: RateLimiter\n}\n\nconst MAX_BODY_BYTES = 1_000_000\n\nexport function createRelayServer(opts: CreateRelayServerOptions): Server {\n const daemonClient = opts.daemonClient ?? defaultDaemonClient\n const rateLimiter = opts.rateLimiter ?? createRateLimiter(opts.config.rateLimit)\n\n return createServer((req, res) => {\n handleRequest(req, res, opts.config, daemonClient, rateLimiter).catch(err => {\n if (!res.headersSent) {\n writeJson(res, 500, {\n error: \"internal_error\",\n message: err instanceof Error ? err.message : String(err),\n })\n }\n })\n })\n}\n\nasync function handleRequest(\n req: IncomingMessage,\n res: ServerResponse,\n config: RelayConfig,\n daemonClient: DaemonClient,\n rateLimiter: RateLimiter,\n): Promise<void> {\n const url = new URL(req.url ?? \"/\", \"http://relay.local\")\n\n if (url.pathname === \"/relay/health\" && req.method === \"GET\") {\n writeJson(res, 200, { ok: true })\n return\n }\n\n if (url.pathname === \"/relay/inbound\" && req.method === \"POST\") {\n await handleInbound(req, res, config, daemonClient, rateLimiter)\n return\n }\n\n writeJson(res, 404, { error: \"not_found\" })\n}\n\nasync function handleInbound(\n req: IncomingMessage,\n res: ServerResponse,\n config: RelayConfig,\n daemonClient: DaemonClient,\n rateLimiter: RateLimiter,\n): Promise<void> {\n // Rate limit before anything else — including before auth — so a\n // flood of requests (valid token or not) can't cost more than the\n // configured budget of daemon calls.\n if (!rateLimiter.allow()) {\n writeJson(res, 429, {\n error: \"rate_limited\",\n message: `Too many requests — limit is ${config.rateLimit.max} per ${config.rateLimit.windowMs}ms.`,\n })\n return\n }\n\n const authHeader = req.headers.authorization ?? \"\"\n const expected = `Bearer ${config.token}`\n if (!timingSafeEqualStrings(authHeader, expected)) {\n writeJson(res, 401, { error: \"unauthorized\" })\n return\n }\n\n let body: unknown\n try {\n body = await readJsonBody(req, MAX_BODY_BYTES)\n } catch (err) {\n writeJson(res, 400, {\n error: \"invalid_body\",\n message: err instanceof Error ? err.message : String(err),\n })\n return\n }\n if (body === INVALID_JSON) {\n writeJson(res, 400, { error: \"invalid_body\", message: \"Body must be valid JSON.\" })\n return\n }\n const text = (body as { text?: unknown } | null)?.text\n if (typeof text !== \"string\" || text.length === 0) {\n writeJson(res, 400, {\n error: \"missing_text\",\n message: \"Body must include a non-empty top-level `text` string. All other fields are ignored.\",\n })\n return\n }\n\n const alive = await daemonClient.checkSessionAlive(config.daemonUrl, config.targetSession)\n if (!alive.ok || !alive.id) {\n writeJson(res, 502, {\n error: \"target_session_unavailable\",\n message: alive.reason ?? \"target session is not available\",\n })\n return\n }\n\n const token = await daemonClient.resolveDaemonToken(config.daemonUrl)\n\n const result =\n config.targetVia === \"terminal\"\n ? await daemonClient.sendTerminalInput(config.daemonUrl, alive.id, text, token)\n : await daemonClient.sendAgentPrompt(config.daemonUrl, alive.id, text, token)\n\n if (!result.ok) {\n const status = result.status && result.status >= 400 && result.status < 500 ? result.status : 502\n writeJson(res, status, {\n error: \"relay_delivery_failed\",\n message: result.message ?? \"delivery to the target session failed\",\n })\n return\n }\n\n writeJson(res, 202, { ok: true, sessionId: alive.id, via: config.targetVia })\n}\n\nfunction writeJson(res: ServerResponse, status: number, body: unknown): void {\n res.writeHead(status, { \"content-type\": \"application/json\" })\n res.end(JSON.stringify(body))\n}\n\nconst INVALID_JSON = Symbol(\"invalid_json\")\n\nfunction readJsonBody(req: IncomingMessage, maxBytes: number): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let size = 0\n const chunks: Buffer[] = []\n req.on(\"data\", (chunk: Buffer) => {\n size += chunk.length\n if (size > maxBytes) {\n reject(new Error(`request body exceeds ${maxBytes} bytes`))\n req.destroy()\n return\n }\n chunks.push(chunk)\n })\n req.on(\"end\", () => {\n if (chunks.length === 0) {\n resolve(null)\n return\n }\n try {\n resolve(JSON.parse(Buffer.concat(chunks).toString(\"utf8\")))\n } catch {\n resolve(INVALID_JSON)\n }\n })\n req.on(\"error\", reject)\n })\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@agentproto/relay",
3
+ "version": "0.1.0",
4
+ "description": "@agentproto/relay — a standalone companion service that lets one external HTTP webhook wake up exactly one pre-configured agentproto session. Generic inbound-only primitive: fixed target session baked into startup config, mandatory bearer token, basic rate limiting.",
5
+ "keywords": [
6
+ "agentproto",
7
+ "relay",
8
+ "webhook",
9
+ "daemon",
10
+ "inbound"
11
+ ],
12
+ "homepage": "https://agentproto.sh",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/agentproto/ts",
16
+ "directory": "packages/relay"
17
+ },
18
+ "bugs": {
19
+ "url": "https://github.com/agentproto/ts/issues"
20
+ },
21
+ "license": "MIT",
22
+ "type": "module",
23
+ "main": "dist/index.mjs",
24
+ "module": "dist/index.mjs",
25
+ "types": "dist/index.d.ts",
26
+ "bin": {
27
+ "agentproto-relay": "./dist/cli.mjs"
28
+ },
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "import": "./dist/index.mjs",
33
+ "default": "./dist/index.mjs"
34
+ },
35
+ "./package.json": "./package.json"
36
+ },
37
+ "files": [
38
+ "dist",
39
+ "README.md",
40
+ "LICENSE"
41
+ ],
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "sideEffects": false,
46
+ "dependencies": {
47
+ "ws": "^8.18.0"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^25.6.2",
51
+ "@types/ws": "^8.5.13",
52
+ "tsup": "^8.5.1",
53
+ "typescript": "^5.9.3",
54
+ "vitest": "^3.2.4",
55
+ "@agentproto/tooling": "0.1.0-alpha.0"
56
+ },
57
+ "engines": {
58
+ "node": ">=20.9.0"
59
+ },
60
+ "scripts": {
61
+ "dev": "tsup --watch",
62
+ "build": "tsup",
63
+ "clean": "rm -rf dist",
64
+ "check-types": "tsc --noEmit",
65
+ "test": "vitest run",
66
+ "test:watch": "vitest"
67
+ }
68
+ }