onelobby 0.4.1 → 0.6.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.
Files changed (99) hide show
  1. package/README.md +2 -2
  2. package/blueprint.schema.json +244 -0
  3. package/dist/blueprint.d.ts +170 -0
  4. package/dist/blueprint.js +286 -0
  5. package/dist/blueprint.js.map +1 -0
  6. package/dist/codec.d.ts +23 -0
  7. package/dist/codec.js +28 -0
  8. package/dist/codec.js.map +1 -1
  9. package/dist/direct/browser-host.d.ts +46 -0
  10. package/dist/direct/browser-host.js +93 -0
  11. package/dist/direct/browser-host.js.map +1 -0
  12. package/dist/direct/hub-host.d.ts +34 -23
  13. package/dist/direct/hub-host.js +75 -59
  14. package/dist/direct/hub-host.js.map +1 -1
  15. package/dist/direct/hub-local.d.ts +22 -0
  16. package/dist/direct/hub-local.js +46 -0
  17. package/dist/direct/hub-local.js.map +1 -0
  18. package/dist/direct/hub.d.ts +37 -10
  19. package/dist/direct/hub.js +114 -23
  20. package/dist/direct/hub.js.map +1 -1
  21. package/dist/direct/index.d.ts +37 -4
  22. package/dist/direct/index.js +162 -21
  23. package/dist/direct/index.js.map +1 -1
  24. package/dist/direct/metrics.d.ts +12 -0
  25. package/dist/direct/metrics.js +45 -0
  26. package/dist/direct/metrics.js.map +1 -0
  27. package/dist/direct/portmap.d.ts +9 -2
  28. package/dist/direct/portmap.js +7 -2
  29. package/dist/direct/portmap.js.map +1 -1
  30. package/dist/direct/sha1.d.ts +16 -0
  31. package/dist/direct/sha1.js +111 -0
  32. package/dist/direct/sha1.js.map +1 -0
  33. package/dist/direct-address.d.ts +2 -2
  34. package/dist/direct-address.js.map +1 -1
  35. package/dist/friendly.d.ts +28 -0
  36. package/dist/friendly.js +40 -0
  37. package/dist/friendly.js.map +1 -1
  38. package/dist/index.d.ts +11 -3
  39. package/dist/index.js +8 -2
  40. package/dist/index.js.map +1 -1
  41. package/dist/internals.d.ts +9 -0
  42. package/dist/internals.js +9 -0
  43. package/dist/internals.js.map +1 -1
  44. package/dist/join-code-kind.d.ts +10 -0
  45. package/dist/join-code-kind.js +10 -0
  46. package/dist/join-code-kind.js.map +1 -0
  47. package/dist/joincode.d.ts +10 -1
  48. package/dist/joincode.js +23 -3
  49. package/dist/joincode.js.map +1 -1
  50. package/dist/lobby.d.ts +65 -4
  51. package/dist/lobby.js +151 -12
  52. package/dist/lobby.js.map +1 -1
  53. package/dist/lockstep.d.ts +8 -0
  54. package/dist/lockstep.js +23 -2
  55. package/dist/lockstep.js.map +1 -1
  56. package/dist/nostr/crypto.d.ts +20 -0
  57. package/dist/nostr/crypto.js +78 -0
  58. package/dist/nostr/crypto.js.map +1 -0
  59. package/dist/nostr/host.d.ts +66 -0
  60. package/dist/nostr/host.js +196 -0
  61. package/dist/nostr/host.js.map +1 -0
  62. package/dist/nostr/limits.d.ts +31 -0
  63. package/dist/nostr/limits.js +36 -0
  64. package/dist/nostr/limits.js.map +1 -0
  65. package/dist/nostr/link.d.ts +70 -0
  66. package/dist/nostr/link.js +180 -0
  67. package/dist/nostr/link.js.map +1 -0
  68. package/dist/nostr/relays.d.ts +79 -0
  69. package/dist/nostr/relays.js +315 -0
  70. package/dist/nostr/relays.js.map +1 -0
  71. package/dist/nostr/room.d.ts +43 -0
  72. package/dist/nostr/room.js +104 -0
  73. package/dist/nostr/room.js.map +1 -0
  74. package/dist/nostr/secp256k1.d.ts +10 -0
  75. package/dist/nostr/secp256k1.js +171 -0
  76. package/dist/nostr/secp256k1.js.map +1 -0
  77. package/dist/nostr/socket.d.ts +48 -0
  78. package/dist/nostr/socket.js +141 -0
  79. package/dist/nostr/socket.js.map +1 -0
  80. package/dist/onelobby.bundle.js +146 -0
  81. package/dist/onelobby.bundle.js.map +7 -0
  82. package/dist/onelobby.bundle.mjs +11 -5
  83. package/dist/onelobby.bundle.mjs.map +4 -4
  84. package/dist/onelobby.d.ts +54 -4
  85. package/dist/onelobby.global.js +2932 -49
  86. package/dist/onelobby.global.js.map +4 -4
  87. package/dist/onelobby.global.min.js +11 -5
  88. package/dist/onelobby.global.min.js.map +4 -4
  89. package/dist/onelobby.js +158 -15
  90. package/dist/onelobby.js.map +1 -1
  91. package/dist/pause.d.ts +85 -0
  92. package/dist/pause.js +160 -0
  93. package/dist/pause.js.map +1 -0
  94. package/dist/transport.d.ts +3 -1
  95. package/dist/transport.js.map +1 -1
  96. package/dist/webrtc.d.ts +1 -0
  97. package/dist/webrtc.js +6 -1
  98. package/dist/webrtc.js.map +1 -1
  99. package/package.json +4 -2
@@ -1 +1 @@
1
- {"version":3,"file":"hub-host.js","sourceRoot":"","sources":["../../src/direct/hub-host.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference types=\"node\" />\nimport { createHash } from \"node:crypto\";\nimport { createSocket } from \"node:dgram\";\nimport { createServer, type Server, type Socket } from \"node:net\";\nimport type { SocketLike } from \"../transport.js\";\nimport { SignalingHub, directHubOptions, type HubDeps, type HubOptions, type Session } from \"./hub.js\";\nimport { PortMapper, type PortMapperOptions, type PortMapResult } from \"./portmap.js\";\n\nconst WS_GUID = \"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\";\nconst MAX_HEADER_BYTES = 8192;\nconst HANDSHAKE_TIMEOUT_MS = 5000;\nconst STATUS_TEXT: Record<number, string> = { 200: \"OK\", 301: \"Moved Permanently\", 302: \"Found\", 404: \"Not Found\", 500: \"Internal Server Error\" };\n\n/**\n * Whether a WebSocket handshake carrying `origin` is accepted. A web page can open a WebSocket to any address it can\n * reach, so a browser's Origin must be one we expect: in `allowed` (\"*\" = all), the same host:port as the request's\n * Host header (the page this host serves itself), or loopback (localhost, 127.0.0.1, [::1], any port). A request with\n * no Origin header is a native client and never gets here.\n */\nexport function originAllowed(origin: string, host: string | undefined, allowed: readonly string[]): boolean {\n if (allowed.includes(\"*\") || allowed.includes(origin)) return true;\n let u: URL;\n try {\n u = new URL(origin);\n } catch {\n return false;\n }\n if (u.protocol !== \"http:\" && u.protocol !== \"https:\") return false;\n if (u.hostname === \"localhost\" || u.hostname === \"127.0.0.1\" || u.hostname === \"[::1]\") return true;\n return host !== undefined && u.host.toLowerCase() === host.trim().toLowerCase();\n}\n\n/**\n * Rejects (EADDRINUSE) when another program holds IPv4 TCP or UDP `port`. Windows lets the dual-stack listener bind\n * over a program on 0.0.0.0 (every IPv4 joiner would then reach that program), and the peer links need UDP `port`\n * too, so both are tried and released before the real listen.\n */\nasync function probeIPv4(port: number): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const s = createServer();\n s.once(\"error\", reject);\n s.listen({ port, host: \"0.0.0.0\", exclusive: true }, () => s.close(() => resolve()));\n });\n await new Promise<void>((resolve, reject) => {\n const u = createSocket({ type: \"udp4\" });\n u.once(\"error\", (e) => {\n u.close();\n reject(e);\n });\n u.bind({ port, address: \"0.0.0.0\", exclusive: true }, () => u.close(() => resolve()));\n });\n}\n\nexport class PortInUseError extends Error {\n readonly code = \"port_in_use\";\n /** Windows reserved the port (EACCES: an excluded port range, often from Hyper-V, WSL or Docker); not another program. */\n readonly reserved: boolean;\n constructor(port: number, detail: string) {\n const reserved = detail === \"EACCES\";\n super(`port_in_use: cannot listen on port ${port} (${detail}): ${portFailureHint(!reserved, reserved)}`);\n this.reserved = reserved;\n }\n}\n\n/** The end of a `port_in_use` message: busy (another program) and reserved (Windows) need different fixes. */\nexport function portFailureHint(anyBusy: boolean, anyReserved: boolean): string {\n if (!anyReserved) return \"is another copy of the game hosting?\";\n if (!anyBusy) return \"Windows has reserved it (an excluded port range, often from Hyper-V, WSL or Docker); pick another port\";\n return \"each one is busy or reserved by Windows (an excluded port range); is another copy of the game hosting?\";\n}\n\n/**\n * Runs a {@link SignalingHub} inside a Node process and listens for joiners' signaling WebSockets on TCP `port`: the\n * Node twin of C#'s `DirectHubHost` (docs/direct-ip.md s.2, s.5 step 3). A plain `net` server with a minimal HTTP/1.1\n * upgrade and RFC 6455 framing (text, close, ping/pong, fragments; client frames must be masked), so the package keeps\n * zero runtime dependencies. Any path upgrades; `GET /healthz` answers `ok`. The host's own client talks to the hub in\n * memory through {@link connectLocal}. `hub.tick()` runs once a second on an unref'd timer.\n */\n/** One plain-HTTP answer from the host's port, e.g. a browser join page. */\nexport interface HttpReply {\n /** Default 200. */\n status?: number;\n /** Content-Type, e.g. \"text/html; charset=utf-8\". */\n type: string;\n body: string | Uint8Array;\n}\n\n/** Serves plain `GET` requests on the direct port (path without the query); null answers 404. */\nexport type HttpHandler = (path: string) => HttpReply | null;\n\nexport class DirectHubHost {\n readonly hub: SignalingHub;\n /**\n * Plain `GET`s that are not WebSocket upgrades go here, so the host can serve its own join page: a browser opening\n * `http://<host address>:<port>/` gets a page that joins with `kit.joinDirect(location.host)`. Null (default): 426.\n */\n http: HttpHandler | null = null;\n /**\n * Browser `Origin` values allowed to open a signaling socket, exact match, \"*\" for all. No Origin header (native\n * clients), the host's own page (Origin equal to the request's Host) and localhost pages are always allowed.\n */\n allowedOrigins: string[] = [];\n /** The bound TCP port (the requested one, or the one the OS picked for 0). */\n readonly port: number;\n portMapper: PortMapper | null = null;\n private readonly server: Server;\n private readonly sockets = new Set<Socket>();\n private readonly ticker: ReturnType<typeof setInterval>;\n private readonly maxMessageBytes: number;\n private closed = false;\n\n private constructor(server: Server, port: number, hub: SignalingHub, maxMessageBytes: number) {\n this.server = server;\n this.port = port;\n this.hub = hub;\n this.maxMessageBytes = maxMessageBytes;\n this.ticker = setInterval(() => this.hub.tick(), 1000);\n this.ticker.unref?.();\n server.on(\"connection\", (sock) => this.accept(sock));\n }\n\n /**\n * Binds TCP `port` on every interface (IPv6 dual-stack where available). Hub options default to\n * {@link directHubOptions} (one lobby, no codes, no ICE servers). Rejects with {@link PortInUseError}.\n */\n static async listen(port: number, options?: Partial<HubOptions>, deps?: HubDeps & { host?: string }): Promise<DirectHubHost> {\n const opts = { ...directHubOptions(8), ...options };\n const server = createServer({ noDelay: true });\n const tryListen = (host: string, ipv6Only?: boolean) =>\n new Promise<void>((resolve, reject) => {\n const onError = (e: NodeJS.ErrnoException) => reject(e);\n server.once(\"error\", onError);\n server.listen({ port, host, ipv6Only }, () => {\n server.off(\"error\", onError);\n resolve();\n });\n });\n try {\n if (deps?.host) await tryListen(deps.host);\n else {\n if (port !== 0) await probeIPv4(port);\n try {\n await tryListen(\"::\", false);\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"EADDRINUSE\") throw e;\n await tryListen(\"0.0.0.0\"); // no IPv6 on this machine\n }\n }\n } catch (e) {\n throw new PortInUseError(port, (e as NodeJS.ErrnoException).code ?? String(e));\n }\n const addr = server.address();\n const bound = typeof addr === \"object\" && addr ? addr.port : port;\n return new DirectHubHost(server, bound, new SignalingHub(opts, deps), opts.maxMessageBytes);\n }\n\n /** Joiner sockets currently open. */\n get connectionCount(): number {\n return this.sockets.size;\n }\n\n /**\n * The host's own signaling socket: a WebSocket look-alike wired straight into the hub (no network). Pass it to the\n * kit as `advanced.socketFactory: () => host.connectLocal()`.\n */\n connectLocal(): SocketLike {\n return new LocalHubSocket(this.hub);\n }\n\n /** Asks the home router to forward TCP and UDP `port` here (UPnP, then NAT-PMP; docs/direct-ip.md s.2a). */\n openPort(options?: PortMapperOptions): Promise<PortMapResult> {\n if (this.portMapper) throw new Error(\"the port is already being opened\");\n this.portMapper = new PortMapper(this.port, options);\n return this.portMapper.open();\n }\n\n /** Stops listening, closes every joiner socket and removes the router mapping. Every call gets the same promise. */\n close(): Promise<void> {\n return (this.closing ??= this.closeOnce());\n }\n\n private closing?: Promise<void>;\n\n private async closeOnce(): Promise<void> {\n this.closed = true;\n clearInterval(this.ticker);\n const unmap = this.portMapper?.close();\n for (const s of this.sockets) s.end(closeFrame(1001, \"host left\"));\n await new Promise<void>((resolve) => this.server.close(() => resolve()));\n setTimeout(() => { for (const s of this.sockets) s.destroy(); }, 300).unref?.();\n await unmap;\n }\n\n // ---------------------------------------------------------------- one TCP connection\n\n private accept(sock: Socket): void {\n if (this.closed) {\n sock.destroy();\n return;\n }\n this.sockets.add(sock);\n sock.on(\"close\", () => this.sockets.delete(sock));\n sock.on(\"error\", () => {});\n const ip = (sock.remoteAddress ?? \"\").replace(/^::ffff:/, \"\");\n let head = Buffer.alloc(0);\n const timer = setTimeout(() => sock.destroy(), HANDSHAKE_TIMEOUT_MS);\n const onData = (chunk: Buffer) => {\n head = Buffer.concat([head, chunk]);\n const end = head.indexOf(\"\\r\\n\\r\\n\");\n if (end < 0) {\n if (head.length > MAX_HEADER_BYTES) sock.destroy();\n return;\n }\n clearTimeout(timer);\n sock.off(\"data\", onData);\n const rest = head.subarray(end + 4);\n if (!this.handshake(sock, head.subarray(0, end).toString(\"latin1\"))) return;\n this.run(sock, ip, rest);\n };\n sock.on(\"data\", onData);\n }\n\n /** RFC 6455 s.4.2: answers 101 with Sec-WebSocket-Accept, or 200 for /healthz, or 400/426. */\n private handshake(sock: Socket, head: string): boolean {\n const [requestLine, ...lines] = head.split(\"\\r\\n\");\n const headers = new Map<string, string>();\n for (const l of lines) {\n const i = l.indexOf(\":\");\n if (i > 0) headers.set(l.slice(0, i).trim().toLowerCase(), l.slice(i + 1).trim());\n }\n const [method, path] = requestLine.split(\" \");\n const reply = (status: string, body: string) =>\n sock.end(`HTTP/1.1 ${status}\\r\\nContent-Type: text/plain\\r\\nContent-Length: ${Buffer.byteLength(body)}\\r\\nConnection: close\\r\\n\\r\\n${body}`);\n if (method === \"GET\" && path === \"/healthz\") {\n reply(\"200 OK\", \"ok\");\n return false;\n }\n const key = headers.get(\"sec-websocket-key\");\n const upgrade = /websocket/i.test(headers.get(\"upgrade\") ?? \"\");\n if (method === \"GET\" && !upgrade && this.http && path) {\n let page: HttpReply | null = null;\n try {\n page = this.http(path.split(\"?\")[0]);\n } catch {\n page = { status: 500, type: \"text/plain\", body: \"error\" };\n }\n const p = page ?? { status: 404, type: \"text/plain\", body: \"not found\" };\n const body = typeof p.body === \"string\" ? Buffer.from(p.body, \"utf8\") : Buffer.from(p.body);\n const status = p.status ?? 200;\n sock.write(`HTTP/1.1 ${status} ${STATUS_TEXT[status] ?? \"OK\"}\\r\\nContent-Type: ${p.type}\\r\\n` +\n `Content-Length: ${body.length}\\r\\nCache-Control: no-store\\r\\nX-Content-Type-Options: nosniff\\r\\nConnection: close\\r\\n\\r\\n`);\n sock.end(body);\n return false;\n }\n if (method !== \"GET\" || !upgrade || !key) {\n reply(\"426 Upgrade Required\", \"this port speaks WebSocket (OneLobby direct host)\");\n return false;\n }\n const origin = headers.get(\"origin\");\n if (origin !== undefined && !originAllowed(origin, headers.get(\"host\"), this.allowedOrigins)) {\n reply(\"403 Forbidden\", \"this origin may not join (OneLobby direct host)\");\n return false;\n }\n const accept = createHash(\"sha1\").update(key + WS_GUID).digest(\"base64\");\n sock.write(`HTTP/1.1 101 Switching Protocols\\r\\nUpgrade: websocket\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: ${accept}\\r\\n\\r\\n`);\n return true;\n }\n\n private run(sock: Socket, ip: string, initial: Buffer): void {\n let open = true;\n const sendText = (text: string) => {\n if (open && !sock.destroyed) sock.write(frame(0x1, Buffer.from(text, \"utf8\")));\n };\n const shut = (code: number, reason: string) => {\n if (!open) return;\n open = false;\n if (!sock.destroyed) sock.end(closeFrame(code, reason));\n };\n let session: Session | null = null;\n session = this.hub.connect(ip, sendText, () => shut(1000, \"closed by the hub\"));\n if (!session) return;\n const s = session;\n const reader = new FrameReader(this.maxMessageBytes + 1024, {\n text: (t) => this.hub.receive(s, t),\n ping: (p) => !sock.destroyed && sock.write(frame(0xa, p)),\n close: () => {\n shut(1000, \"\");\n this.hub.disconnect(s);\n },\n fail: (code, why) => {\n shut(code, why);\n this.hub.disconnect(s);\n },\n });\n sock.on(\"data\", (b: Buffer) => reader.push(b));\n sock.on(\"close\", () => {\n open = false;\n this.hub.disconnect(s);\n });\n if (initial.length) reader.push(initial);\n }\n}\n\n// ------------------------------------------------------------------------------------------------ RFC 6455 framing\n\n/** One unmasked server frame (FIN set). */\nfunction frame(opcode: number, payload: Buffer): Buffer {\n const n = payload.length;\n const head = n < 126 ? Buffer.from([0x80 | opcode, n]) : n < 65536 ? Buffer.alloc(4) : Buffer.alloc(10);\n if (n >= 126) {\n head[0] = 0x80 | opcode;\n if (n < 65536) {\n head[1] = 126;\n head.writeUInt16BE(n, 2);\n } else {\n head[1] = 127;\n head.writeBigUInt64BE(BigInt(n), 2);\n }\n }\n return Buffer.concat([head, payload]);\n}\n\nfunction closeFrame(code: number, reason: string): Buffer {\n const r = Buffer.from(reason.slice(0, 100), \"utf8\");\n const p = Buffer.alloc(2 + r.length);\n p.writeUInt16BE(code, 0);\n r.copy(p, 2);\n return frame(0x8, p);\n}\n\ninterface FrameSink {\n text(t: string): void;\n ping(payload: Buffer): void;\n close(): void;\n fail(code: number, why: string): void;\n}\n\n/** Incremental client-frame parser: masked frames only, text messages (fragmented or not), control frames between. */\nclass FrameReader {\n private buf: Buffer = Buffer.alloc(0);\n private parts: Buffer[] = [];\n private partBytes = 0;\n private inMessage = false;\n private binary = false;\n private done = false;\n private readonly utf8 = new TextDecoder(\"utf-8\", { fatal: true });\n\n constructor(private readonly maxMessage: number, private readonly sink: FrameSink) {}\n\n push(chunk: Buffer): void {\n if (this.done) return;\n this.buf = this.buf.length ? Buffer.concat([this.buf, chunk]) : chunk;\n while (!this.done) {\n if (this.buf.length < 2) return;\n const b0 = this.buf[0];\n const b1 = this.buf[1];\n const fin = (b0 & 0x80) !== 0;\n const opcode = b0 & 0x0f;\n if (b0 & 0x70) return this.fail(1002, \"reserved bits set\");\n if (!(b1 & 0x80)) return this.fail(1002, \"client frames must be masked\");\n let len = b1 & 0x7f;\n let off = 2;\n if (len === 126) {\n if (this.buf.length < 4) return;\n len = this.buf.readUInt16BE(2);\n off = 4;\n } else if (len === 127) {\n if (this.buf.length < 10) return;\n const big = this.buf.readBigUInt64BE(2);\n if (big > BigInt(this.maxMessage)) return this.fail(1009, \"message too big\");\n len = Number(big);\n off = 10;\n }\n if (len > this.maxMessage) return this.fail(1009, \"message too big\");\n if (this.buf.length < off + 4 + len) return;\n const mask = this.buf.subarray(off, off + 4);\n const payload = Buffer.from(this.buf.subarray(off + 4, off + 4 + len));\n for (let i = 0; i < payload.length; i++) payload[i] ^= mask[i & 3];\n this.buf = this.buf.subarray(off + 4 + len);\n if (opcode >= 0x8) {\n if (!fin || len > 125) return this.fail(1002, \"bad control frame\");\n if (opcode === 0x8) {\n this.done = true;\n this.sink.close();\n return;\n }\n if (opcode === 0x9) this.sink.ping(payload);\n continue; // pong or unknown control: ignore\n }\n if (opcode === 0x1 || opcode === 0x2) {\n if (this.inMessage) return this.fail(1002, \"new message inside a fragmented one\");\n this.inMessage = true;\n this.binary = opcode === 0x2; // spec/signaling.md: binary frames are ignored\n } else if (opcode !== 0x0 || !this.inMessage) return this.fail(1002, \"unexpected continuation\");\n this.partBytes += payload.length;\n if (this.partBytes > this.maxMessage) return this.fail(1009, \"message too big\");\n if (!this.binary) this.parts.push(payload);\n if (fin) {\n const all = this.parts.length === 1 ? this.parts[0] : Buffer.concat(this.parts);\n const skip = this.binary;\n this.parts = [];\n this.partBytes = 0;\n this.inMessage = false;\n this.binary = false;\n if (skip) continue;\n let text: string;\n try {\n text = this.utf8.decode(all);\n } catch {\n return this.fail(1007, \"invalid UTF-8\");\n }\n this.sink.text(text);\n }\n }\n }\n\n private fail(code: number, why: string): void {\n this.done = true;\n this.sink.fail(code, why);\n }\n}\n\n// ------------------------------------------------------------------------------------------------ in-memory socket\n\n/**\n * The direct-IP host's own signaling socket (C#'s `HubSignalingSocket`): sends go straight into the hub; the hub's\n * replies are delivered on a microtask, so callbacks never run inside the hub.\n */\nexport class LocalHubSocket implements SocketLike {\n /** Address the hub sees for the host itself (rate limits and kicks are per address). */\n static readonly ADDRESS = \"local\";\n readyState = 0;\n onopen: SocketLike[\"onopen\"] = null;\n onmessage: SocketLike[\"onmessage\"] = null;\n onclose: SocketLike[\"onclose\"] = null;\n onerror: SocketLike[\"onerror\"] = null;\n private session: Session | null;\n\n constructor(private readonly hub: SignalingHub) {\n this.session = hub.connect(LocalHubSocket.ADDRESS, (text) => queueMicrotask(() => this.readyState === 1 && this.onmessage?.({ data: text })), () =>\n this.finish(),\n );\n queueMicrotask(() => {\n if (!this.session) {\n this.finish();\n return;\n }\n this.readyState = 1;\n this.onopen?.();\n });\n }\n\n send(data: string): void {\n if (this.readyState === 1 && this.session) this.hub.receive(this.session, data);\n }\n\n close(): void {\n const s = this.session;\n const wasOpen = this.readyState === 1;\n this.finish();\n if (wasOpen && s) this.hub.disconnect(s);\n }\n\n private finish(): void {\n if (this.readyState === 3) return;\n this.readyState = 3;\n queueMicrotask(() => this.onclose?.());\n }\n}\n"]}
1
+ {"version":3,"file":"hub-host.js","sourceRoot":"","sources":["../../src/direct/hub-host.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference types=\"node\" />\nimport { createHash } from \"node:crypto\";\nimport { createSocket } from \"node:dgram\";\nimport { createServer, type Server, type Socket } from \"node:net\";\nimport type { SocketLike } from \"../transport.js\";\nimport type { IpCodeKind, JoinCodeKind } from \"../join-code-kind.js\";\nimport { SignalingHub, directHubOptions, type HubDeps, type HubOptions, type Session } from \"./hub.js\";\nimport { LocalHubSocket } from \"./hub-local.js\";\nimport { PortMapper,type PortMapperOptions, type PortMapResult } from \"./portmap.js\";\nimport type { NostrHostBridge } from \"../nostr/host.js\";\n\nconst WS_GUID = \"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\";\nconst MAX_HEADER_BYTES = 8192;\nconst HANDSHAKE_TIMEOUT_MS = 5000;\n/** A joiner socket with more than this much unsent data is closed (1008 \"backpressure\"); spec/signaling.md. */\nexport const MAX_PENDING_WRITE_BYTES = 1024 * 1024;\nconst BACKPRESSURE_GRACE_MS = 3000;\nconst STATUS_TEXT: Record<number, string> = { 200: \"OK\", 301: \"Moved Permanently\", 302: \"Found\", 404: \"Not Found\", 500: \"Internal Server Error\" };\n\n/**\n * Whether a WebSocket handshake carrying `origin` is accepted. A web page can open a WebSocket to any address it can\n * reach, so a browser's Origin must be one we expect: in `allowed` (\"*\" = all), the same host:port as the request's\n * Host header (the page this host serves itself), or loopback (localhost, 127.0.0.1, [::1], any port). A request with\n * no Origin header is a native client and never gets here.\n */\nexport function originAllowed(origin: string, host: string | undefined, allowed: readonly string[]): boolean {\n if (allowed.includes(\"*\") || allowed.includes(origin)) return true;\n let u: URL;\n try {\n u = new URL(origin);\n } catch {\n return false;\n }\n if (u.protocol !== \"http:\" && u.protocol !== \"https:\") return false;\n if (u.hostname === \"localhost\" || u.hostname === \"127.0.0.1\" || u.hostname === \"[::1]\") return true;\n return host !== undefined && u.host.toLowerCase() === host.trim().toLowerCase();\n}\n\n/** Whether `ip` (as the socket reports it) is 127.0.0.0/8, ::1 or an IPv4-mapped loopback address. */\nexport function isLoopback(ip: string): boolean {\n const a = ip.replace(/^::ffff:/i, \"\");\n return /^127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(a) || a === \"::1\";\n}\n\n/**\n * Rejects (EADDRINUSE) when another program holds IPv4 TCP or UDP `port`. Windows lets the dual-stack listener bind\n * over a program on 0.0.0.0 (every IPv4 joiner would then reach that program), and the peer links need UDP `port`\n * too, so both are tried and released before the real listen.\n */\nasync function probeIPv4(port: number): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const s = createServer();\n s.once(\"error\", reject);\n s.listen({ port, host: \"0.0.0.0\", exclusive: true }, () => s.close(() => resolve()));\n });\n await new Promise<void>((resolve, reject) => {\n const u = createSocket({ type: \"udp4\" });\n u.once(\"error\", (e) => {\n u.close();\n reject(e);\n });\n u.bind({ port, address: \"0.0.0.0\", exclusive: true }, () => u.close(() => resolve()));\n });\n}\n\nexport class PortInUseError extends Error {\n readonly code = \"port_in_use\";\n /** Windows reserved the port (EACCES: an excluded port range, often from Hyper-V, WSL or Docker); not another program. */\n readonly reserved: boolean;\n constructor(port: number, detail: string) {\n const reserved = detail === \"EACCES\";\n super(`port_in_use: cannot listen on port ${port} (${detail}): ${portFailureHint(!reserved, reserved)}`);\n this.reserved = reserved;\n }\n}\n\n/** The end of a `port_in_use` message: busy (another program) and reserved (Windows) need different fixes. */\nexport function portFailureHint(anyBusy: boolean, anyReserved: boolean): string {\n if (!anyReserved) return \"is another copy of the game hosting?\";\n if (!anyBusy) return \"Windows has reserved it (an excluded port range, often from Hyper-V, WSL or Docker); pick another port\";\n return \"each one is busy or reserved by Windows (an excluded port range); is another copy of the game hosting?\";\n}\n\n/**\n * Runs a {@link SignalingHub} inside a Node process and listens for joiners' signaling WebSockets on TCP `port`: the\n * Node twin of C#'s `DirectHubHost` (docs/design/direct-ip.md s.2, s.5 step 3). A plain `net` server with a minimal HTTP/1.1\n * upgrade and RFC 6455 framing (text, close, ping/pong, fragments; client frames must be masked), so the package keeps\n * zero runtime dependencies. Any path upgrades; `GET /healthz` answers `ok` and `GET /metrics` the hub's Prometheus text\n * (loopback callers only), as onelobby-server does, ahead of the `http` callback. The host's own client talks to the hub in\n * memory through {@link connectLocal}. `hub.tick()` runs once a second on an unref'd timer.\n */\n/** One plain-HTTP answer from the host's port, e.g. a browser join page. */\nexport interface HttpReply {\n /** Default 200. */\n status?: number;\n /** Content-Type, e.g. \"text/html; charset=utf-8\". */\n type: string;\n body: string | Uint8Array;\n /**\n * Extra response headers, e.g. `{ \"Cache-Control\": \"max-age=3600\" }` for a static asset (default `no-store`). The\n * hub owns Content-Type, Content-Length and Connection; a name or value with a line break answers 500.\n */\n headers?: Record<string, string>;\n}\n\n/** `GET /joininfo` on a direct host: what a page served from the host shows as its share link (`directJoinInfo()`). */\nexport interface DirectJoinInfo {\n /** What to hand out: the Nostr code (version 1) by default, else the IP code. */\n joinCode: string;\n joinCodeKind: JoinCodeKind;\n /** The IP code (address and port); equals `joinCode` when Nostr is off. */\n directCode: string;\n directCodeKind: IpCodeKind;\n /** With `http`: `http://<the code's address>:<port>/`; else null. */\n joinUrl: string | null;\n port: number;\n}\n\nconst HUB_OWNED_HEADERS = new Set([\"content-type\", \"content-length\", \"connection\", \"transfer-encoding\"]);\n\nfunction replyHeaders(extra: Record<string, string> | undefined): string {\n const h = new Map<string, [string, string]>([\n [\"cache-control\", [\"Cache-Control\", \"no-store\"]],\n [\"x-content-type-options\", [\"X-Content-Type-Options\", \"nosniff\"]],\n ]);\n for (const [k, v] of Object.entries(extra ?? {})) {\n if (/[\\r\\n:]/.test(k) || /[\\r\\n]/.test(String(v)) || !k) throw new Error(\"bad header\");\n if (!HUB_OWNED_HEADERS.has(k.toLowerCase())) h.set(k.toLowerCase(), [k, String(v)]);\n }\n return [...h.values()].map(([k, v]) => `${k}: ${v}\\r\\n`).join(\"\");\n}\n\n/** Serves plain `GET` requests on the direct port (path without the query); null answers 404. */\nexport type HttpHandler = (path: string) => HttpReply | null;\n\nexport class DirectHubHost {\n readonly hub: SignalingHub;\n /**\n * Plain `GET`s that are not WebSocket upgrades go here, so the host can serve its own join page: a browser opening\n * `http://<host address>:<port>/` gets a page that joins with `kit.joinDirect(location.host)`. Null (default): 426.\n */\n http: HttpHandler | null = null;\n /**\n * Browser `Origin` values allowed to open a signaling socket, exact match, \"*\" for all. No Origin header (native\n * clients), the host's own page (Origin equal to the request's Host) and localhost pages are always allowed.\n */\n allowedOrigins: string[] = [];\n /** Served as JSON at `GET /joininfo` (404 while null); `hostDirect` keeps it current as the join code changes. */\n joinInfo: DirectJoinInfo | null = null;\n /** The bound TCP port (the requested one, or the one the OS picked for 0). */\n readonly port: number;\n portMapper: PortMapper | null = null;\n /** Nostr signaling for joiners that cannot reach the port (spec/nostr-signaling.md); set by `hostDirect`. */\n nostr: NostrHostBridge | null = null;\n private readonly server: Server;\n private readonly sockets = new Set<Socket>();\n private readonly ticker: ReturnType<typeof setInterval>;\n private readonly maxMessageBytes: number;\n private closed = false;\n\n private constructor(server: Server, port: number, hub: SignalingHub, maxMessageBytes: number) {\n this.server = server;\n this.port = port;\n this.hub = hub;\n this.maxMessageBytes = maxMessageBytes;\n this.ticker = setInterval(() => this.hub.tick(), 1000);\n this.ticker.unref?.();\n server.on(\"connection\", (sock) => this.accept(sock));\n }\n\n /**\n * Binds TCP `port` on every interface (IPv6 dual-stack where available). Hub options default to\n * {@link directHubOptions} (one lobby, no codes, no ICE servers). Rejects with {@link PortInUseError}.\n */\n static async listen(port: number, options?: Partial<HubOptions>, deps?: HubDeps & { host?: string }): Promise<DirectHubHost> {\n const opts = { ...directHubOptions(8), ...options };\n const server = createServer({ noDelay: true });\n const tryListen = (host: string, ipv6Only?: boolean) =>\n new Promise<void>((resolve, reject) => {\n const onError = (e: NodeJS.ErrnoException) => reject(e);\n server.once(\"error\", onError);\n server.listen({ port, host, ipv6Only }, () => {\n server.off(\"error\", onError);\n resolve();\n });\n });\n try {\n if (deps?.host) await tryListen(deps.host);\n else {\n if (port !== 0) await probeIPv4(port);\n try {\n await tryListen(\"::\", false);\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"EADDRINUSE\") throw e;\n await tryListen(\"0.0.0.0\"); // no IPv6 on this machine\n }\n }\n } catch (e) {\n throw new PortInUseError(port, (e as NodeJS.ErrnoException).code ?? String(e));\n }\n const addr = server.address();\n const bound = typeof addr === \"object\" && addr ? addr.port : port;\n return new DirectHubHost(server, bound, new SignalingHub(opts, deps), opts.maxMessageBytes);\n }\n\n /** Joiner sockets currently open. */\n get connectionCount(): number {\n return this.sockets.size;\n }\n\n /**\n * The host's own signaling socket: a WebSocket look-alike wired straight into the hub (no network). Pass it to the\n * kit as `advanced.socketFactory: () => host.connectLocal()`.\n */\n connectLocal(): SocketLike {\n return new LocalHubSocket(this.hub);\n }\n\n /** Asks the home router to forward TCP and UDP `port` here (UPnP, then NAT-PMP; docs/design/direct-ip.md s.2a). */\n openPort(options?: PortMapperOptions): Promise<PortMapResult> {\n if (this.portMapper) throw new Error(\"the port is already being opened\");\n this.portMapper = new PortMapper(this.port, options);\n return this.portMapper.open();\n }\n\n /** Stops listening, closes every joiner socket and removes the router mapping. Every call gets the same promise. */\n close(): Promise<void> {\n return (this.closing ??= this.closeOnce());\n }\n\n private closing?: Promise<void>;\n\n private async closeOnce(): Promise<void> {\n this.closed = true;\n clearInterval(this.ticker);\n this.nostr?.close();\n const unmap = this.portMapper?.close();\n for (const s of this.sockets) s.end(closeFrame(1001, \"host left\"));\n await new Promise<void>((resolve) => this.server.close(() => resolve()));\n setTimeout(() => { for (const s of this.sockets) s.destroy(); }, 300).unref?.();\n await unmap;\n }\n\n // ---------------------------------------------------------------- one TCP connection\n\n private accept(sock: Socket): void {\n if (this.closed) {\n sock.destroy();\n return;\n }\n this.sockets.add(sock);\n sock.on(\"close\", () => this.sockets.delete(sock));\n sock.on(\"error\", () => {});\n const ip = (sock.remoteAddress ?? \"\").replace(/^::ffff:/, \"\");\n let head = Buffer.alloc(0);\n const timer = setTimeout(() => sock.destroy(), HANDSHAKE_TIMEOUT_MS);\n const onData = (chunk: Buffer) => {\n head = Buffer.concat([head, chunk]);\n const end = head.indexOf(\"\\r\\n\\r\\n\");\n if (end < 0) {\n if (head.length > MAX_HEADER_BYTES) sock.destroy();\n return;\n }\n clearTimeout(timer);\n sock.off(\"data\", onData);\n const rest = head.subarray(end + 4);\n if (!this.handshake(sock, ip, head.subarray(0, end).toString(\"latin1\"))) return;\n this.run(sock, ip, rest);\n };\n sock.on(\"data\", onData);\n }\n\n /** RFC 6455 s.4.2: answers 101 with Sec-WebSocket-Accept, or 200 for /healthz and /metrics (loopback only), or 400/426. */\n private handshake(sock: Socket, ip: string, head: string): boolean {\n const [requestLine, ...lines] = head.split(\"\\r\\n\");\n const headers = new Map<string, string>();\n for (const l of lines) {\n const i = l.indexOf(\":\");\n if (i > 0) headers.set(l.slice(0, i).trim().toLowerCase(), l.slice(i + 1).trim());\n }\n const [method, path] = requestLine.split(\" \");\n const reply = (status: string, body: string, type = \"text/plain\") =>\n sock.end(`HTTP/1.1 ${status}\\r\\nContent-Type: ${type}\\r\\nContent-Length: ${Buffer.byteLength(body)}\\r\\nConnection: close\\r\\n\\r\\n${body}`);\n // The same two endpoints as onelobby-server; /metrics stays local because this port faces the internet.\n if (method === \"GET\" && path === \"/healthz\") {\n reply(\"200 OK\", \"ok\\n\");\n return false;\n }\n if (method === \"GET\" && path === \"/metrics\") {\n if (isLoopback(ip)) reply(\"200 OK\", this.hub.metrics.render(), \"text/plain; version=0.0.4\");\n else reply(\"403 Forbidden\", \"metrics are local only (OneLobby direct host)\");\n return false;\n }\n const key = headers.get(\"sec-websocket-key\");\n const upgrade = /websocket/i.test(headers.get(\"upgrade\") ?? \"\");\n // The share link for a page the host serves: a player who opened it at a LAN address still shares the public one.\n if (method === \"GET\" && !upgrade && path?.split(\"?\")[0] === \"/joininfo\") {\n if (this.joinInfo) reply(\"200 OK\", JSON.stringify(this.joinInfo), \"application/json\");\n else reply(\"404 Not Found\", \"no join code yet\");\n return false;\n }\n if (method === \"GET\" && !upgrade && this.http && path) {\n let page: HttpReply | null = null;\n let extra = \"\";\n try {\n page = this.http(path.split(\"?\")[0]);\n extra = replyHeaders(page?.headers);\n } catch {\n page = { status: 500, type: \"text/plain\", body: \"error\" };\n extra = replyHeaders(undefined);\n }\n const p = page ?? { status: 404, type: \"text/plain\", body: \"not found\" };\n const body = typeof p.body === \"string\" ? Buffer.from(p.body, \"utf8\") : Buffer.from(p.body);\n const status = p.status ?? 200;\n sock.write(`HTTP/1.1 ${status} ${STATUS_TEXT[status] ?? \"OK\"}\\r\\nContent-Type: ${p.type}\\r\\n` +\n `Content-Length: ${body.length}\\r\\n${extra}Connection: close\\r\\n\\r\\n`);\n sock.end(body);\n return false;\n }\n if (method !== \"GET\" || !upgrade || !key) {\n reply(\"426 Upgrade Required\", \"this port speaks WebSocket (OneLobby direct host)\");\n return false;\n }\n const origin = headers.get(\"origin\");\n if (origin !== undefined && !originAllowed(origin, headers.get(\"host\"), this.allowedOrigins)) {\n reply(\"403 Forbidden\", \"this origin may not join (OneLobby direct host)\");\n return false;\n }\n const accept = createHash(\"sha1\").update(key + WS_GUID).digest(\"base64\");\n sock.write(`HTTP/1.1 101 Switching Protocols\\r\\nUpgrade: websocket\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: ${accept}\\r\\n\\r\\n`);\n return true;\n }\n\n private run(sock: Socket, ip: string, initial: Buffer): void {\n let open = true;\n let session: Session | null = null;\n const shut = (code: number, reason: string) => {\n if (!open) return;\n open = false;\n if (sock.destroyed) return;\n // a reader that stopped reading never drains its buffer: give the close frame a moment, then cut it off\n if (code === 1008 && reason === \"backpressure\") {\n sock.write(closeFrame(code, reason));\n setTimeout(() => sock.destroy(), BACKPRESSURE_GRACE_MS).unref?.();\n if (session) this.hub.disconnect(session);\n } else sock.end(closeFrame(code, reason));\n };\n const sendText = (text: string) => {\n if (!open || sock.destroyed) return;\n sock.write(frame(0x1, Buffer.from(text, \"utf8\")));\n // a slow or malicious reader must not grow this process's memory without bound\n if (sock.writableLength > MAX_PENDING_WRITE_BYTES) shut(1008, \"backpressure\");\n };\n session = this.hub.connect(ip, sendText, (code, reason) => shut(code ?? 1000, reason ?? \"closed by the hub\"));\n if (!session) return;\n const s = session;\n const reader = new FrameReader(this.maxMessageBytes + 1024, {\n text: (t) => this.hub.receive(s, t),\n ping: (p) => !sock.destroyed && sock.write(frame(0xa, p)),\n close: () => {\n shut(1000, \"\");\n this.hub.disconnect(s);\n },\n fail: (code, why) => {\n shut(code, why);\n this.hub.disconnect(s);\n },\n });\n sock.on(\"data\", (b: Buffer) => reader.push(b));\n sock.on(\"close\", () => {\n open = false;\n this.hub.disconnect(s);\n });\n if (initial.length) reader.push(initial);\n }\n}\n\n// ------------------------------------------------------------------------------------------------ RFC 6455 framing\n\n/** One unmasked server frame (FIN set). */\nfunction frame(opcode: number, payload: Buffer): Buffer {\n const n = payload.length;\n const head = n < 126 ? Buffer.from([0x80 | opcode, n]) : n < 65536 ? Buffer.alloc(4) : Buffer.alloc(10);\n if (n >= 126) {\n head[0] = 0x80 | opcode;\n if (n < 65536) {\n head[1] = 126;\n head.writeUInt16BE(n, 2);\n } else {\n head[1] = 127;\n head.writeBigUInt64BE(BigInt(n), 2);\n }\n }\n return Buffer.concat([head, payload]);\n}\n\nfunction closeFrame(code: number, reason: string): Buffer {\n const r = Buffer.from(reason.slice(0, 100), \"utf8\");\n const p = Buffer.alloc(2 + r.length);\n p.writeUInt16BE(code, 0);\n r.copy(p, 2);\n return frame(0x8, p);\n}\n\ninterface FrameSink {\n text(t: string): void;\n ping(payload: Buffer): void;\n close(): void;\n fail(code: number, why: string): void;\n}\n\n/** Incremental client-frame parser: masked frames only, text messages (fragmented or not), control frames between. */\nclass FrameReader {\n private buf: Buffer = Buffer.alloc(0);\n private parts: Buffer[] = [];\n private partBytes = 0;\n private inMessage = false;\n private binary = false;\n private done = false;\n private readonly utf8 = new TextDecoder(\"utf-8\", { fatal: true });\n\n constructor(private readonly maxMessage: number, private readonly sink: FrameSink) {}\n\n push(chunk: Buffer): void {\n if (this.done) return;\n this.buf = this.buf.length ? Buffer.concat([this.buf, chunk]) : chunk;\n while (!this.done) {\n if (this.buf.length < 2) return;\n const b0 = this.buf[0];\n const b1 = this.buf[1];\n const fin = (b0 & 0x80) !== 0;\n const opcode = b0 & 0x0f;\n if (b0 & 0x70) return this.fail(1002, \"reserved bits set\");\n if (!(b1 & 0x80)) return this.fail(1002, \"client frames must be masked\");\n let len = b1 & 0x7f;\n let off = 2;\n if (len === 126) {\n if (this.buf.length < 4) return;\n len = this.buf.readUInt16BE(2);\n off = 4;\n } else if (len === 127) {\n if (this.buf.length < 10) return;\n const big = this.buf.readBigUInt64BE(2);\n if (big > BigInt(this.maxMessage)) return this.fail(1009, \"message too big\");\n len = Number(big);\n off = 10;\n }\n if (len > this.maxMessage) return this.fail(1009, \"message too big\");\n if (this.buf.length < off + 4 + len) return;\n const mask = this.buf.subarray(off, off + 4);\n const payload = Buffer.from(this.buf.subarray(off + 4, off + 4 + len));\n for (let i = 0; i < payload.length; i++) payload[i] ^= mask[i & 3];\n this.buf = this.buf.subarray(off + 4 + len);\n if (opcode >= 0x8) {\n if (!fin || len > 125) return this.fail(1002, \"bad control frame\");\n if (opcode === 0x8) {\n this.done = true;\n this.sink.close();\n return;\n }\n if (opcode === 0x9) this.sink.ping(payload);\n continue; // pong or unknown control: ignore\n }\n if (opcode === 0x1 || opcode === 0x2) {\n if (this.inMessage) return this.fail(1002, \"new message inside a fragmented one\");\n this.inMessage = true;\n this.binary = opcode === 0x2; // spec/signaling.md: binary frames are ignored\n } else if (opcode !== 0x0 || !this.inMessage) return this.fail(1002, \"unexpected continuation\");\n this.partBytes += payload.length;\n if (this.partBytes > this.maxMessage) return this.fail(1009, \"message too big\");\n if (!this.binary) this.parts.push(payload);\n if (fin) {\n const all = this.parts.length === 1 ? this.parts[0] : Buffer.concat(this.parts);\n const skip = this.binary;\n this.parts = [];\n this.partBytes = 0;\n this.inMessage = false;\n this.binary = false;\n if (skip) continue;\n let text: string;\n try {\n text = this.utf8.decode(all);\n } catch {\n return this.fail(1007, \"invalid UTF-8\");\n }\n this.sink.text(text);\n }\n }\n }\n\n private fail(code: number, why: string): void {\n this.done = true;\n this.sink.fail(code, why);\n }\n}\n\nexport { LocalHubSocket };\n"]}
@@ -0,0 +1,22 @@
1
+ import type { SocketLike } from "../transport.js";
2
+ import type { SignalingHub } from "./hub.js";
3
+ /**
4
+ * A direct host's own signaling socket (C#'s `HubSignalingSocket`): sends go straight into the hub; the hub's
5
+ * replies are delivered on a microtask, so callbacks never run inside the hub. No Node APIs, so a browser tab can
6
+ * use it too (`kit.hostNostr`).
7
+ */
8
+ export declare class LocalHubSocket implements SocketLike {
9
+ private readonly hub;
10
+ /** Address the hub sees for the host itself (rate limits and kicks are per address). */
11
+ static readonly ADDRESS = "local";
12
+ readyState: number;
13
+ onopen: SocketLike["onopen"];
14
+ onmessage: SocketLike["onmessage"];
15
+ onclose: SocketLike["onclose"];
16
+ onerror: SocketLike["onerror"];
17
+ private session;
18
+ constructor(hub: SignalingHub);
19
+ send(data: string): void;
20
+ close(): void;
21
+ private finish;
22
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * A direct host's own signaling socket (C#'s `HubSignalingSocket`): sends go straight into the hub; the hub's
3
+ * replies are delivered on a microtask, so callbacks never run inside the hub. No Node APIs, so a browser tab can
4
+ * use it too (`kit.hostNostr`).
5
+ */
6
+ export class LocalHubSocket {
7
+ hub;
8
+ /** Address the hub sees for the host itself (rate limits and kicks are per address). */
9
+ static ADDRESS = "local";
10
+ readyState = 0;
11
+ onopen = null;
12
+ onmessage = null;
13
+ onclose = null;
14
+ onerror = null;
15
+ session;
16
+ constructor(hub) {
17
+ this.hub = hub;
18
+ this.session = hub.connect(LocalHubSocket.ADDRESS, (text) => queueMicrotask(() => this.readyState === 1 && this.onmessage?.({ data: text })), () => this.finish());
19
+ queueMicrotask(() => {
20
+ if (!this.session) {
21
+ this.finish();
22
+ return;
23
+ }
24
+ this.readyState = 1;
25
+ this.onopen?.();
26
+ });
27
+ }
28
+ send(data) {
29
+ if (this.readyState === 1 && this.session)
30
+ this.hub.receive(this.session, data);
31
+ }
32
+ close() {
33
+ const s = this.session;
34
+ const wasOpen = this.readyState === 1;
35
+ this.finish();
36
+ if (wasOpen && s)
37
+ this.hub.disconnect(s);
38
+ }
39
+ finish() {
40
+ if (this.readyState === 3)
41
+ return;
42
+ this.readyState = 3;
43
+ queueMicrotask(() => this.onclose?.());
44
+ }
45
+ }
46
+ //# sourceMappingURL=hub-local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hub-local.js","sourceRoot":"","sources":["../../src/direct/hub-local.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,OAAO,cAAc;IAUI;IAT7B,wFAAwF;IACxF,MAAM,CAAU,OAAO,GAAG,OAAO,CAAC;IAClC,UAAU,GAAG,CAAC,CAAC;IACf,MAAM,GAAyB,IAAI,CAAC;IACpC,SAAS,GAA4B,IAAI,CAAC;IAC1C,OAAO,GAA0B,IAAI,CAAC;IACtC,OAAO,GAA0B,IAAI,CAAC;IAC9B,OAAO,CAAiB;IAEhC,YAA6B,GAAiB;QAAjB,QAAG,GAAH,GAAG,CAAc;QAC5C,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CACjJ,IAAI,CAAC,MAAM,EAAE,CACd,CAAC;QACF,cAAc,CAAC,GAAG,EAAE;YAClB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClB,IAAI,CAAC,MAAM,EAAE,CAAC;gBACd,OAAO;YACT,CAAC;YACD,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;YACpB,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,IAAY;QACf,IAAI,IAAI,CAAC,UAAU,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO;YAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAClF,CAAC;IAED,KAAK;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,OAAO,IAAI,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IAEO,MAAM;QACZ,IAAI,IAAI,CAAC,UAAU,KAAK,CAAC;YAAE,OAAO;QAClC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,cAAc,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACzC,CAAC","sourcesContent":["import type { SocketLike } from \"../transport.js\";\nimport type { SignalingHub, Session } from \"./hub.js\";\n\n/**\n * A direct host's own signaling socket (C#'s `HubSignalingSocket`): sends go straight into the hub; the hub's\n * replies are delivered on a microtask, so callbacks never run inside the hub. No Node APIs, so a browser tab can\n * use it too (`kit.hostNostr`).\n */\nexport class LocalHubSocket implements SocketLike {\n /** Address the hub sees for the host itself (rate limits and kicks are per address). */\n static readonly ADDRESS = \"local\";\n readyState = 0;\n onopen: SocketLike[\"onopen\"] = null;\n onmessage: SocketLike[\"onmessage\"] = null;\n onclose: SocketLike[\"onclose\"] = null;\n onerror: SocketLike[\"onerror\"] = null;\n private session: Session | null;\n\n constructor(private readonly hub: SignalingHub) {\n this.session = hub.connect(LocalHubSocket.ADDRESS, (text) => queueMicrotask(() => this.readyState === 1 && this.onmessage?.({ data: text })), () =>\n this.finish(),\n );\n queueMicrotask(() => {\n if (!this.session) {\n this.finish();\n return;\n }\n this.readyState = 1;\n this.onopen?.();\n });\n }\n\n send(data: string): void {\n if (this.readyState === 1 && this.session) this.hub.receive(this.session, data);\n }\n\n close(): void {\n const s = this.session;\n const wasOpen = this.readyState === 1;\n this.finish();\n if (wasOpen && s) this.hub.disconnect(s);\n }\n\n private finish(): void {\n if (this.readyState === 3) return;\n this.readyState = 3;\n queueMicrotask(() => this.onclose?.());\n }\n}\n"]}
@@ -1,10 +1,13 @@
1
1
  /**
2
- * The signaling hub (protocol lk1) in TypeScript, for a Node process that hosts direct-IP lobbies
3
- * (docs/direct-ip.md s.2): a line-by-line port of `server/OneLobby.Hub/Hub.cs`, held to the same rules by
2
+ * The signaling hub (protocol lk1) in TypeScript, for a Node process or a browser tab that hosts direct lobbies
3
+ * (docs/design/direct-ip.md s.2): a line-by-line port of `server/OneLobby.Hub/Hub.cs`, held to the same rules by
4
4
  * `conformance/server`. Transport-agnostic: feed it text frames with `receive`, call `tick` about once a second.
5
- * Metrics are left out (that is onelobby-server's job); everything else (codes, list, resume, private lobbies,
6
- * kicks, migration claims, TURN credentials, rate limits) behaves as in C#.
5
+ * Metrics (same names, labels and help text as C#, rendered by `metrics.render()`) are counted too, so every hub shape
6
+ * looks the same from outside; everything else (codes, list, resume, private lobbies, kicks, migration claims, TURN
7
+ * credentials, rate limits) behaves as in C#.
7
8
  */
9
+ import { Metrics } from "./metrics.js";
10
+ export { Metrics };
8
11
  export declare const PROTO = "lk1";
9
12
  /** The settings the hub reads; same names and defaults as C#'s `HubOptions`. */
10
13
  export interface HubOptions {
@@ -26,6 +29,8 @@ export interface HubOptions {
26
29
  createPerMin: number;
27
30
  joinPerMin: number;
28
31
  signalPerSec: number;
32
+ /** Open sockets per address (loopback included); `disableIpLimits` lifts it, `rateScale` scales it. */
33
+ socketsPerIp: number;
29
34
  openLobbiesPerIp: number;
30
35
  idleTimeoutMs: number;
31
36
  resumeWindowMs: number;
@@ -39,8 +44,14 @@ export interface HubOptions {
39
44
  issueCodes: boolean;
40
45
  }
41
46
  export declare function defaultHubOptions(): HubOptions;
42
- /** Settings for a hub inside the host's game (docs/direct-ip.md s.2): no codes, no list, no ICE servers. */
47
+ /** Settings for a hub inside the host's game (docs/design/direct-ip.md s.2): no codes, no list, no ICE servers. */
43
48
  export declare function directHubOptions(maxPlayers: number, password?: string | null): HubOptions;
49
+ /** A session's total `signal` budget is this many targets' worth of `signalPerSec` (spec/signaling.md rate limits). */
50
+ export declare const SIGNAL_FANOUT = 8;
51
+ /** Hub sessions bridged from Nostr have the address `nostr:<pubkey prefix>`. */
52
+ export declare const NOSTR_ADDR = "nostr:";
53
+ /** `signal` per second per (sender, Nostr target): relays reject high publish rates. */
54
+ export declare const NOSTR_SIGNAL_PER_SEC = 10;
44
55
  /** Sliding-window counter: at most `limit` events per `windowMs`. */
45
56
  export declare class RateWindow {
46
57
  readonly limit: number;
@@ -60,8 +71,7 @@ export declare class Session {
60
71
  readonly ip: string;
61
72
  readonly connId: string;
62
73
  readonly send: (text: string) => void;
63
- readonly close: () => void;
64
- readonly signalRate: RateWindow;
74
+ readonly close: (code?: number, reason?: string) => void;
65
75
  closed: boolean;
66
76
  lastSeen: number;
67
77
  helloDone: boolean;
@@ -72,7 +82,13 @@ export declare class Session {
72
82
  member: Member | null;
73
83
  pendingIn: HubLobby | null;
74
84
  pendingMember: Member | null;
75
- constructor(id: number, ip: string, connId: string, send: (text: string) => void, close: () => void, signalRate: RateWindow);
85
+ constructor(id: number, ip: string, connId: string, send: (text: string) => void, close: (code?: number, reason?: string) => void);
86
+ /** Nostr joiners: the remote address of the host's WebRTC link to this session, once known (kick bans it too). */
87
+ linkIp: string | null;
88
+ /** One window per target member (a member belongs to one lobby, so a new lobby starts fresh). */
89
+ readonly signalRates: Map<Member, RateWindow>;
90
+ /** All signals of this session, so the per-target budget does not grow without bound with the lobby. */
91
+ signalTotal: RateWindow | null;
76
92
  }
77
93
  declare class Member {
78
94
  peerId: number;
@@ -132,13 +148,20 @@ export declare class SignalingHub {
132
148
  private createdOnce;
133
149
  private members;
134
150
  private readonly logSalt;
151
+ readonly metrics: Metrics;
135
152
  constructor(options?: Partial<HubOptions>, deps?: HubDeps);
136
153
  get lobbyCount(): number;
137
154
  get socketCount(): number;
138
155
  private get scale();
139
156
  /** Registers a socket. Returns null (after sending server_full and closing) when over maxPeers. */
140
- connect(ip: string, send: (text: string) => void, close: () => void): Session | null;
157
+ connect(ip: string, send: (text: string) => void, close: (code?: number, reason?: string) => void): Session | null;
141
158
  disconnect(s: Session): void;
159
+ /**
160
+ * The host's WebRTC link to joiner `peerId` has the remote address `ip` (selected candidate pair; the host's own
161
+ * lobby reports it, a relayed or mDNS address must not be passed). Only Nostr sessions take it: their socket address
162
+ * is a pubkey the joiner chose. A joiner whose link address is banned is removed as kicked; a later kick bans it.
163
+ */
164
+ reportLinkAddress(peerId: number, ip: string): void;
142
165
  private closeSession;
143
166
  /** Call about once a second: idle timeouts, resume-window expiry, code retirement. */
144
167
  tick(): void;
@@ -153,6 +176,11 @@ export declare class SignalingHub {
153
176
  private list;
154
177
  private leave;
155
178
  private signal;
179
+ /**
180
+ * spec/signaling.md rate limits: `signal` is counted per sender and target, so a host answering several joiners at once
181
+ * gets the budget for each, and per sender in total (SIGNAL_FANOUT targets' worth).
182
+ */
183
+ private signalRate;
156
184
  private requireHost;
157
185
  private hostMeta;
158
186
  private hostPhase;
@@ -178,4 +206,3 @@ export declare class SignalingHub {
178
206
  private logEvent;
179
207
  private hashIp;
180
208
  }
181
- export {};