{"version":3,"sources":["../src/relay-server/cors.ts","../src/relay-server/args.ts","../src/relay-server/core.ts","../src/relay-server/node.ts","../src/relay-server/cli.ts"],"names":["randomBytes","next","createHash","timingSafeEqual","URL","ok","createServer"],"mappings":"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","file":"relay-server-cli.cjs","sourcesContent":["/**\n * CORS policy for the relay: `*`, or an allowlist of origins.\n *\n * `Access-Control-Allow-Origin` carries exactly ONE origin or `*` — a browser\n * matches the header's value against its own origin and nothing else. So a list\n * cannot be sent as a list. It has to be checked per request: echo the request's\n * `Origin` back when it is listed, send `Vary: Origin` so a cache does not hand\n * one origin's answer to another, and send no allow-origin header at all when\n * the origin is not listed.\n *\n * Not `null` for \"matches nothing\": sandboxed iframes and `file://` pages send\n * `Origin: null`, so that value grants exactly the pages least entitled to it.\n */\n\nexport type CorsPolicy = { kind: \"any\" } | { kind: \"list\"; origins: string[] };\n\n/**\n * Parse `*`, a comma-separated origin list, or an array of origins.\n *\n * Throws on anything that is not unambiguously one of those — an empty value,\n * `*` mixed with named origins, `null`, or an entry with a path — because a\n * relay that starts with a policy nobody wrote fails later, in a browser, where\n * the operator cannot see why.\n */\nexport function parseCorsOrigins(value: string | readonly string[]): CorsPolicy {\n  const entries = (typeof value === \"string\" ? value.split(\",\") : [...value])\n    .map((entry) => entry.trim())\n    .filter((entry) => entry.length > 0);\n\n  if (entries.length === 0) {\n    throw new Error(\"CORS origin list is empty: pass `*` or one or more origins, e.g. https://example.com\");\n  }\n\n  if (entries.includes(\"*\")) {\n    if (entries.length === 1) return { kind: \"any\" };\n    throw new Error(\n      \"CORS `*` cannot be combined with named origins — `*` already allows every origin, so the list would mean nothing. Pass either `*` or the origins.\",\n    );\n  }\n\n  const origins: string[] = [];\n  for (const entry of entries) {\n    const origin = normalizeOrigin(entry);\n    if (!origins.includes(origin)) origins.push(origin);\n  }\n\n  return { kind: \"list\", origins };\n}\n\n/**\n * The form a browser sends in `Origin`: lower-case scheme and host, no default\n * port, no path. One trailing slash is forgiven, since that is how origins get\n * copied out of an address bar.\n */\nfunction normalizeOrigin(raw: string): string {\n  if (raw.toLowerCase() === \"null\") {\n    throw new Error(\"CORS origin `null` is refused: it is what sandboxed iframes and file:// pages send.\");\n  }\n\n  let url: URL;\n  try {\n    url = new URL(raw);\n  } catch {\n    throw new Error(`CORS origin \"${raw}\" is not an origin — expected scheme://host[:port], e.g. https://example.com`);\n  }\n\n  if ((url.pathname !== \"/\" && url.pathname !== \"\") || url.search || url.hash || url.username || url.password) {\n    throw new Error(`CORS origin \"${raw}\" has a path, query or credentials — an origin is only scheme://host[:port]`);\n  }\n\n  // Special schemes (http, https, …) have a tuple origin; `URL` serialises it.\n  if (url.origin !== \"null\") return url.origin;\n\n  // A non-special scheme (chrome-extension://id, …) has no tuple origin in the\n  // URL spec, but a browser still sends scheme://host for it.\n  if (url.host) return `${url.protocol}//${url.host}`;\n\n  throw new Error(`CORS origin \"${raw}\" is not an origin — expected scheme://host[:port], e.g. https://example.com`);\n}\n\n/** The allow-origin value for one request, or `null` for \"send none\". */\nexport function allowOriginFor(policy: CorsPolicy, requestOrigin: string | undefined): string | null {\n  if (policy.kind === \"any\") return \"*\";\n  return requestOrigin !== undefined && policy.origins.includes(requestOrigin) ? requestOrigin : null;\n}\n\n/** Human-readable policy, for a startup log line. */\nexport function describeCorsPolicy(policy: CorsPolicy): string {\n  return policy.kind === \"any\" ? \"*\" : policy.origins.join(\",\");\n}\n","import { describeCorsPolicy, parseCorsOrigins, type CorsPolicy } from \"./cors\";\n\n/**\n * Settings resolution for `agent-integrations-relay`.\n *\n * **Precedence, for every setting: flag, then env var, then default.** A flag\n * is what the person starting the process typed; an env var is ambient and is\n * often set by a platform (Forge sets `PORT`; this package's Dockerfile sets\n * `HOST=0.0.0.0`), so the explicit one wins. When a flag overrides an env var\n * that is also set to something different, the override is reported in\n * `warnings` rather than applied silently — the relay's own deploy README once\n * told operators to set `CORS_ALLOW_ORIGIN` to override a start script that\n * passed `--cors`, and nothing ever said the env var was being ignored.\n *\n * An env var set to the empty string counts as unset, which is how platform\n * env editors write a cleared value.\n */\n\nexport type SettingSource = \"flag\" | \"env\" | \"default\";\n\nexport type RelayCliConfig = {\n  port: number;\n  host: string;\n  prefix: string;\n  ttlMs: number;\n  cors: CorsPolicy;\n  sources: { port: SettingSource; host: SettingSource; prefix: SettingSource; ttlMs: SettingSource; cors: SettingSource };\n  warnings: string[];\n  help: boolean;\n};\n\nexport type ParseResult = { ok: true; config: RelayCliConfig } | { ok: false; error: string };\n\ntype Key = \"port\" | \"host\" | \"prefix\" | \"ttlMs\" | \"cors\";\n\nconst SETTINGS: Record<Key, { flag: string; env: string; fallback: string }> = {\n  port: { flag: \"--port\", env: \"PORT\", fallback: \"8787\" },\n  // Loopback by default: this relay fronts terminal_run (RCE) and register is\n  // unauthenticated, so it must not listen on all interfaces unless the\n  // operator explicitly opts in with --host 0.0.0.0.\n  host: { flag: \"--host\", env: \"HOST\", fallback: \"127.0.0.1\" },\n  prefix: { flag: \"--prefix\", env: \"PREFIX\", fallback: \"\" },\n  ttlMs: { flag: \"--ttl-ms\", env: \"TTL_MS\", fallback: String(4 * 60 * 60 * 1000) },\n  cors: { flag: \"--cors\", env: \"CORS_ALLOW_ORIGIN\", fallback: \"*\" },\n};\n\nexport function parseRelayArgs(argv: readonly string[], env: Readonly<Record<string, string | undefined>>): ParseResult {\n  const flags: Partial<Record<Key, string>> = {};\n  let help = false;\n\n  for (let i = 0; i < argv.length; i++) {\n    const arg = argv[i]!;\n    if (arg === \"-h\" || arg === \"--help\") {\n      help = true;\n      continue;\n    }\n\n    const key = (Object.keys(SETTINGS) as Key[]).find((k) => SETTINGS[k].flag === arg);\n    if (!key) return { ok: false, error: `unknown flag: ${arg}` };\n\n    const value = argv[i + 1];\n    if (value === undefined || value.startsWith(\"--\")) return { ok: false, error: `${arg} needs a value` };\n    i++;\n\n    // --cors is a LIST, so repeating it adds origins. Every other flag is a\n    // single value, and the last one given wins.\n    flags[key] = key === \"cors\" && flags.cors !== undefined ? `${flags.cors},${value}` : value;\n  }\n\n  const warnings: string[] = [];\n  const raw = {} as Record<Key, string>;\n  const sources = {} as Record<Key, SettingSource>;\n\n  for (const key of Object.keys(SETTINGS) as Key[]) {\n    const { flag, env: envName, fallback } = SETTINGS[key];\n    const fromEnv = env[envName] === \"\" ? undefined : env[envName];\n    const fromFlag = flags[key];\n\n    if (fromFlag !== undefined) {\n      raw[key] = fromFlag;\n      sources[key] = \"flag\";\n      if (fromEnv !== undefined && fromEnv !== fromFlag) {\n        warnings.push(`${envName}=${fromEnv} is ignored: ${flag} ${fromFlag} was passed, and a flag wins over its env var.`);\n      }\n    } else if (fromEnv !== undefined) {\n      raw[key] = fromEnv;\n      sources[key] = \"env\";\n    } else {\n      raw[key] = fallback;\n      sources[key] = \"default\";\n    }\n  }\n\n  const named = (key: Key) => (sources[key] === \"env\" ? SETTINGS[key].env : SETTINGS[key].flag);\n\n  const port = Number(raw.port);\n  if (!Number.isInteger(port) || port <= 0 || port > 65535) {\n    return { ok: false, error: `invalid ${named(\"port\")}: ${raw.port}` };\n  }\n\n  const ttlMs = Number(raw.ttlMs);\n  if (!Number.isFinite(ttlMs) || ttlMs <= 0) {\n    return { ok: false, error: `invalid ${named(\"ttlMs\")}: ${raw.ttlMs}` };\n  }\n\n  let cors: CorsPolicy;\n  try {\n    cors = parseCorsOrigins(raw.cors);\n  } catch (e) {\n    return { ok: false, error: `invalid ${named(\"cors\")}: ${e instanceof Error ? e.message : String(e)}` };\n  }\n\n  // Same-value warnings compare raw strings; compare the parsed policies too, so\n  // `--cors \"https://a,https://b\"` against `CORS_ALLOW_ORIGIN=\"https://a, https://b\"`\n  // is not reported as a conflict.\n  if (sources.cors === \"flag\" && env.CORS_ALLOW_ORIGIN) {\n    try {\n      if (describeCorsPolicy(parseCorsOrigins(env.CORS_ALLOW_ORIGIN)) === describeCorsPolicy(cors)) {\n        const i = warnings.findIndex((w) => w.startsWith(\"CORS_ALLOW_ORIGIN=\"));\n        if (i !== -1) warnings.splice(i, 1);\n      }\n    } catch {\n      /* an unparseable env var that lost to the flag stays reported */\n    }\n  }\n\n  return {\n    ok: true,\n    config: {\n      port,\n      host: raw.host,\n      prefix: raw.prefix,\n      ttlMs,\n      cors,\n      sources: sources as RelayCliConfig[\"sources\"],\n      warnings,\n      help,\n    },\n  };\n}\n","import { createHash, randomBytes, timingSafeEqual } from \"node:crypto\";\n\n/**\n * RelayBroker — pure logic for the SSE+POST tunnel described in\n * docs/relay-protocol.md, hostable in any Node-compatible runtime\n * (Node, Bun, Deno-with-Node-compat, Cloudflare Workers via the Web\n * standards subset). No HTTP framework opinions; this class just\n * stores sessions, validates tokens, enqueues frames, and produces\n * SSE event payloads ready to flush.\n *\n *   const broker = new RelayBroker();\n *   const reg     = broker.register(\"session-id\", \"token\");      // ok / error\n *   broker.inbox(\"session-id\", \"token\", '{\"jsonrpc\":\"2.0\",…}');  // enqueue inbound\n *   const sub = broker.subscribe(\"session-id\", \"token\", \"inbound\");\n *   for await (const payload of sub.frames()) yield encodeSse(payload);\n *\n * Storage is an in-memory Map by default — fine for a single relay\n * process. To run multiple instances behind a load balancer, swap\n * `MemoryStore` for a Redis-backed equivalent (same Store interface).\n */\n\nexport type Direction = \"inbound\" | \"outbound\";\n\nexport type Session = {\n  id: string;\n  /** SHA-256 hex of the original token. Compared with timing-safe equals. */\n  tokenHash: string;\n  /** Last touched (ms since epoch). Used for TTL cleanup. */\n  lastSeen: number;\n};\n\nexport type Subscriber = {\n  id: string;\n  direction: Direction;\n  queue: string[];\n  resolveNext: ((frame: string | null) => void) | null;\n  /**\n   * The caller-supplied client label, when one was given.\n   *\n   * Used to route a RESPONSE back to whoever asked. Without it the broker\n   * cannot tell two holders of one bearer token apart, and every reply goes to\n   * every subscriber -- so a second token holder passively receives the results\n   * of everyone else's tool calls without making one.\n   */\n  client?: string;\n  /**\n   * Present only for a LONG-POLL subscriber, which outlives any one request:\n   * it is read by a series of `GET /poll` calls rather than one open stream,\n   * so it needs its own liveness record.\n   */\n  poll?: {\n    /** Last time a poll started or finished (ms since epoch). */\n    lastSeen: number;\n    /** Polls currently parked on this subscriber. Never pruned while > 0. */\n    parked: number;\n    /** Wake every parked poll — a frame landed, or the session ended. */\n    wakers: Set<() => void>;\n  };\n  /** Set once the subscriber has been ended (unsubscribed, pruned, or its session is gone). */\n  ended?: boolean;\n};\n\nexport type RelayBrokerOptions = {\n  /** Sessions auto-expire after this many ms of inactivity. Default 4h. */\n  ttlMs?: number;\n  /** Cleanup tick interval in ms. Default 60 000. */\n  reapIntervalMs?: number;\n  /**\n   * A long-poll subscriber that has not polled for this long is dropped (and,\n   * for an outbound one, the page is told the peer left). Checked on the reap\n   * tick. Default 60 000 — the PHP relay's window, and comfortably longer than\n   * the 25 s maximum park, so a healthy poller is never pruned between polls.\n   */\n  pollIdleMs?: number;\n  /** Bring-your-own storage layer (redis, etc.). Defaults to in-memory. */\n  store?: Store;\n};\n\nexport interface Store {\n  putSession(s: Session): void;\n  getSession(id: string): Session | undefined;\n  deleteSession(id: string): void;\n  /** Used by the reap tick — return ids whose lastSeen < cutoff. */\n  expiredSessionIds(cutoff: number): string[];\n}\n\nclass MemoryStore implements Store {\n  private sessions = new Map<string, Session>();\n  putSession(s: Session) { this.sessions.set(s.id, s); }\n  getSession(id: string) { return this.sessions.get(id); }\n  deleteSession(id: string) { this.sessions.delete(id); }\n  expiredSessionIds(cutoff: number) {\n    const out: string[] = [];\n    for (const [id, s] of this.sessions) if (s.lastSeen < cutoff) out.push(id);\n    return out;\n  }\n}\n\nconst SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{4,64}$/;\n\n/** The subscriber ids this broker hands out — and the only shape a poll may echo back. */\nconst SUBSCRIBER_ID_PATTERN = /^[a-f0-9]{16}$/;\n\nexport class RelayBroker {\n  private readonly ttlMs: number;\n  private readonly pollIdleMs: number;\n  private readonly store: Store;\n  /** Per-session, per-direction subscriber list. */\n  private subs: Map<string, Map<string, Map<string, Subscriber>>> = new Map();\n\n  /** Per-session map of JSON-RPC request id -> the client that asked. */\n  private callers: Map<string, Map<string, string>> = new Map();\n  private reaper?: ReturnType<typeof setInterval>;\n\n  constructor(opts: RelayBrokerOptions = {}) {\n    this.ttlMs = opts.ttlMs ?? 4 * 60 * 60 * 1000; // 4h\n    this.pollIdleMs = opts.pollIdleMs ?? 60_000;\n    this.store = opts.store ?? new MemoryStore();\n    const tick = opts.reapIntervalMs ?? 60_000;\n    if (tick > 0) {\n      this.reaper = setInterval(() => this.reap(), tick);\n      // Don't keep the process alive just for the reaper.\n      if (typeof (this.reaper as { unref?: () => void }).unref === \"function\") {\n        (this.reaper as { unref: () => void }).unref();\n      }\n    }\n  }\n\n  dispose() {\n    if (this.reaper) clearInterval(this.reaper);\n    for (const id of [...this.subs.keys()]) this.endSubscribers(id);\n    this.subs.clear();\n    this.callers.clear();\n  }\n\n  /** Register a session id + token. Idempotent — same id+token re-registers,\n   *  different token fails. */\n  register(id: string, token: string): { ok: true } | { ok: false; reason: string } {\n    if (!SESSION_ID_PATTERN.test(id)) return { ok: false, reason: \"invalid_session_id\" };\n    if (typeof token !== \"string\" || token.length < 16 || token.length > 128) {\n      return { ok: false, reason: \"invalid_token\" };\n    }\n    const existing = this.store.getSession(id);\n    const hash = sha256Hex(token);\n    if (existing) {\n      if (!timingSafeEqualHex(existing.tokenHash, hash)) return { ok: false, reason: \"session_taken\" };\n      existing.lastSeen = Date.now();\n      this.store.putSession(existing);\n      return { ok: true };\n    }\n    this.store.putSession({ id, tokenHash: hash, lastSeen: Date.now() });\n    return { ok: true };\n  }\n\n  unregister(id: string, token: string): boolean {\n    if (!this.validate(id, token)) return false;\n    this.store.deleteSession(id);\n    this.endSubscribers(id);\n    this.subs.delete(id);\n    this.callers.delete(id);\n    return true;\n  }\n\n  /**\n   * Validate an authenticated touch, saying WHY when it fails.\n   *\n   * `session_gone` and `invalid_token` are different facts and a client acts on\n   * them differently. A gone session means the page has closed or the TTL has\n   * elapsed — the NORMAL end of a relay lifecycle, since the browser is the\n   * server and no state persists across restarts. A bad token means the caller\n   * is wrong.\n   *\n   * They were collapsed into one boolean and reported as `invalid_token`, so an\n   * agent holding a perfectly good token against a closed page was told its\n   * credentials were wrong. Not a missing signal — an actively misleading one,\n   * which sends the reader to debug an auth path that was never the problem.\n   *\n   * Missing credentials stay `invalid_token`: a request that never named a\n   * session has not discovered a dead one.\n   *\n   * The reason is deliberately NOT widened to cover a wrong token on a live\n   * session — answering `session_gone` there would tell an unauthenticated\n   * caller which sessions exist.\n   *\n   * Requested by the Prism harness while designing a non-Node relay client.\n   */\n  check(id: string, token: string): { ok: true } | { ok: false; reason: \"invalid_token\" | \"session_gone\" } {\n    if (!id || !token) return { ok: false, reason: \"invalid_token\" };\n\n    const s = this.store.getSession(id);\n    if (!s) return { ok: false, reason: \"session_gone\" };\n\n    if (!timingSafeEqualHex(s.tokenHash, sha256Hex(token))) {\n      return { ok: false, reason: \"invalid_token\" };\n    }\n\n    s.lastSeen = Date.now();\n    this.store.putSession(s);\n    return { ok: true };\n  }\n\n  /**\n   * Validate an authenticated touch and slide the TTL forward.\n   *\n   * Kept as-is for existing callers; `check()` is the one that says why.\n   */\n  validate(id: string, token: string): boolean {\n    return this.check(id, token).ok;\n  }\n\n  /** Drop a session — the page closed, or a test needs it gone. */\n  dropSession(id: string): void {\n    this.store.deleteSession(id);\n    this.endSubscribers(id);\n    this.subs.delete(id);\n    this.callers.delete(id);\n  }\n\n  /** Push a frame onto the inbound queue (external agent → browser). */\n  inbox(id: string, token: string, payload: string, opts: { client?: string } = {}): boolean {\n    if (!this.validate(id, token)) return false;\n    if (!this.isFrame(payload)) return false;\n\n    // Remember WHO asked, so the reply can go back to them alone.\n    if (opts.client !== undefined) {\n      this.rememberCaller(id, payload, opts.client);\n    }\n\n    this.fanOut(id, \"inbound\", payload);\n    return true;\n  }\n\n  /** Push a frame onto the outbound queue (browser server → external agents). */\n  outbox(id: string, token: string, payload: string): boolean {\n    if (!this.validate(id, token)) return false;\n    if (!this.isFrame(payload)) return false;\n\n    // A RESPONSE goes to the caller. A NOTIFICATION goes to everyone.\n    //\n    // `relay-protocol.md` has always said \"tool-call replies go back on the\n    // transport that originated the call\"; the relay broadcast them instead.\n    // Combined with a bearer token that carries no per-agent identity, that\n    // meant a second token holder passively received the results of everyone\n    // else's calls -- turning a share link from \"you may act here\" into \"you\n    // may watch everyone acting here\", which nobody chose.\n    //\n    // Notifications stay broadcast: presence, activity and server-pushed state\n    // answer nobody and are meant for every attached client. Narrowing those\n    // would break the collaboration this exists to serve.\n    const target = this.callerFor(id, payload);\n\n    if (target === null) {\n      this.fanOut(id, \"outbound\", payload);\n      return true;\n    }\n\n    this.fanOutTo(id, \"outbound\", payload, target);\n    return true;\n  }\n\n  /**\n   * Subscribe to a session's queue for one direction. Returns an iterable\n   * the caller (an HTTP handler) pumps as SSE.\n   */\n  subscribe(id: string, token: string, direction: Direction, opts: { client?: string } = {}): SubscribeResult {\n    // check(), not validate(): a stream re-attaching to an ended session must be\n    // told the session is GONE, not that its token is wrong.\n    const auth = this.check(id, token);\n    if (!auth.ok) return auth;\n\n    const subscriberId = randomBytes(8).toString(\"hex\");\n    const subscriber: Subscriber = {\n      id: subscriberId,\n      direction,\n      queue: [],\n      resolveNext: null,\n      client: opts.client,\n    };\n    this.getDirSubs(id, direction).set(subscriberId, subscriber);\n    if (direction === \"outbound\") this.announcePeer(id, \"notifications/peer_joined\", subscriberId);\n\n    /** Async generator the HTTP handler drains. Yields raw frame payloads;\n     *  the handler is responsible for SSE framing (`event: mcp\ndata: …`). */\n    const frames = async function* (this: Subscriber): AsyncGenerator<string, void, void> {\n      while (true) {\n        if (this.queue.length > 0) {\n          const next = this.queue.shift();\n          if (next !== undefined) yield next;\n          continue;\n        }\n        // Checked before parking, not only on wake: a subscriber ended while\n        // the generator was busy yielding has nobody left to wake it.\n        if (this.ended) return;\n        const next = await new Promise<string | null>((resolve) => {\n          this.resolveNext = resolve;\n        });\n        this.resolveNext = null;\n        if (next === null) return;\n        yield next;\n      }\n    }.bind(subscriber);\n\n    return {\n      ok: true,\n      subscriberId,\n      frames: frames(),\n      unsubscribe: () => {\n        // Wake the generator and let it return cleanly.\n        this.endSubscriber(subscriber);\n        this.removeSubscriber(id, subscriber);\n      },\n    };\n  }\n\n  /**\n   * Attach a LONG-POLL subscriber, or re-attach the one a previous poll created.\n   *\n   * The CDN-safe receive leg: a series of short requests instead of one open\n   * stream, because Cloudflare's HTTP/3 edge resets long-lived SSE. Same\n   * contract as the PHP relay in px-ui-sandbox and the one\n   * `@particle-academy/fancy-cf-relay` and `mcp-relay-client` speak:\n   *\n   * - The first poll gets a fresh 16-hex subscriber id; the client echoes it back\n   *   as `subscriber` on every later poll and reads the same queue.\n   * - An id in that shape that this session does not know (pruned, say) is\n   *   adopted as a NEW subscriber under that id, as the PHP relay does, so a\n   *   client that went quiet and came back keeps its identity.\n   * - An id belonging to a STREAMING subscriber is never adopted: one queue read\n   *   by two consumers splits its frames between them.\n   *\n   * Frames queue on the subscriber between polls, so nothing is lost in the gap\n   * between one request ending and the next arriving. A poller that stops is\n   * pruned after `pollIdleMs`.\n   */\n  poll(\n    id: string,\n    token: string,\n    direction: Direction,\n    opts: { subscriber?: string; client?: string } = {},\n  ): PollResult {\n    const auth = this.check(id, token);\n    if (!auth.ok) return auth;\n\n    const dir = this.getDirSubs(id, direction);\n    const requested = opts.subscriber && SUBSCRIBER_ID_PATTERN.test(opts.subscriber) ? opts.subscriber : undefined;\n    const existing = requested ? dir.get(requested) : undefined;\n\n    let subscriber: Subscriber;\n    let created: boolean;\n    if (existing?.poll) {\n      subscriber = existing;\n      created = false;\n    } else {\n      const subscriberId = requested && !existing ? requested : randomBytes(8).toString(\"hex\");\n      subscriber = {\n        id: subscriberId,\n        direction,\n        queue: [],\n        resolveNext: null,\n        client: opts.client,\n        poll: { lastSeen: Date.now(), parked: 0, wakers: new Set() },\n      };\n      dir.set(subscriberId, subscriber);\n      created = true;\n      if (direction === \"outbound\") this.announcePeer(id, \"notifications/peer_joined\", subscriberId);\n    }\n\n    const state = subscriber.poll!;\n    state.lastSeen = Date.now();\n\n    return {\n      ok: true,\n      subscriberId: subscriber.id,\n      created,\n      wait: async (ms: number, signal?: AbortSignal): Promise<string[]> => {\n        state.parked++;\n        state.lastSeen = Date.now();\n        try {\n          if (subscriber.queue.length === 0 && ms > 0 && !subscriber.ended && !signal?.aborted) {\n            await new Promise<void>((resolve) => {\n              const done = () => {\n                clearTimeout(timer);\n                signal?.removeEventListener(\"abort\", done);\n                state.wakers.delete(done);\n                resolve();\n              };\n              const timer = setTimeout(done, ms);\n              state.wakers.add(done);\n              signal?.addEventListener(\"abort\", done, { once: true });\n            });\n          }\n          // An aborted poll takes NOTHING: its response will never be read, and\n          // a frame handed to it would be a frame nobody receives.\n          if (signal?.aborted) return [];\n          return subscriber.queue.splice(0);\n        } finally {\n          state.parked--;\n          state.lastSeen = Date.now();\n        }\n      },\n      requeue: (frames: string[]) => {\n        if (frames.length > 0 && !subscriber.ended) subscriber.queue.unshift(...frames);\n      },\n    };\n  }\n\n  // ────────────────────────────────────────────────────────────── internals\n\n  private getDirSubs(sessionId: string, direction: Direction): Map<string, Subscriber> {\n    let bySession = this.subs.get(sessionId);\n    if (!bySession) {\n      bySession = new Map();\n      this.subs.set(sessionId, bySession);\n    }\n    let byDir = bySession.get(direction);\n    if (!byDir) {\n      byDir = new Map();\n      bySession.set(direction, byDir);\n    }\n    return byDir;\n  }\n\n  /**\n   * Record which client asked, keyed by JSON-RPC id.\n   *\n   * Only for REQUESTS — a frame with both an `id` and a `method`. A\n   * notification answers nobody and a response is not a question.\n   */\n  private rememberCaller(sessionId: string, payload: string, client: string): void {\n    const frame = this.parseFrame(payload);\n    if (!frame || frame.id === undefined || frame.id === null || typeof frame.method !== \"string\") {\n      return;\n    }\n\n    let byId = this.callers.get(sessionId);\n    if (!byId) {\n      byId = new Map();\n      this.callers.set(sessionId, byId);\n    }\n\n    // BOUNDED. A session that asks for hours must not grow this without limit,\n    // and an unanswered request would otherwise sit here forever. Oldest out\n    // first; losing the oldest correlation degrades to \"delivered to nobody\",\n    // which fails closed rather than open.\n    if (byId.size >= 1000) {\n      const oldest = byId.keys().next();\n      if (!oldest.done) byId.delete(oldest.value);\n    }\n\n    byId.set(String(frame.id), client);\n  }\n\n  /**\n   * The client a RESPONSE belongs to, or `null` when the frame is a broadcast.\n   *\n   * Returns the empty string for a response whose id nobody is recorded as\n   * having asked — routed to NOBODY rather than to everyone. Broadcasting an\n   * uncorrelated reply \"just in case\" is precisely the leak being closed.\n   */\n  private callerFor(sessionId: string, payload: string): string | null {\n    const frame = this.parseFrame(payload);\n\n    // Not a response: no id, or it carries a method (a request/notification).\n    if (!frame || frame.id === undefined || frame.id === null || typeof frame.method === \"string\") {\n      return null;\n    }\n\n    // LEGACY MODE is decided by whether any subscriber IDENTIFIED ITSELF, not\n    // by whether a correlation happens to have been recorded yet.\n    //\n    // Keying on the correlation map was wrong in a way a test caught: a\n    // labelled client that has subscribed but not yet asked leaves the map\n    // empty, and an unsolicited response would then broadcast to everyone --\n    // the leak reopening in the window before the first call.\n    //\n    // If nobody labelled themselves, every client is legacy and broadcast is\n    // the only thing that can work; narrowing would break them in silence.\n    if (!this.anyIdentifiedSubscriber(sessionId)) {\n      return null;\n    }\n\n    const byId = this.callers.get(sessionId);\n    const key = String(frame.id);\n    const client = byId?.get(key);\n\n    // CONSUMED. Correlation is not a standing subscription: leaving it would\n    // let a replayed frame with the same id be delivered again, and would make\n    // the map a slow leak on a long session.\n    byId?.delete(key);\n\n    return client ?? \"\";\n  }\n\n  /**\n   * Has any subscriber on this session told the broker who it is?\n   *\n   * The discriminator between a scoped session and a legacy one. Checked across\n   * BOTH directions: the page subscribes inbound and rarely labels itself, so\n   * asking only about the outbound side would misread a scoped session whose\n   * agents have not yet attached.\n   */\n  private anyIdentifiedSubscriber(sessionId: string): boolean {\n    const dirs = this.subs.get(sessionId);\n    if (!dirs) return false;\n\n    for (const dir of dirs.values()) {\n      for (const sub of dir.values()) {\n        if (sub.client !== undefined) return true;\n      }\n    }\n\n    return false;\n  }\n\n  private parseFrame(payload: string): { id?: unknown; method?: unknown } | null {\n    try {\n      const parsed: unknown = JSON.parse(payload);\n      return parsed && typeof parsed === \"object\" ? (parsed as { id?: unknown; method?: unknown }) : null;\n    } catch {\n      return null;\n    }\n  }\n\n  /** Deliver to the subscribers of one client only. */\n  private fanOutTo(sessionId: string, direction: Direction, payload: string, client: string) {\n    const dir = this.subs.get(sessionId)?.get(direction);\n    if (!dir) return;\n\n    for (const sub of dir.values()) {\n      if (sub.client !== client) continue;\n      this.deliver(sub, payload);\n    }\n  }\n\n  private fanOut(sessionId: string, direction: Direction, payload: string) {\n    const dir = this.subs.get(sessionId)?.get(direction);\n    if (!dir) return;\n    for (const sub of dir.values()) this.deliver(sub, payload);\n  }\n\n  /**\n   * Hand one frame to one subscriber.\n   *\n   * The resolver is CLEARED before it is called. It used to stay set until the\n   * generator resumed on a later microtask, so a second frame in the same tick\n   * called an already-settled resolver — a no-op — after shifting its frame out\n   * of the queue, and that frame was lost. Cleared first, the second frame just\n   * waits in the queue for the generator to come back for it.\n   */\n  private deliver(sub: Subscriber, payload: string) {\n    if (sub.ended) return;\n    sub.queue.push(payload);\n\n    const resolve = sub.resolveNext;\n    if (resolve) {\n      sub.resolveNext = null;\n      resolve(sub.queue.shift() ?? null);\n      return;\n    }\n\n    if (sub.poll) for (const wake of [...sub.poll.wakers]) wake();\n  }\n\n  /** Tell the page (the inbound side) that an agent arrived or left. */\n  private announcePeer(sessionId: string, method: \"notifications/peer_joined\" | \"notifications/peer_left\", subscriberId: string) {\n    this.fanOut(sessionId, \"inbound\", JSON.stringify({ jsonrpc: \"2.0\", method, params: { subscriberId, ts: Date.now() } }));\n  }\n\n  /** End one subscriber: close its stream, or release its parked polls. Idempotent. */\n  private endSubscriber(sub: Subscriber) {\n    if (sub.ended) return;\n    sub.ended = true;\n\n    const resolve = sub.resolveNext;\n    sub.resolveNext = null;\n    resolve?.(null);\n\n    if (sub.poll) for (const wake of [...sub.poll.wakers]) wake();\n  }\n\n  /**\n   * End every subscriber of a session whose session is going away.\n   *\n   * Streams used to be dropped from the map WITHOUT being woken, so an SSE leg\n   * stayed open, heartbeating, for a session that no longer existed — and its\n   * client could not learn the page had closed. Ended, the stream closes, the\n   * client reconnects, and `events` answers 410.\n   */\n  private endSubscribers(sessionId: string) {\n    const dirs = this.subs.get(sessionId);\n    if (!dirs) return;\n    for (const dir of dirs.values()) for (const sub of dir.values()) this.endSubscriber(sub);\n  }\n\n  /** Remove a subscriber from its session, announcing an agent's departure once. */\n  private removeSubscriber(sessionId: string, sub: Subscriber) {\n    const dir = this.subs.get(sessionId)?.get(sub.direction);\n    // Look it up rather than recreating the maps: a session that has already\n    // been dropped must not grow an empty entry back, nor announce to nobody.\n    if (!dir || dir.get(sub.id) !== sub) return;\n    dir.delete(sub.id);\n    if (sub.direction === \"outbound\") this.announcePeer(sessionId, \"notifications/peer_left\", sub.id);\n  }\n\n  /** Drop long-poll subscribers that stopped polling. Never one with a poll parked. */\n  private prunePollers(now: number) {\n    for (const [sessionId, dirs] of this.subs) {\n      for (const dir of dirs.values()) {\n        for (const sub of [...dir.values()]) {\n          if (!sub.poll || sub.poll.parked > 0) continue;\n          if (now - sub.poll.lastSeen <= this.pollIdleMs) continue;\n          this.endSubscriber(sub);\n          this.removeSubscriber(sessionId, sub);\n        }\n      }\n    }\n  }\n\n  /**\n   * Validate that a peer-supplied payload is a well-formed JSON-RPC 2.0 frame\n   * (or batch) before it is fanned out. Previously this was a substring match on\n   * `\"jsonrpc\"`, which let any token holder inject spoofed frames — a forged\n   * `notifications/peer_joined` / `peer_left` (broker-reserved presence control),\n   * a fake `notifications/agent_activity {source:\"user\"}` (\"human took control\"),\n   * or a forged response with a matching id. We now parse + shape-check, and\n   * reject the broker-reserved control methods (the broker emits those itself,\n   * never a peer).\n   */\n  private isFrame(payload: string): boolean {\n    if (payload.length === 0) return false;\n    let parsed: unknown;\n    try {\n      parsed = JSON.parse(payload);\n    } catch {\n      return false;\n    }\n    const frames = Array.isArray(parsed) ? parsed : [parsed];\n    return frames.length > 0 && frames.every((f) => this.isValidFrame(f));\n  }\n\n  private isValidFrame(f: unknown): boolean {\n    if (!f || typeof f !== \"object\" || Array.isArray(f)) return false;\n    const o = f as Record<string, unknown>;\n    if (o.jsonrpc !== \"2.0\") return false;\n    const method = typeof o.method === \"string\" ? o.method : undefined;\n    // Broker-reserved control frames may never arrive from a peer.\n    if (method === \"notifications/peer_joined\" || method === \"notifications/peer_left\") return false;\n    if (method !== undefined) return true; // request or notification\n    // Response: needs an id and exactly one of result / error.\n    const hasResult = \"result\" in o;\n    const hasError = \"error\" in o;\n    return \"id\" in o && hasResult !== hasError;\n  }\n\n  private reap() {\n    const now = Date.now();\n    const cutoff = now - this.ttlMs;\n    for (const id of this.store.expiredSessionIds(cutoff)) {\n      this.endSubscribers(id);\n      this.subs.delete(id);\n      this.callers.delete(id);\n      this.store.deleteSession(id);\n    }\n    this.prunePollers(now);\n  }\n}\n\nexport type PollResult =\n  | { ok: false; reason: \"invalid_token\" | \"session_gone\" }\n  | {\n      ok: true;\n      /** The id the client must echo back as `subscriber` on its next poll. */\n      subscriberId: string;\n      /** Whether this poll created the subscriber (and, outbound, announced it). */\n      created: boolean;\n      /**\n       * Park up to `ms` for frames, then take everything queued. Returns at once\n       * when frames are already waiting, when `ms` is 0, or when the session\n       * ends. An aborted `signal` returns `[]` and takes nothing.\n       */\n      wait: (ms: number, signal?: AbortSignal) => Promise<string[]>;\n      /** Put frames back at the head of the queue — a response that could not be written. */\n      requeue: (frames: string[]) => void;\n    };\n\nexport type SubscribeResult =\n  | { ok: false; reason: string }\n  | {\n      ok: true;\n      subscriberId: string;\n      frames: AsyncGenerator<string, void, void>;\n      unsubscribe: () => void;\n    };\n\nfunction sha256Hex(input: string): string {\n  return createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\nfunction timingSafeEqualHex(a: string, b: string): boolean {\n  if (a.length !== b.length) return false;\n  return timingSafeEqual(Buffer.from(a, \"hex\"), Buffer.from(b, \"hex\"));\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { URL } from \"node:url\";\nimport { RelayBroker, type RelayBrokerOptions } from \"./core\";\nimport { allowOriginFor, parseCorsOrigins, type CorsPolicy } from \"./cors\";\n\n/**\n * Node HTTP adapter for {@link RelayBroker}. Returns a single request\n * handler plus per-route handlers, so you can either drop it into\n * `http.createServer(...)` directly or mount the individual handlers\n * onto your existing Node HTTP framework (Express, Hono w/ node-adapter,\n * native http).\n *\n *   const relay = createNodeRelay({ pathPrefix: \"/mcp-relay\" });\n *   http.createServer(relay.handler).listen(8787);\n *\n *   // Or piecemeal:\n *   app.post(\"/mcp-relay/register\",       relay.register);\n *   app.post(\"/mcp-relay/:s/inbox\",       relay.inbox);\n *   app.post(\"/mcp-relay/:s/outbox\",      relay.outbox);\n *   app.get (\"/mcp-relay/:s/events\",      relay.events);\n *   app.get (\"/mcp-relay/:s/poll\",        relay.poll);\n *   app.post(\"/mcp-relay/:s/unregister\",  relay.unregister);\n */\n\n/** Longest a single poll may park, in ms — the PHP relay's cap, kept identical. */\nexport const POLL_MAX_WAIT_MS = 25_000;\n\n/** Park window when a poll names none, in ms — fancy-cf-relay's default. */\nexport const POLL_DEFAULT_WAIT_MS = 20_000;\n\n/**\n * The park window a poll asked for, clamped to 0..{@link POLL_MAX_WAIT_MS}.\n *\n * Absent means the default; present but not a number means 0, which is what\n * the PHP relay's integer cast makes of it — a malformed hint returns at once\n * rather than parking for a length nobody chose.\n */\nexport function pollWaitMs(raw: string | null | undefined): number {\n  if (raw === null || raw === undefined) return POLL_DEFAULT_WAIT_MS;\n  const n = Number.parseInt(raw, 10);\n  if (!Number.isFinite(n)) return 0;\n  return Math.min(Math.max(n, 0), POLL_MAX_WAIT_MS);\n}\n\nexport type NodeRelayOptions = RelayBrokerOptions & {\n  /** URL path prefix (without trailing slash). Default `\"\"` — handlers\n   *  expect paths like `/register`, `/{id}/inbox`, etc. directly. */\n  pathPrefix?: string;\n  /**\n   * Browser origins allowed to read relay responses: `*`, or a comma-separated\n   * list of origins (`\"https://example.com,https://www.example.com\"`).\n   * Default `*` — relays are typically called cross-origin from the demo host.\n   *\n   * A list is enforced per request: a listed `Origin` is echoed back as\n   * `Access-Control-Allow-Origin` with `Vary: Origin`, and an unlisted one\n   * gets no allow-origin header at all. `*` mixed into a list, an empty value,\n   * `null` or an entry with a path throws here, at construction.\n   */\n  corsAllowOrigin?: string;\n  /**\n   * The same allow-list as an array. When non-empty it takes precedence over\n   * `corsAllowOrigin`. Recommended for any browser-facing deployment: it blunts\n   * DNS rebinding and hostile cross-origin pages reading relay responses. When\n   * neither names origins, `*` is used and the session token is the only auth\n   * — pair that with a loopback bind.\n   */\n  allowedOrigins?: string[];\n};\n\nexport type NodeHandler = (req: IncomingMessage, res: ServerResponse) => unknown | Promise<unknown>;\n\nexport type NodeRelay = {\n  broker: RelayBroker;\n  /** Single-handler shape — routes internally based on method + URL. */\n  handler: NodeHandler;\n  /** Per-route handlers. Each handler ignores the URL prefix and\n   *  acts on the path remainder, so you can mount them under any\n   *  prefix in your existing app. */\n  register: NodeHandler;\n  inbox: NodeHandler;\n  outbox: NodeHandler;\n  events: NodeHandler;\n  /** Long-poll receive leg — the CDN-safe alternative to `events`. */\n  poll: NodeHandler;\n  unregister: NodeHandler;\n};\n\nexport function createNodeRelay(opts: NodeRelayOptions = {}): NodeRelay {\n  const broker = new RelayBroker(opts);\n  const prefix = (opts.pathPrefix ?? \"\").replace(/\\/$/, \"\");\n  // Parsed once, here, so a bad policy fails at startup rather than in a browser.\n  const cors: CorsPolicy =\n    opts.allowedOrigins && opts.allowedOrigins.length > 0\n      ? parseCorsOrigins(opts.allowedOrigins)\n      : parseCorsOrigins(opts.corsAllowOrigin ?? \"*\");\n\n  function setCorsHeaders(res: ServerResponse, req?: IncomingMessage) {\n    if (cors.kind === \"list\") {\n      // The answer depends on who asked, so say so to every cache in between —\n      // including on a refusal, or a cached refusal could be served to a listed\n      // origin.\n      res.setHeader(\"vary\", \"Origin\");\n    }\n    const origin = req?.headers.origin;\n    const allow = allowOriginFor(cors, typeof origin === \"string\" ? origin : undefined);\n    // No header at all for an unlisted origin. Not `null`: sandboxed iframes and\n    // file:// pages send `Origin: null`, so that value would admit exactly them.\n    if (allow !== null) res.setHeader(\"access-control-allow-origin\", allow);\n    res.setHeader(\"access-control-allow-methods\", \"GET, POST, OPTIONS\");\n    // `authorization` is forward-compat for a header-borne session token.\n    res.setHeader(\"access-control-allow-headers\", \"content-type, x-csrf-token, accept, authorization\");\n    res.setHeader(\"access-control-max-age\", \"86400\");\n  }\n\n  function readBody(req: IncomingMessage): Promise<string> {\n    return new Promise((resolve, reject) => {\n      const chunks: Buffer[] = [];\n      let bytes = 0;\n      req.on(\"data\", (chunk: Buffer) => {\n        bytes += chunk.length;\n        // Cap individual frames at 256 KB — protect against runaway payloads.\n        if (bytes > 256 * 1024) {\n          reject(new Error(\"payload_too_large\"));\n          req.destroy();\n          return;\n        }\n        chunks.push(chunk);\n      });\n      req.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf8\")));\n      req.on(\"error\", reject);\n    });\n  }\n\n  function json(res: ServerResponse, status: number, body: unknown): void {\n    res.statusCode = status;\n    res.setHeader(\"content-type\", \"application/json\");\n    res.end(JSON.stringify(body));\n  }\n\n  function getQuery(req: IncomingMessage): URLSearchParams {\n    const host = req.headers.host || \"x\";\n    const u = new URL(req.url || \"/\", `http://${host}`);\n    return u.searchParams;\n  }\n\n  function getPathname(req: IncomingMessage): string {\n    const host = req.headers.host || \"x\";\n    const u = new URL(req.url || \"/\", `http://${host}`);\n    return u.pathname;\n  }\n\n  const register: NodeHandler = async (req, res) => {\n    setCorsHeaders(res, req);\n    if (req.method === \"OPTIONS\") { res.statusCode = 204; return res.end(); }\n    if (req.method !== \"POST\") return json(res, 405, { error: \"method_not_allowed\" });\n    let body: string;\n    try { body = await readBody(req); } catch (e) {\n      return json(res, 413, { error: e instanceof Error ? e.message : \"payload_error\" });\n    }\n    let parsed: unknown;\n    try { parsed = JSON.parse(body); } catch { return json(res, 400, { error: \"invalid_json\" }); }\n    const { session, token } = (parsed ?? {}) as { session?: string; token?: string };\n    if (typeof session !== \"string\" || typeof token !== \"string\") {\n      return json(res, 400, { error: \"missing_fields\" });\n    }\n    const result = broker.register(session, token);\n    if (!result.ok) return json(res, 401, { error: result.reason });\n    return json(res, 200, { ok: true });\n  };\n\n  /** Handler for endpoints with a `{session}` segment. The path matcher\n   *  caller passes the session id explicitly so this works mounted under\n   *  any route shape. */\n  function makeSessionHandler(\n    direction: Direction | \"unregister\",\n  ): NodeHandler {\n    return async (req, res) => {\n      setCorsHeaders(res, req);\n      if (req.method === \"OPTIONS\") { res.statusCode = 204; return res.end(); }\n      if (req.method !== \"POST\") return json(res, 405, { error: \"method_not_allowed\" });\n      const session = extractSession(req, prefix);\n      if (!session) return json(res, 400, { error: \"missing_session\" });\n      const token = getQuery(req).get(\"token\") ?? \"\";\n\n      if (direction === \"unregister\") {\n        // Unregistering a session that is already gone is a SUCCESS, not an\n        // auth failure. The caller wanted it gone and it is gone; reporting\n        // `invalid_token` for a correct token would make a clean shutdown look\n        // like a broken one, and a client retrying it would loop.\n        const state = broker.check(session, token);\n        if (!state.ok && state.reason === \"session_gone\") {\n          return json(res, 200, { ok: true, alreadyGone: true });\n        }\n\n        const ok = broker.unregister(session, token);\n        return json(res, ok ? 200 : 401, ok ? { ok: true } : { error: \"invalid_token\" });\n      }\n\n      let body: string;\n      try { body = await readBody(req); } catch (e) {\n        return json(res, 413, { error: e instanceof Error ? e.message : \"payload_error\" });\n      }\n      // A GONE SESSION IS REPORTED AS ITSELF, with 410, before the frame is\n      // even considered.\n      //\n      // Every failure here used to come back as `401 invalid_token_or_frame`,\n      // so an agent whose page had simply closed was told its credentials or\n      // its JSON were wrong. A relay session ending is the NORMAL end of a\n      // lifecycle -- the browser is the server and nothing persists -- so it is\n      // the one outcome a server-side client must be able to recognise.\n      //\n      // 410 Gone rather than 404: the session existed and is now over, which is\n      // exactly what the status means, and it distinguishes \"this is finished\"\n      // from \"you have the wrong URL\".\n      const auth = broker.check(session, token);\n      if (!auth.ok && auth.reason === \"session_gone\") {\n        return json(res, 410, { error: \"session_gone\" });\n      }\n\n      // `client` identifies WHICH agent is calling, so its reply can be routed\n      // back to it alone. Optional: a client that sends none gets the legacy\n      // broadcast, which is the only thing that can work for it.\n      const client = getQuery(req).get(\"client\") ?? undefined;\n\n      const ok = direction === \"inbound\"\n        ? broker.inbox(session, token, body, { client })\n        : broker.outbox(session, token, body);\n      return json(res, ok ? 200 : 401, ok ? { ok: true } : { error: \"invalid_token_or_frame\" });\n    };\n  }\n\n  const inbox = makeSessionHandler(\"inbound\");\n  const outbox = makeSessionHandler(\"outbound\");\n  const unregister = makeSessionHandler(\"unregister\");\n\n  const events: NodeHandler = async (req, res) => {\n    setCorsHeaders(res, req);\n    if (req.method === \"OPTIONS\") { res.statusCode = 204; return res.end(); }\n    if (req.method !== \"GET\") return json(res, 405, { error: \"method_not_allowed\" });\n    const session = extractSession(req, prefix);\n    if (!session) return json(res, 400, { error: \"missing_session\" });\n    const q = getQuery(req);\n    const token = q.get(\"token\") ?? \"\";\n    const direction = q.get(\"direction\") === \"outbound\" ? \"outbound\" : \"inbound\";\n\n    // The SAME `client` the agent posts under, so a reply can find its way\n    // back. An agent that subscribes with a label and posts without one (or\n    // vice versa) simply does not correlate and its replies go nowhere -- which\n    // fails closed, and is the right way round for a leak fix.\n    const sub = broker.subscribe(session, token, direction, {\n      client: getQuery(req).get(\"client\") ?? undefined,\n    });\n    if (!sub.ok) {\n      // 410 for a session that has ended, as on every other route; 401 only for\n      // a wrong or missing token. EventSource treats either as final, so a\n      // browser stops reconnecting to a page that is gone.\n      res.statusCode = sub.reason === \"session_gone\" ? 410 : 401;\n      res.setHeader(\"content-type\", \"text/event-stream\");\n      res.write(`event: error\\ndata: ${sub.reason}\\n\\n`);\n      return res.end();\n    }\n\n    res.statusCode = 200;\n    res.setHeader(\"content-type\", \"text/event-stream\");\n    res.setHeader(\"cache-control\", \"no-cache\");\n    res.setHeader(\"connection\", \"keep-alive\");\n    res.setHeader(\"x-accel-buffering\", \"no\");\n    res.write(\"retry: 2000\\n\\n\");\n    flush(res);\n\n    let heartbeat: ReturnType<typeof setInterval> | null = setInterval(() => {\n      res.write(\": keepalive\\n\\n\");\n      flush(res);\n    }, 15_000);\n    if (heartbeat && typeof (heartbeat as { unref?: () => void }).unref === \"function\") {\n      (heartbeat as { unref: () => void }).unref();\n    }\n\n    const cleanup = () => {\n      if (heartbeat) { clearInterval(heartbeat); heartbeat = null; }\n      sub.unsubscribe();\n    };\n    req.on(\"close\", cleanup);\n    req.on(\"error\", cleanup);\n\n    try {\n      for await (const frame of sub.frames) {\n        res.write(`event: mcp\\ndata: ${frame}\\n\\n`);\n        flush(res);\n      }\n    } catch {\n      /* stream ended */\n    } finally {\n      cleanup();\n      res.end();\n    }\n  };\n\n  /**\n   * Long-poll receive leg: `GET /{session}/poll?token&direction&wait&subscriber&client`.\n   *\n   * Answers `200 { subscriber, frames }` once a frame is queued or the park\n   * window (`wait`, ms, clamped to 0..25000) runs out. Short requests survive a\n   * Cloudflare HTTP/3 edge that resets long-lived SSE streams. Parking is ~free\n   * on the Node event loop, unlike PHP-FPM where it holds a worker.\n   */\n  const poll: NodeHandler = async (req, res) => {\n    setCorsHeaders(res, req);\n    if (req.method === \"OPTIONS\") { res.statusCode = 204; return res.end(); }\n    if (req.method !== \"GET\") return json(res, 405, { error: \"method_not_allowed\" });\n    const session = extractSession(req, prefix);\n    if (!session) return json(res, 400, { error: \"missing_session\" });\n    const q = getQuery(req);\n    const direction = q.get(\"direction\") === \"outbound\" ? \"outbound\" : \"inbound\";\n\n    const attached = broker.poll(session, q.get(\"token\") ?? \"\", direction, {\n      subscriber: q.get(\"subscriber\") ?? undefined,\n      client: q.get(\"client\") ?? undefined,\n    });\n    if (!attached.ok) {\n      return json(res, attached.reason === \"session_gone\" ? 410 : 401, { error: attached.reason });\n    }\n\n    // `res` 'close' fires when the client goes away before we answer. `req`\n    // 'close' is not a disconnect signal: on a bodiless GET it can fire as soon\n    // as the request has been read.\n    const gone = new AbortController();\n    const onClose = () => { if (!res.writableEnded) gone.abort(); };\n    res.on(\"close\", onClose);\n\n    const frames = await attached.wait(pollWaitMs(q.get(\"wait\")), gone.signal);\n    res.off(\"close\", onClose);\n\n    if (gone.signal.aborted || res.destroyed) {\n      // Nobody will read this answer. Put back anything taken for it.\n      attached.requeue(frames);\n      return;\n    }\n\n    res.setHeader(\"cache-control\", \"no-store\");\n    return json(res, 200, { subscriber: attached.subscriberId, frames });\n  };\n\n  /**\n   * Single handler — routes based on method + path. Useful for mounting\n   * via `http.createServer(relay.handler)` without an Express layer.\n   */\n  const handler: NodeHandler = async (req, res) => {\n    const pathname = getPathname(req);\n    if (!pathname.startsWith(prefix + \"/\")) {\n      return json(res, 404, { error: \"not_found\" });\n    }\n    const rest = pathname.slice(prefix.length); // \"/register\", \"/<id>/inbox\", etc.\n    if (rest === \"/register\") return register(req, res);\n    const m = /^\\/([A-Za-z0-9_-]{4,64})\\/(inbox|outbox|events|poll|unregister)$/.exec(rest);\n    if (!m) return json(res, 404, { error: \"not_found\" });\n    const route = m[2];\n    if (route === \"inbox\") return inbox(req, res);\n    if (route === \"outbox\") return outbox(req, res);\n    if (route === \"events\") return events(req, res);\n    if (route === \"poll\") return poll(req, res);\n    if (route === \"unregister\") return unregister(req, res);\n    return json(res, 404, { error: \"not_found\" });\n  };\n\n  return { broker, handler, register, inbox, outbox, events, poll, unregister };\n}\n\nfunction extractSession(req: IncomingMessage, prefix: string): string | null {\n  const host = req.headers.host || \"x\";\n  const u = new URL(req.url || \"/\", `http://${host}`);\n  const path = u.pathname;\n  if (prefix && !path.startsWith(prefix + \"/\")) return null;\n  const rest = prefix ? path.slice(prefix.length) : path;\n  const m = /^\\/([A-Za-z0-9_-]{4,64})\\//.exec(rest);\n  return m ? m[1] : null;\n}\n\nfunction flush(res: ServerResponse) {\n  // Node doesn't expose explicit flush, but write returns false when buffered;\n  // explicit flushHeaders + write is enough for SSE in practice.\n  const r = res as { flush?: () => void };\n  r.flush?.();\n}\n\ntype Direction = \"inbound\" | \"outbound\";\n","#!/usr/bin/env node\nimport { createServer } from \"node:http\";\nimport { parseRelayArgs } from \"./args\";\nimport { describeCorsPolicy } from \"./cors\";\nimport { createNodeRelay } from \"./node\";\n\n/**\n * `agent-integrations-relay` — standalone Node HTTP server hosting the relay\n * broker. End users hit `Start share` on a demo page, get a session URL pointing\n * at this service, and paste it into their MCP client. No state persists across\n * restarts.\n *\n * Settings resolve flag → env var → default; see ./args.ts and HELP below.\n *\n * Health: any request to `/` returns 200 OK so platform health checks pass\n * without authenticating.\n */\nasync function main() {\n  const parsed = parseRelayArgs(process.argv.slice(2), process.env);\n  if (!parsed.ok) {\n    process.stderr.write(`[relay] ${parsed.error}\\n`);\n    process.exit(2);\n  }\n\n  const { config } = parsed;\n  if (config.help) {\n    process.stdout.write(HELP);\n    process.exit(0);\n  }\n\n  for (const warning of config.warnings) {\n    process.stderr.write(`[relay] WARNING: ${warning}\\n`);\n  }\n\n  const { port, host, prefix, ttlMs, cors } = config;\n  const relay = createNodeRelay({\n    pathPrefix: prefix,\n    ttlMs,\n    corsAllowOrigin: cors.kind === \"any\" ? \"*\" : cors.origins.join(\",\"),\n  });\n\n  const server = createServer((req, res) => {\n    // Health: GET / always 200 so platform health checks succeed without auth.\n    const url = req.url || \"/\";\n    if ((url === \"/\" || url === \"/healthz\" || url === (prefix + \"/\")) && req.method === \"GET\") {\n      res.statusCode = 200;\n      res.setHeader(\"content-type\", \"application/json\");\n      res.end(JSON.stringify({ ok: true, service: \"agent-integrations-relay\" }));\n      return;\n    }\n    relay.handler(req, res);\n  });\n\n  const isLoopback = host === \"127.0.0.1\" || host === \"::1\" || host === \"localhost\";\n  if (!isLoopback) {\n    process.stderr.write(\n      `[relay] WARNING: binding ${host} exposes the relay on non-loopback interfaces. ` +\n        `register is unauthenticated and a leaked session token grants terminal_run. ` +\n        `Only do this behind an authenticating proxy / trusted network.\\n`,\n    );\n  }\n\n  const corsSource = { flag: \"--cors\", env: \"CORS_ALLOW_ORIGIN\", default: \"default\" }[config.sources.cors];\n  server.listen(port, host, () => {\n    process.stdout.write(\n      `[relay] listening on http://${host}:${port}${prefix || \"\"} ` +\n        `(ttl=${Math.round(ttlMs / 1000)}s, cors=${describeCorsPolicy(cors)} from ${corsSource})\\n`,\n    );\n  });\n\n  const shutdown = () => {\n    process.stdout.write(\"[relay] shutting down\\n\");\n    relay.broker.dispose();\n    server.close(() => process.exit(0));\n    setTimeout(() => process.exit(0), 2000).unref();\n  };\n  process.on(\"SIGTERM\", shutdown);\n  process.on(\"SIGINT\", shutdown);\n}\n\nconst HELP = `agent-integrations-relay — Node HTTP server for the MCP relay broker.\n\nUsage: agent-integrations-relay [options]\n\nOptions:\n  --port <n>          Listen port (env: PORT). Default 8787.\n  --host <addr>       Bind address (env: HOST). Default 127.0.0.1 (loopback).\n                      Pass 0.0.0.0 to expose on all interfaces (prints a warning).\n  --prefix <path>     URL path prefix (env: PREFIX). Default \"\".\n  --ttl-ms <n>        Session TTL ms (env: TTL_MS). Default 14_400_000.\n  --cors <origins>    Allowed browser origins (env: CORS_ALLOW_ORIGIN). Default \"*\".\n                      \"*\", or a comma-separated list such as\n                      \"https://example.com,https://www.example.com\". May be\n                      repeated. A listed Origin is echoed back with Vary: Origin;\n                      an unlisted one gets no Access-Control-Allow-Origin.\n  -h, --help          Show this help.\n\nPrecedence: a flag wins over its env var, which wins over the default. An env\nvar that a flag overrides is reported at startup. An empty env var is unset.\n\nEndpoints (under --prefix):\n  POST  /register                          { session, token } → { ok: true }\n  POST  /<session>/inbox?token=...         body: JSON-RPC frame\n  POST  /<session>/outbox?token=...        body: JSON-RPC frame\n  GET   /<session>/events?token=...&direction=inbound|outbound\n                                           Server-sent events stream\n  GET   /<session>/poll?token=...&direction=inbound|outbound&wait=<ms>&subscriber=<id>\n                                           Long-poll → { subscriber, frames }\n  POST  /<session>/unregister?token=...    Tear down session\n  GET   /                                  Healthcheck → 200\n\nA session that has ended answers 410 {\"error\":\"session_gone\"} on every session\nroute; a wrong or missing token answers 401.\n`;\n\nmain().catch((e) => {\n  process.stderr.write(`[relay] fatal: ${e instanceof Error ? e.stack ?? e.message : String(e)}\\n`);\n  process.exit(1);\n});\n"]}