onelobby 0.5.0 → 0.7.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 (109) hide show
  1. package/README.md +2 -2
  2. package/blueprint.schema.json +8 -1
  3. package/dist/blueprint.d.ts +4 -0
  4. package/dist/blueprint.js +5 -0
  5. package/dist/blueprint.js.map +1 -1
  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 +39 -10
  19. package/dist/direct/hub.js +134 -24
  20. package/dist/direct/hub.js.map +1 -1
  21. package/dist/direct/index.d.ts +36 -3
  22. package/dist/direct/index.js +146 -20
  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 +24 -0
  36. package/dist/friendly.js +30 -0
  37. package/dist/friendly.js.map +1 -1
  38. package/dist/index.d.ts +8 -4
  39. package/dist/index.js +6 -4
  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 +94 -5
  51. package/dist/lobby.js +177 -18
  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 +33 -0
  63. package/dist/nostr/limits.js +38 -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 +325 -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 +31 -3
  85. package/dist/onelobby.global.js +2673 -60
  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 +77 -14
  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/signaling.d.ts +2 -0
  95. package/dist/signaling.js.map +1 -1
  96. package/dist/socket.d.ts +15 -6
  97. package/dist/socket.js.map +1 -1
  98. package/dist/testing.d.ts +2 -0
  99. package/dist/testing.js +18 -2
  100. package/dist/testing.js.map +1 -1
  101. package/dist/transport.d.ts +5 -1
  102. package/dist/transport.js.map +1 -1
  103. package/dist/webrtc.d.ts +6 -0
  104. package/dist/webrtc.js +27 -3
  105. package/dist/webrtc.js.map +1 -1
  106. package/package.json +1 -1
  107. package/dist/deprecated.d.ts +0 -18
  108. package/dist/deprecated.js +0 -11
  109. package/dist/deprecated.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"portmap.js","sourceRoot":"","sources":["../../src/direct/portmap.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference types=\"node\" />\nimport { createSocket, type Socket as UdpSocket } from \"node:dgram\";\nimport { request as httpRequest } from \"node:http\";\nimport { networkInterfaces } from \"node:os\";\nimport { execFile } from \"node:child_process\";\n\nexport type PortMapMethod = \"none\" | \"upnp\" | \"natpmp\";\n\n/** What {@link PortMapper.open} found. `mapped` means TCP and UDP `port` both forward here. */\nexport interface PortMapResult {\n mapped: boolean;\n method: PortMapMethod;\n /** The router's WAN address as it reports it (may itself be private or carrier-grade NAT). */\n externalIPv4: string | null;\n /** This PC's address on the router's network, when the router was found. */\n localIPv4: string | null;\n /** Why nothing was mapped, for logs. */\n detail: string;\n}\n\n/** Seams for tests (a fake gateway on loopback) and the few knobs a game might want. Same as C#'s PortMapperOptions. */\nexport interface PortMapperOptions {\n /** Where the SSDP M-SEARCH goes; default the UPnP multicast group 239.255.255.250:1900. */\n ssdp?: { address: string; port: number };\n /** NAT-PMP server; default this PC's IPv4 default gateway, port 5351. */\n natPmp?: { address: string; port: number };\n discoveryTimeoutMs?: number;\n requestTimeoutMs?: number;\n /** Lease asked for; renewed at half of it while hosting. Routers that only allow permanent leases get 0. */\n leaseSeconds?: number;\n description?: string;\n tryUpnp?: boolean;\n tryNatPmp?: boolean;\n /**\n * Optional log hook; left out (default) stays quiet. Gets one line when the host quits and its mappings are deleted:\n * `direct host mapping deleted port=47810 protocols=TCP,UDP mapping=UPnP`.\n */\n log?: (line: string) => void;\n}\n\nconst SEARCH_TARGETS = [\n \"urn:schemas-upnp-org:device:InternetGatewayDevice:1\",\n \"urn:schemas-upnp-org:device:InternetGatewayDevice:2\",\n \"urn:schemas-upnp-org:service:WANIPConnection:1\",\n];\nconst SERVICE_TYPES = [\n \"urn:schemas-upnp-org:service:WANIPConnection:2\",\n \"urn:schemas-upnp-org:service:WANIPConnection:1\",\n \"urn:schemas-upnp-org:service:WANPPPConnection:1\",\n];\n\nclass UpnpError extends Error {\n constructor(readonly code: number, message: string) {\n super(message);\n }\n}\n\n/**\n * Opens TCP and UDP `port` on the home router for a direct-IP host (docs/direct-ip.md s.2a): UPnP IGD (SSDP, then\n * GetExternalIPAddress + AddPortMapping), then NAT-PMP (RFC 6886). Node twin of C#'s `PortMapper`, same order and rules:\n * same external and internal port or nothing (a join code carries one port), leases renew at half-life, {@link close}\n * deletes the mappings. Windows Firewall drops SSDP replies on a network marked Public; the result is then unmapped.\n */\nexport class PortMapper {\n result: PortMapResult | null = null;\n private readonly o: Required<Omit<PortMapperOptions, \"natPmp\" | \"log\">> & Pick<PortMapperOptions, \"natPmp\" | \"log\">;\n private control: URL | null = null;\n private service = \"\";\n private lease = 0;\n private natPmpAt: { address: string; port: number } | null = null;\n private renew: ReturnType<typeof setInterval> | null = null;\n private stopped = false;\n private opening: Promise<PortMapResult> | null = null;\n /**\n * Every mapping a request was sent for and the router did not refuse (\"upnp TCP\", \"pmp 1\", ...): what close()\n * deletes. Added before the request goes out, so a host that quits mid-request still undoes it.\n */\n private readonly maybeMapped = new Set<string>();\n\n constructor(readonly port: number, options: PortMapperOptions = {}) {\n if (!Number.isInteger(port) || port < 1 || port > 65535) throw new RangeError(`bad port ${port}`);\n this.o = {\n ssdp: { address: \"239.255.255.250\", port: 1900 },\n discoveryTimeoutMs: 2000,\n requestTimeoutMs: 3000,\n leaseSeconds: 7200,\n description: \"OneLobby\",\n tryUpnp: true,\n tryNatPmp: true,\n ...options,\n };\n }\n\n /** Finds the router and maps TCP + UDP `port`. Never rejects for network trouble: see `detail`. */\n open(): Promise<PortMapResult> {\n return (this.opening = this.openBoth());\n }\n\n private async openBoth(): Promise<PortMapResult> {\n const notes: string[] = [];\n if (this.o.tryUpnp) {\n try {\n const r = await this.tryUpnp();\n if (r) return this.done(r);\n notes.push(\"no UPnP gateway answered\");\n } catch (e) {\n notes.push(`UPnP: ${(e as Error).message}`);\n }\n }\n if (this.o.tryNatPmp) {\n try {\n const r = await this.tryNatPmp();\n if (r) return this.done(r);\n notes.push(\"no NAT-PMP answer\");\n } catch (e) {\n notes.push(`NAT-PMP: ${(e as Error).message}`);\n }\n }\n return (this.result = { mapped: false, method: \"none\", externalIPv4: null, localIPv4: null, detail: notes.join(\"; \") });\n }\n\n private done(r: PortMapResult): PortMapResult {\n this.result = r;\n if (r.mapped && !this.stopped && (this.lease > 0 || r.method === \"natpmp\")) {\n const everyMs = Math.max(30, (this.lease > 0 ? this.lease : this.o.leaseSeconds) / 2) * 1000;\n this.renew = setInterval(() => {\n const p = r.method === \"upnp\" ? this.addUpnpBoth(r.localIPv4!, this.lease) : this.natPmpMapBoth(this.o.leaseSeconds);\n p.catch(() => {}); // the next round tries again; the old lease still has half its life\n }, everyMs);\n this.renew.unref?.();\n }\n return r;\n }\n\n // ------------------------------------------------------------------------------------------------ UPnP IGD\n\n private async tryUpnp(): Promise<PortMapResult | null> {\n const location = await this.discover();\n if (!location) return null;\n const desc = await this.http(\"GET\", location, null, {});\n const baseText = tag(desc.body, \"URLBase\");\n const base = baseText && /^https?:\\/\\//i.test(baseText) ? new URL(baseText) : location;\n for (const type of SERVICE_TYPES) {\n for (const svc of desc.body.match(/<service>[\\s\\S]*?<\\/service>/g) ?? []) {\n if ((tag(svc, \"serviceType\") ?? \"\").trim() !== type) continue;\n const ctl = tag(svc, \"controlURL\")?.trim();\n if (!ctl) continue;\n this.control = new URL(ctl, base);\n this.service = type;\n break;\n }\n if (this.control) break;\n }\n if (!this.control) return { mapped: false, method: \"upnp\", externalIPv4: null, localIPv4: null, detail: \"UPnP gateway has no WANIPConnection service\" };\n\n const local = await localAddressToward(this.control.hostname, Number(this.control.port) || 80);\n let external: string | null = null;\n try {\n external = tag((await this.soap(\"GetExternalIPAddress\", [])).body, \"NewExternalIPAddress\")?.trim() ?? null;\n } catch (e) {\n if (!(e instanceof UpnpError)) throw e; // some routers refuse this but still map\n }\n this.lease = this.o.leaseSeconds;\n try {\n await this.addUpnpBoth(local, this.lease);\n } catch (e) {\n if (!(e instanceof UpnpError)) throw e;\n if (e.code === 725) {\n // OnlyPermanentLeasesSupported\n this.lease = 0;\n await this.addUpnpBoth(local, 0);\n } else return { mapped: false, method: \"upnp\", externalIPv4: external, localIPv4: local, detail: `UPnP ${e.message}` };\n }\n return { mapped: true, method: \"upnp\", externalIPv4: external, localIPv4: local, detail: \"UPnP\" };\n }\n\n private async addUpnpBoth(local: string, lease: number): Promise<void> {\n for (const proto of [\"TCP\", \"UDP\"]) {\n if (this.stopped) throw new Error(\"closed before the router answered\");\n const key = `upnp ${proto}`;\n this.maybeMapped.add(key);\n try {\n await this.soap(\"AddPortMapping\", [\n [\"NewRemoteHost\", \"\"], [\"NewExternalPort\", String(this.port)], [\"NewProtocol\", proto], [\"NewInternalPort\", String(this.port)],\n [\"NewInternalClient\", local], [\"NewEnabled\", \"1\"], [\"NewPortMappingDescription\", this.o.description], [\"NewLeaseDuration\", String(lease)],\n ]);\n } catch (e) {\n // refused (e.g. 718: another device holds the port): not ours, so close() must not delete it\n if (e instanceof UpnpError) this.maybeMapped.delete(key);\n throw e;\n }\n // close() ran while this request was out: its delete may have reached the router first, so undo it now\n if (this.stopped) await this.undo([key]);\n }\n }\n\n /**\n * SSDP search: multicast once per interface that has a gateway (so a Hyper-V, WSL or Docker adapter cannot swallow\n * it), plus a unicast copy to the gateway.\n */\n private discover(): Promise<URL | null> {\n const multicast = Number(this.o.ssdp.address.split(\".\")[0]) >= 224;\n const locals = multicast ? gatewayInterfaces() : [];\n if (locals.length === 0) locals.push({ local: \"0.0.0.0\", gateway: null });\n return new Promise((resolve) => {\n const sockets: UdpSocket[] = [];\n let finished = false;\n const finish = (u: URL | null) => {\n if (finished) return;\n finished = true;\n clearTimeout(timer);\n for (const s of sockets) s.close();\n resolve(u);\n };\n const timer = setTimeout(() => finish(null), this.o.discoveryTimeoutMs);\n for (const { local, gateway } of locals) {\n const s = createSocket({ type: \"udp4\", reuseAddr: false });\n sockets.push(s);\n s.on(\"error\", () => {});\n s.on(\"message\", (m) => {\n const u = parseSsdp(m.toString(\"latin1\"));\n if (u) finish(u);\n });\n s.bind(0, local === \"0.0.0.0\" ? undefined : local, () => {\n try {\n s.setMulticastTTL(2);\n if (local !== \"0.0.0.0\") s.setMulticastInterface(local);\n } catch {\n /* not fatal: the OS default interface is used */\n }\n for (const st of SEARCH_TARGETS) {\n const b = Buffer.from(`M-SEARCH * HTTP/1.1\\r\\nHOST: 239.255.255.250:1900\\r\\nMAN: \"ssdp:discover\"\\r\\nMX: 1\\r\\nST: ${st}\\r\\n\\r\\n`);\n s.send(b, this.o.ssdp.port, this.o.ssdp.address, () => {});\n if (gateway) s.send(b, 1900, gateway, () => {});\n }\n });\n }\n });\n }\n\n private async soap(action: string, args: [string, string][]): Promise<{ status: number; body: string }> {\n const inner = args.map(([k, v]) => `<${k}>${xmlEscape(v)}</${k}>`).join(\"\");\n const body =\n `<?xml version=\"1.0\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">` +\n `<s:Body><u:${action} xmlns:u=\"${this.service}\">${inner}</u:${action}></s:Body></s:Envelope>`;\n const res = await this.http(\"POST\", this.control!, body, { \"Content-Type\": 'text/xml; charset=\"utf-8\"', SOAPAction: `\"${this.service}#${action}\"` });\n if (res.status < 200 || res.status >= 300) {\n const code = tag(res.body, \"errorCode\");\n const desc = tag(res.body, \"errorDescription\") ?? \"\";\n throw new UpnpError(Number(code) || 0, `${action} error ${code ?? res.status} ${desc}`.trim());\n }\n return res;\n }\n\n /**\n * One connection per request: some routers close after each reply without saying so, and a reused\n * keep-alive socket then fails every second request with \"socket hang up\".\n */\n private http(method: string, url: URL, body: string | null, headers: Record<string, string>): Promise<{ status: number; body: string }> {\n return new Promise((resolve, reject) => {\n const h = { ...headers, Connection: \"close\" };\n const req = httpRequest(\n { method, hostname: url.hostname, port: url.port || 80, path: url.pathname + url.search, timeout: this.o.requestTimeoutMs, agent: false,\n headers: body === null ? h : { ...h, \"Content-Length\": Buffer.byteLength(body) } },\n (res) => {\n let text = \"\";\n res.setEncoding(\"utf8\");\n res.on(\"data\", (d) => (text += d));\n res.on(\"end\", () => resolve({ status: res.statusCode ?? 0, body: text }));\n },\n );\n req.on(\"timeout\", () => req.destroy(new Error(`${method} ${url.pathname} timed out`)));\n req.on(\"error\", reject);\n if (body !== null) req.write(body);\n req.end();\n });\n }\n\n // ------------------------------------------------------------------------------------------------ NAT-PMP\n\n private async tryNatPmp(): Promise<PortMapResult | null> {\n // One gateway only: each silent one costs the full retransmission budget.\n let gw0 = this.o.natPmp ?? null;\n if (!gw0) {\n const routed = (await defaultGatewayFallback()) ?? gatewayInterfaces().find((g) => g.gateway)?.gateway ?? null;\n if (routed) gw0 = { address: routed, port: 5351 };\n }\n const candidates = gw0 ? [gw0] : [];\n for (const gw of candidates) {\n const ext = await this.natPmpRequest(gw, Buffer.from([0, 0]), 12);\n if (!ext) continue;\n this.natPmpAt = gw;\n const local = await localAddressToward(gw.address, gw.port);\n const external = ext.readUInt16BE(2) === 0 ? `${ext[8]}.${ext[9]}.${ext[10]}.${ext[11]}` : null;\n const err = await this.natPmpMapBoth(this.o.leaseSeconds);\n if (err) return { mapped: false, method: \"natpmp\", externalIPv4: external, localIPv4: local, detail: `NAT-PMP ${err}` };\n return { mapped: true, method: \"natpmp\", externalIPv4: external, localIPv4: local, detail: \"NAT-PMP\" };\n }\n return null;\n }\n\n /** Maps UDP then TCP; null on success, else why. A different external port counts as failure (and is undone). */\n private async natPmpMapBoth(lifetime: number): Promise<string | null> {\n for (const op of [1, 2]) {\n if (this.stopped) return \"closed before the router answered\";\n const key = `pmp ${op}`;\n this.maybeMapped.add(key);\n const reply = await this.natPmpRequest(this.natPmpAt!, this.mapRequest(op, lifetime), 16);\n if (this.stopped) await this.undo([key]);\n if (!reply) return \"no answer to the mapping request\";\n const rc = reply.readUInt16BE(2);\n if (rc !== 0) {\n this.maybeMapped.delete(key);\n return `result code ${rc}`;\n }\n const mapped = reply.readUInt16BE(10);\n if (lifetime > 0 && mapped !== this.port) {\n await this.natPmpRequest(this.natPmpAt!, this.mapRequest(op, 0), 16);\n this.maybeMapped.delete(key);\n return `router offered port ${mapped} instead of ${this.port}`;\n }\n }\n return null;\n }\n\n private mapRequest(op: number, lifetime: number): Buffer {\n const b = Buffer.alloc(12);\n b[1] = op;\n b.writeUInt16BE(this.port, 4);\n b.writeUInt16BE(lifetime > 0 ? this.port : 0, 6);\n b.writeUInt32BE(lifetime, 8);\n return b;\n }\n\n /** RFC 6886 s.3.1 retransmission: 250 ms, doubling, 3 tries (under 2 s). Null when nobody answers. */\n private natPmpRequest(to: { address: string; port: number }, req: Buffer, replyLength: number): Promise<Buffer | null> {\n return new Promise((resolve) => {\n const s = createSocket(\"udp4\");\n let wait = 250;\n let tries = 0;\n let timer: ReturnType<typeof setTimeout> | null = null;\n const finish = (b: Buffer | null) => {\n if (timer) clearTimeout(timer);\n s.close();\n resolve(b);\n };\n s.on(\"error\", () => {}); // ICMP port unreachable on Windows: keep waiting for the timer\n s.on(\"message\", (b) => {\n if (b.length >= replyLength && b[0] === 0 && b[1] === req[1] + 128) finish(b);\n });\n const attempt = () => {\n if (tries++ >= 3) return finish(null);\n s.send(req, to.port, to.address, () => {});\n timer = setTimeout(attempt, wait);\n wait *= 2;\n };\n s.bind(0, attempt);\n });\n }\n\n /**\n * Stops renewing and deletes every mapping it may have made, even while {@link open} is still talking to the router\n * (best effort, bounded to about two seconds; a request still out when it returns undoes itself when it lands).\n */\n async close(): Promise<void> {\n if (this.stopped) return;\n this.stopped = true;\n if (this.renew) clearInterval(this.renew);\n if (this.opening) await Promise.race([this.opening.catch(() => {}), delay(500)]);\n await this.undo([...this.maybeMapped]);\n }\n\n private async undo(keys: string[]): Promise<void> {\n if (keys.length === 0) return;\n const work = Promise.all(\n keys.map((k) => {\n this.maybeMapped.delete(k);\n return k.startsWith(\"upnp \")\n ? this.soap(\"DeletePortMapping\", [[\"NewRemoteHost\", \"\"], [\"NewExternalPort\", String(this.port)], [\"NewProtocol\", k.slice(5)]])\n : this.natPmpOnce(this.mapRequest(Number(k.slice(4)), 0));\n }),\n );\n await Promise.race([work.catch(() => {}), delay(1500)]);\n this.logDeleted(keys);\n }\n\n /** One line per mapping kind, e.g. `direct host mapping deleted port=47810 protocols=TCP,UDP mapping=UPnP`. */\n private logDeleted(keys: string[]): void {\n if (!this.o.log) return;\n for (const upnp of [true, false]) {\n const mine = keys.filter((k) => k.startsWith(\"upnp \") === upnp);\n if (mine.length === 0) continue;\n const protos = [...new Set(mine.map((k) => (upnp ? k.slice(5) : k === \"pmp 2\" ? \"TCP\" : \"UDP\")))].sort();\n try {\n this.o.log(`direct host mapping deleted port=${this.port} protocols=${protos.join(\",\")} mapping=${upnp ? \"UPnP\" : \"NAT-PMP\"}`);\n } catch {\n // a game's logger must not stop the quit\n }\n }\n }\n\n private natPmpOnce(req: Buffer): Promise<void> {\n return new Promise((resolve) => {\n const s = createSocket(\"udp4\");\n s.on(\"error\", () => {});\n s.send(req, this.natPmpAt!.port, this.natPmpAt!.address, () => {\n s.close();\n resolve();\n });\n });\n }\n}\n\n// ------------------------------------------------------------------------------------------------ helpers\n\n/**\n * True for an address the internet can route to: not private (RFC 1918), carrier-grade NAT (100.64/10), loopback,\n * link-local, 0/8, or multicast/reserved (224+). A router that reports a non-public WAN address is itself behind NAT.\n */\nexport function isPublicIPv4(address: string | null | undefined): boolean {\n if (!address) return false;\n const m = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.exec(address);\n if (!m) return false;\n const [a, b] = [Number(m[1]), Number(m[2])];\n if (m.slice(1).some((x) => Number(x) > 255)) return false;\n if (a === 0 || a === 10 || a === 127 || a >= 224) return false;\n if (a === 100 && b >= 64 && b < 128) return false;\n if (a === 169 && b === 254) return false;\n if (a === 172 && b >= 16 && b < 32) return false;\n if (a === 192 && b === 168) return false;\n return true;\n}\n\nfunction tag(xml: string, name: string): string | null {\n const m = new RegExp(`<(?:[A-Za-z0-9_]+:)?${name}(?:\\\\s[^>]*)?>([\\\\s\\\\S]*?)</(?:[A-Za-z0-9_]+:)?${name}>`).exec(xml);\n return m ? m[1] : null;\n}\n\nfunction xmlEscape(s: string): string {\n return s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\").replace(/'/g, \"&apos;\");\n}\n\nfunction parseSsdp(text: string): URL | null {\n let location: string | null = null;\n let gateway = false;\n for (const line of text.split(/\\r?\\n/)) {\n const i = line.indexOf(\":\");\n if (i < 0) continue;\n const name = line.slice(0, i).trim().toLowerCase();\n const value = line.slice(i + 1).trim();\n if (name === \"location\") location = value;\n if ((name === \"st\" || name === \"usn\") && /InternetGatewayDevice|WANIPConnection/.test(value)) gateway = true;\n }\n if (!gateway || !location) return null;\n try {\n return new URL(location);\n } catch {\n return null;\n }\n}\n\n/**\n * Each IPv4 interface address, with its gateway when one can be guessed. Node's `os` does not report gateways, so the\n * gateway is the interface's .1 (true for nearly every home router); the SSDP multicast does not depend on it.\n */\nfunction gatewayInterfaces(): { local: string; gateway: string | null }[] {\n const out: { local: string; gateway: string | null }[] = [];\n for (const addrs of Object.values(networkInterfaces())) {\n for (const a of addrs ?? []) {\n if (a.family !== \"IPv4\" || a.internal || a.address.startsWith(\"169.254.\")) continue;\n const ip = a.address.split(\".\").map(Number);\n const mask = a.netmask.split(\".\").map(Number);\n const net = ip.map((x, i) => x & mask[i]);\n out.push({ local: a.address, gateway: mask[3] === 255 ? null : `${net[0]}.${net[1]}.${net[2]}.${net[3] + 1}` });\n }\n }\n return out;\n}\n\n/** The IPv4 default gateway from the OS route table (Windows `route print`, else `ip route`); null if it will not say. */\nfunction defaultGatewayFallback(): Promise<string | null> {\n return new Promise((resolve) => {\n const win = process.platform === \"win32\";\n execFile(win ? \"route\" : \"ip\", win ? [\"print\", \"0.0.0.0\"] : [\"route\", \"show\", \"default\"], { timeout: 2000 }, (err, stdout) => {\n if (err) return resolve(null);\n const m = win ? /0\\.0\\.0\\.0\\s+0\\.0\\.0\\.0\\s+(\\d+\\.\\d+\\.\\d+\\.\\d+)/.exec(stdout) : /default via (\\d+\\.\\d+\\.\\d+\\.\\d+)/.exec(stdout);\n resolve(m ? m[1] : null);\n });\n });\n}\n\n/** The local IPv4 the OS would use to reach `host` (a connected UDP socket sends nothing). */\nfunction localAddressToward(host: string, port: number): Promise<string> {\n return new Promise((resolve, reject) => {\n const s = createSocket(\"udp4\");\n s.on(\"error\", (e) => {\n s.close();\n reject(e);\n });\n s.connect(port, host, () => {\n const a = s.address().address;\n s.close();\n resolve(a);\n });\n });\n}\n\n/** The IPv4 a same-network join code carries when the router was not found (see C#'s DirectAddress.LanIPv4). */\nexport async function lanIPv4(): Promise<string | null> {\n try {\n const a = await localAddressToward(\"192.0.2.1\", 9); // TEST-NET-1: routed like the internet, never contacted\n if (a && a !== \"0.0.0.0\" && !a.startsWith(\"127.\")) return a;\n } catch {\n /* no default route: offline LAN party, look at the interfaces instead */\n }\n return gatewayInterfaces()[0]?.local ?? null;\n}\n\n/** This machine's addresses with the port, IPv4 first, for an \"Advanced\" fold-out on the host screen. */\nexport function localAddresses(port: number): string[] {\n const v4: string[] = [];\n const v6: string[] = [];\n for (const addrs of Object.values(networkInterfaces())) {\n for (const a of addrs ?? []) {\n if (a.internal) continue;\n if (a.family === \"IPv4\" && !a.address.startsWith(\"169.254.\")) v4.push(`${a.address}:${port}`);\n else if (a.family === \"IPv6\" && !/^fe80:/i.test(a.address) && !/^ff/i.test(a.address)) v6.push(`[${a.address}]:${port}`);\n }\n }\n return [...v4, ...v6];\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms).unref?.());\n}\n"]}
1
+ {"version":3,"file":"portmap.js","sourceRoot":"","sources":["../../src/direct/portmap.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference types=\"node\" />\nimport { createSocket, type Socket as UdpSocket } from \"node:dgram\";\nimport { request as httpRequest } from \"node:http\";\nimport { networkInterfaces } from \"node:os\";\nimport { execFile } from \"node:child_process\";\n\nexport type PortMapMethod = \"none\" | \"upnp\" | \"natpmp\";\n\n/** What {@link PortMapper.open} found. `mapped` means TCP and UDP `port` both forward here. */\nexport interface PortMapResult {\n mapped: boolean;\n method: PortMapMethod;\n /** The router's WAN address as it reports it (may itself be private or carrier-grade NAT). */\n externalIPv4: string | null;\n /** This PC's address on the router's network, when the router was found. */\n localIPv4: string | null;\n /** Why nothing was mapped, for logs. */\n detail: string;\n}\n\n/** Seams for tests (a fake gateway on loopback) and the few knobs a game might want. Same as C#'s PortMapperOptions. */\nexport interface PortMapperOptions {\n /** Where the SSDP M-SEARCH goes; default the UPnP multicast group 239.255.255.250:1900. */\n ssdp?: { address: string; port: number };\n /** NAT-PMP server; default this PC's IPv4 default gateway, port 5351. */\n natPmp?: { address: string; port: number };\n discoveryTimeoutMs?: number;\n requestTimeoutMs?: number;\n /** Lease asked for; renewed at half of it while hosting. Routers that only allow permanent leases get 0. */\n leaseSeconds?: number;\n description?: string;\n tryUpnp?: boolean;\n tryNatPmp?: boolean;\n /**\n * `hostDirect` only: when nothing was mapped, ask the router again after this many ms, doubling up to 5 minutes, until\n * it answers or the host quits (a router still booting after a power cut, UPnP switched back on). Default 30000; 0 never.\n */\n retryMs?: number;\n /**\n * Optional log hook; left out (default) stays quiet. Gets one line when the host quits and its mappings are deleted:\n * `direct host mapping deleted port=47810 protocols=TCP,UDP mapping=UPnP`.\n */\n log?: (line: string) => void;\n}\n\nconst SEARCH_TARGETS = [\n \"urn:schemas-upnp-org:device:InternetGatewayDevice:1\",\n \"urn:schemas-upnp-org:device:InternetGatewayDevice:2\",\n \"urn:schemas-upnp-org:service:WANIPConnection:1\",\n];\nconst SERVICE_TYPES = [\n \"urn:schemas-upnp-org:service:WANIPConnection:2\",\n \"urn:schemas-upnp-org:service:WANIPConnection:1\",\n \"urn:schemas-upnp-org:service:WANPPPConnection:1\",\n];\n\nclass UpnpError extends Error {\n constructor(readonly code: number, message: string) {\n super(message);\n }\n}\n\n/**\n * Opens TCP and UDP `port` on the home router for a direct-IP host (docs/design/direct-ip.md s.2a): UPnP IGD (SSDP, then\n * GetExternalIPAddress + AddPortMapping), then NAT-PMP (RFC 6886). Node twin of C#'s `PortMapper`, same order and rules:\n * same external and internal port or nothing (a join code carries one port), leases renew at half-life, {@link close}\n * deletes the mappings. Windows Firewall drops SSDP replies on a network marked Public; the result is then unmapped.\n */\nexport class PortMapper {\n result: PortMapResult | null = null;\n private readonly o: Required<Omit<PortMapperOptions, \"natPmp\" | \"log\">> & Pick<PortMapperOptions, \"natPmp\" | \"log\">;\n private control: URL | null = null;\n private service = \"\";\n private lease = 0;\n private natPmpAt: { address: string; port: number } | null = null;\n private renew: ReturnType<typeof setInterval> | null = null;\n private stopped = false;\n private opening: Promise<PortMapResult> | null = null;\n /**\n * Every mapping a request was sent for and the router did not refuse (\"upnp TCP\", \"pmp 1\", ...): what close()\n * deletes. Added before the request goes out, so a host that quits mid-request still undoes it.\n */\n private readonly maybeMapped = new Set<string>();\n\n constructor(readonly port: number, options: PortMapperOptions = {}) {\n if (!Number.isInteger(port) || port < 1 || port > 65535) throw new RangeError(`bad port ${port}`);\n this.o = {\n ssdp: { address: \"239.255.255.250\", port: 1900 },\n discoveryTimeoutMs: 2000,\n requestTimeoutMs: 3000,\n leaseSeconds: 7200,\n description: \"OneLobby\",\n tryUpnp: true,\n tryNatPmp: true,\n retryMs: 30000,\n ...options,\n };\n }\n\n /** True once {@link close} ran: no more requests go out. */\n get closed(): boolean {\n return this.stopped;\n }\n\n /** Finds the router and maps TCP + UDP `port`. Never rejects for network trouble: see `detail`. May run again after an unmapped result. */\n open(): Promise<PortMapResult> {\n return (this.opening = this.openBoth());\n }\n\n private async openBoth(): Promise<PortMapResult> {\n const notes: string[] = [];\n if (this.o.tryUpnp) {\n try {\n const r = await this.tryUpnp();\n if (r) return this.done(r);\n notes.push(\"no UPnP gateway answered\");\n } catch (e) {\n notes.push(`UPnP: ${(e as Error).message}`);\n }\n }\n if (this.o.tryNatPmp) {\n try {\n const r = await this.tryNatPmp();\n if (r) return this.done(r);\n notes.push(\"no NAT-PMP answer\");\n } catch (e) {\n notes.push(`NAT-PMP: ${(e as Error).message}`);\n }\n }\n return (this.result = { mapped: false, method: \"none\", externalIPv4: null, localIPv4: null, detail: notes.join(\"; \") });\n }\n\n private done(r: PortMapResult): PortMapResult {\n this.result = r;\n if (r.mapped && !this.stopped && (this.lease > 0 || r.method === \"natpmp\")) {\n const everyMs = Math.max(30, (this.lease > 0 ? this.lease : this.o.leaseSeconds) / 2) * 1000;\n this.renew = setInterval(() => {\n const p = r.method === \"upnp\" ? this.addUpnpBoth(r.localIPv4!, this.lease) : this.natPmpMapBoth(this.o.leaseSeconds);\n p.catch(() => {}); // the next round tries again; the old lease still has half its life\n }, everyMs);\n this.renew.unref?.();\n }\n return r;\n }\n\n // ------------------------------------------------------------------------------------------------ UPnP IGD\n\n private async tryUpnp(): Promise<PortMapResult | null> {\n const location = await this.discover();\n if (!location) return null;\n const desc = await this.http(\"GET\", location, null, {});\n const baseText = tag(desc.body, \"URLBase\");\n const base = baseText && /^https?:\\/\\//i.test(baseText) ? new URL(baseText) : location;\n for (const type of SERVICE_TYPES) {\n for (const svc of desc.body.match(/<service>[\\s\\S]*?<\\/service>/g) ?? []) {\n if ((tag(svc, \"serviceType\") ?? \"\").trim() !== type) continue;\n const ctl = tag(svc, \"controlURL\")?.trim();\n if (!ctl) continue;\n this.control = new URL(ctl, base);\n this.service = type;\n break;\n }\n if (this.control) break;\n }\n if (!this.control) return { mapped: false, method: \"upnp\", externalIPv4: null, localIPv4: null, detail: \"UPnP gateway has no WANIPConnection service\" };\n\n const local = await localAddressToward(this.control.hostname, Number(this.control.port) || 80);\n let external: string | null = null;\n try {\n external = tag((await this.soap(\"GetExternalIPAddress\", [])).body, \"NewExternalIPAddress\")?.trim() ?? null;\n } catch (e) {\n if (!(e instanceof UpnpError)) throw e; // some routers refuse this but still map\n }\n this.lease = this.o.leaseSeconds;\n try {\n await this.addUpnpBoth(local, this.lease);\n } catch (e) {\n if (!(e instanceof UpnpError)) throw e;\n if (e.code === 725) {\n // OnlyPermanentLeasesSupported\n this.lease = 0;\n await this.addUpnpBoth(local, 0);\n } else return { mapped: false, method: \"upnp\", externalIPv4: external, localIPv4: local, detail: `UPnP ${e.message}` };\n }\n return { mapped: true, method: \"upnp\", externalIPv4: external, localIPv4: local, detail: \"UPnP\" };\n }\n\n private async addUpnpBoth(local: string, lease: number): Promise<void> {\n for (const proto of [\"TCP\", \"UDP\"]) {\n if (this.stopped) throw new Error(\"closed before the router answered\");\n const key = `upnp ${proto}`;\n this.maybeMapped.add(key);\n try {\n await this.soap(\"AddPortMapping\", [\n [\"NewRemoteHost\", \"\"], [\"NewExternalPort\", String(this.port)], [\"NewProtocol\", proto], [\"NewInternalPort\", String(this.port)],\n [\"NewInternalClient\", local], [\"NewEnabled\", \"1\"], [\"NewPortMappingDescription\", this.o.description], [\"NewLeaseDuration\", String(lease)],\n ]);\n } catch (e) {\n // refused (e.g. 718: another device holds the port): not ours, so close() must not delete it\n if (e instanceof UpnpError) this.maybeMapped.delete(key);\n throw e;\n }\n // close() ran while this request was out: its delete may have reached the router first, so undo it now\n if (this.stopped) await this.undo([key]);\n }\n }\n\n /**\n * SSDP search: multicast once per interface that has a gateway (so a Hyper-V, WSL or Docker adapter cannot swallow\n * it), plus a unicast copy to the gateway.\n */\n private discover(): Promise<URL | null> {\n const multicast = Number(this.o.ssdp.address.split(\".\")[0]) >= 224;\n const locals = multicast ? gatewayInterfaces() : [];\n if (locals.length === 0) locals.push({ local: \"0.0.0.0\", gateway: null });\n return new Promise((resolve) => {\n const sockets: UdpSocket[] = [];\n let finished = false;\n const finish = (u: URL | null) => {\n if (finished) return;\n finished = true;\n clearTimeout(timer);\n for (const s of sockets) s.close();\n resolve(u);\n };\n const timer = setTimeout(() => finish(null), this.o.discoveryTimeoutMs);\n for (const { local, gateway } of locals) {\n const s = createSocket({ type: \"udp4\", reuseAddr: false });\n sockets.push(s);\n s.on(\"error\", () => {});\n s.on(\"message\", (m) => {\n const u = parseSsdp(m.toString(\"latin1\"));\n if (u) finish(u);\n });\n s.bind(0, local === \"0.0.0.0\" ? undefined : local, () => {\n try {\n s.setMulticastTTL(2);\n if (local !== \"0.0.0.0\") s.setMulticastInterface(local);\n } catch {\n /* not fatal: the OS default interface is used */\n }\n for (const st of SEARCH_TARGETS) {\n const b = Buffer.from(`M-SEARCH * HTTP/1.1\\r\\nHOST: 239.255.255.250:1900\\r\\nMAN: \"ssdp:discover\"\\r\\nMX: 1\\r\\nST: ${st}\\r\\n\\r\\n`);\n s.send(b, this.o.ssdp.port, this.o.ssdp.address, () => {});\n if (gateway) s.send(b, 1900, gateway, () => {});\n }\n });\n }\n });\n }\n\n private async soap(action: string, args: [string, string][]): Promise<{ status: number; body: string }> {\n const inner = args.map(([k, v]) => `<${k}>${xmlEscape(v)}</${k}>`).join(\"\");\n const body =\n `<?xml version=\"1.0\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">` +\n `<s:Body><u:${action} xmlns:u=\"${this.service}\">${inner}</u:${action}></s:Body></s:Envelope>`;\n const res = await this.http(\"POST\", this.control!, body, { \"Content-Type\": 'text/xml; charset=\"utf-8\"', SOAPAction: `\"${this.service}#${action}\"` });\n if (res.status < 200 || res.status >= 300) {\n const code = tag(res.body, \"errorCode\");\n const desc = tag(res.body, \"errorDescription\") ?? \"\";\n throw new UpnpError(Number(code) || 0, `${action} error ${code ?? res.status} ${desc}`.trim());\n }\n return res;\n }\n\n /**\n * One connection per request: some routers close after each reply without saying so, and a reused\n * keep-alive socket then fails every second request with \"socket hang up\".\n */\n private http(method: string, url: URL, body: string | null, headers: Record<string, string>): Promise<{ status: number; body: string }> {\n return new Promise((resolve, reject) => {\n const h = { ...headers, Connection: \"close\" };\n const req = httpRequest(\n { method, hostname: url.hostname, port: url.port || 80, path: url.pathname + url.search, timeout: this.o.requestTimeoutMs, agent: false,\n headers: body === null ? h : { ...h, \"Content-Length\": Buffer.byteLength(body) } },\n (res) => {\n let text = \"\";\n res.setEncoding(\"utf8\");\n res.on(\"data\", (d) => (text += d));\n res.on(\"end\", () => resolve({ status: res.statusCode ?? 0, body: text }));\n },\n );\n req.on(\"timeout\", () => req.destroy(new Error(`${method} ${url.pathname} timed out`)));\n req.on(\"error\", reject);\n if (body !== null) req.write(body);\n req.end();\n });\n }\n\n // ------------------------------------------------------------------------------------------------ NAT-PMP\n\n private async tryNatPmp(): Promise<PortMapResult | null> {\n // One gateway only: each silent one costs the full retransmission budget.\n let gw0 = this.o.natPmp ?? null;\n if (!gw0) {\n const routed = (await defaultGatewayFallback()) ?? gatewayInterfaces().find((g) => g.gateway)?.gateway ?? null;\n if (routed) gw0 = { address: routed, port: 5351 };\n }\n const candidates = gw0 ? [gw0] : [];\n for (const gw of candidates) {\n const ext = await this.natPmpRequest(gw, Buffer.from([0, 0]), 12);\n if (!ext) continue;\n this.natPmpAt = gw;\n const local = await localAddressToward(gw.address, gw.port);\n const external = ext.readUInt16BE(2) === 0 ? `${ext[8]}.${ext[9]}.${ext[10]}.${ext[11]}` : null;\n const err = await this.natPmpMapBoth(this.o.leaseSeconds);\n if (err) return { mapped: false, method: \"natpmp\", externalIPv4: external, localIPv4: local, detail: `NAT-PMP ${err}` };\n return { mapped: true, method: \"natpmp\", externalIPv4: external, localIPv4: local, detail: \"NAT-PMP\" };\n }\n return null;\n }\n\n /** Maps UDP then TCP; null on success, else why. A different external port counts as failure (and is undone). */\n private async natPmpMapBoth(lifetime: number): Promise<string | null> {\n for (const op of [1, 2]) {\n if (this.stopped) return \"closed before the router answered\";\n const key = `pmp ${op}`;\n this.maybeMapped.add(key);\n const reply = await this.natPmpRequest(this.natPmpAt!, this.mapRequest(op, lifetime), 16);\n if (this.stopped) await this.undo([key]);\n if (!reply) return \"no answer to the mapping request\";\n const rc = reply.readUInt16BE(2);\n if (rc !== 0) {\n this.maybeMapped.delete(key);\n return `result code ${rc}`;\n }\n const mapped = reply.readUInt16BE(10);\n if (lifetime > 0 && mapped !== this.port) {\n await this.natPmpRequest(this.natPmpAt!, this.mapRequest(op, 0), 16);\n this.maybeMapped.delete(key);\n return `router offered port ${mapped} instead of ${this.port}`;\n }\n }\n return null;\n }\n\n private mapRequest(op: number, lifetime: number): Buffer {\n const b = Buffer.alloc(12);\n b[1] = op;\n b.writeUInt16BE(this.port, 4);\n b.writeUInt16BE(lifetime > 0 ? this.port : 0, 6);\n b.writeUInt32BE(lifetime, 8);\n return b;\n }\n\n /** RFC 6886 s.3.1 retransmission: 250 ms, doubling, 3 tries (under 2 s). Null when nobody answers. */\n private natPmpRequest(to: { address: string; port: number }, req: Buffer, replyLength: number): Promise<Buffer | null> {\n return new Promise((resolve) => {\n const s = createSocket(\"udp4\");\n let wait = 250;\n let tries = 0;\n let timer: ReturnType<typeof setTimeout> | null = null;\n const finish = (b: Buffer | null) => {\n if (timer) clearTimeout(timer);\n s.close();\n resolve(b);\n };\n s.on(\"error\", () => {}); // ICMP port unreachable on Windows: keep waiting for the timer\n s.on(\"message\", (b) => {\n if (b.length >= replyLength && b[0] === 0 && b[1] === req[1] + 128) finish(b);\n });\n const attempt = () => {\n if (tries++ >= 3) return finish(null);\n s.send(req, to.port, to.address, () => {});\n timer = setTimeout(attempt, wait);\n wait *= 2;\n };\n s.bind(0, attempt);\n });\n }\n\n /**\n * Stops renewing and deletes every mapping it may have made, even while {@link open} is still talking to the router\n * (best effort, bounded to about two seconds; a request still out when it returns undoes itself when it lands).\n */\n async close(): Promise<void> {\n if (this.stopped) return;\n this.stopped = true;\n if (this.renew) clearInterval(this.renew);\n if (this.opening) await Promise.race([this.opening.catch(() => {}), delay(500)]);\n await this.undo([...this.maybeMapped]);\n }\n\n private async undo(keys: string[]): Promise<void> {\n if (keys.length === 0) return;\n const work = Promise.all(\n keys.map((k) => {\n this.maybeMapped.delete(k);\n return k.startsWith(\"upnp \")\n ? this.soap(\"DeletePortMapping\", [[\"NewRemoteHost\", \"\"], [\"NewExternalPort\", String(this.port)], [\"NewProtocol\", k.slice(5)]])\n : this.natPmpOnce(this.mapRequest(Number(k.slice(4)), 0));\n }),\n );\n await Promise.race([work.catch(() => {}), delay(1500)]);\n this.logDeleted(keys);\n }\n\n /** One line per mapping kind, e.g. `direct host mapping deleted port=47810 protocols=TCP,UDP mapping=UPnP`. */\n private logDeleted(keys: string[]): void {\n if (!this.o.log) return;\n for (const upnp of [true, false]) {\n const mine = keys.filter((k) => k.startsWith(\"upnp \") === upnp);\n if (mine.length === 0) continue;\n const protos = [...new Set(mine.map((k) => (upnp ? k.slice(5) : k === \"pmp 2\" ? \"TCP\" : \"UDP\")))].sort();\n try {\n this.o.log(`direct host mapping deleted port=${this.port} protocols=${protos.join(\",\")} mapping=${upnp ? \"UPnP\" : \"NAT-PMP\"}`);\n } catch {\n // a game's logger must not stop the quit\n }\n }\n }\n\n private natPmpOnce(req: Buffer): Promise<void> {\n return new Promise((resolve) => {\n const s = createSocket(\"udp4\");\n s.on(\"error\", () => {});\n s.send(req, this.natPmpAt!.port, this.natPmpAt!.address, () => {\n s.close();\n resolve();\n });\n });\n }\n}\n\n// ------------------------------------------------------------------------------------------------ helpers\n\n/**\n * True for an address the internet can route to: not private (RFC 1918), carrier-grade NAT (100.64/10), loopback,\n * link-local, 0/8, or multicast/reserved (224+). A router that reports a non-public WAN address is itself behind NAT.\n */\nexport function isPublicIPv4(address: string | null | undefined): boolean {\n if (!address) return false;\n const m = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.exec(address);\n if (!m) return false;\n const [a, b] = [Number(m[1]), Number(m[2])];\n if (m.slice(1).some((x) => Number(x) > 255)) return false;\n if (a === 0 || a === 10 || a === 127 || a >= 224) return false;\n if (a === 100 && b >= 64 && b < 128) return false;\n if (a === 169 && b === 254) return false;\n if (a === 172 && b >= 16 && b < 32) return false;\n if (a === 192 && b === 168) return false;\n return true;\n}\n\nfunction tag(xml: string, name: string): string | null {\n const m = new RegExp(`<(?:[A-Za-z0-9_]+:)?${name}(?:\\\\s[^>]*)?>([\\\\s\\\\S]*?)</(?:[A-Za-z0-9_]+:)?${name}>`).exec(xml);\n return m ? m[1] : null;\n}\n\nfunction xmlEscape(s: string): string {\n return s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\").replace(/'/g, \"&apos;\");\n}\n\nfunction parseSsdp(text: string): URL | null {\n let location: string | null = null;\n let gateway = false;\n for (const line of text.split(/\\r?\\n/)) {\n const i = line.indexOf(\":\");\n if (i < 0) continue;\n const name = line.slice(0, i).trim().toLowerCase();\n const value = line.slice(i + 1).trim();\n if (name === \"location\") location = value;\n if ((name === \"st\" || name === \"usn\") && /InternetGatewayDevice|WANIPConnection/.test(value)) gateway = true;\n }\n if (!gateway || !location) return null;\n try {\n return new URL(location);\n } catch {\n return null;\n }\n}\n\n/**\n * Each IPv4 interface address, with its gateway when one can be guessed. Node's `os` does not report gateways, so the\n * gateway is the interface's .1 (true for nearly every home router); the SSDP multicast does not depend on it.\n */\nfunction gatewayInterfaces(): { local: string; gateway: string | null }[] {\n const out: { local: string; gateway: string | null }[] = [];\n for (const addrs of Object.values(networkInterfaces())) {\n for (const a of addrs ?? []) {\n if (a.family !== \"IPv4\" || a.internal || a.address.startsWith(\"169.254.\")) continue;\n const ip = a.address.split(\".\").map(Number);\n const mask = a.netmask.split(\".\").map(Number);\n const net = ip.map((x, i) => x & mask[i]);\n out.push({ local: a.address, gateway: mask[3] === 255 ? null : `${net[0]}.${net[1]}.${net[2]}.${net[3] + 1}` });\n }\n }\n return out;\n}\n\n/** The IPv4 default gateway from the OS route table (Windows `route print`, else `ip route`); null if it will not say. */\nfunction defaultGatewayFallback(): Promise<string | null> {\n return new Promise((resolve) => {\n const win = process.platform === \"win32\";\n execFile(win ? \"route\" : \"ip\", win ? [\"print\", \"0.0.0.0\"] : [\"route\", \"show\", \"default\"], { timeout: 2000 }, (err, stdout) => {\n if (err) return resolve(null);\n const m = win ? /0\\.0\\.0\\.0\\s+0\\.0\\.0\\.0\\s+(\\d+\\.\\d+\\.\\d+\\.\\d+)/.exec(stdout) : /default via (\\d+\\.\\d+\\.\\d+\\.\\d+)/.exec(stdout);\n resolve(m ? m[1] : null);\n });\n });\n}\n\n/** The local IPv4 the OS would use to reach `host` (a connected UDP socket sends nothing). */\nfunction localAddressToward(host: string, port: number): Promise<string> {\n return new Promise((resolve, reject) => {\n const s = createSocket(\"udp4\");\n s.on(\"error\", (e) => {\n s.close();\n reject(e);\n });\n s.connect(port, host, () => {\n const a = s.address().address;\n s.close();\n resolve(a);\n });\n });\n}\n\n/** The IPv4 a same-network join code carries when the router was not found (see C#'s DirectAddress.LanIPv4). */\nexport async function lanIPv4(): Promise<string | null> {\n try {\n const a = await localAddressToward(\"192.0.2.1\", 9); // TEST-NET-1: routed like the internet, never contacted\n if (a && a !== \"0.0.0.0\" && !a.startsWith(\"127.\")) return a;\n } catch {\n /* no default route: offline LAN party, look at the interfaces instead */\n }\n return gatewayInterfaces()[0]?.local ?? null;\n}\n\n/** This machine's addresses with the port, IPv4 first, for an \"Advanced\" fold-out on the host screen. */\nexport function localAddresses(port: number): string[] {\n const v4: string[] = [];\n const v6: string[] = [];\n for (const addrs of Object.values(networkInterfaces())) {\n for (const a of addrs ?? []) {\n if (a.internal) continue;\n if (a.family === \"IPv4\" && !a.address.startsWith(\"169.254.\")) v4.push(`${a.address}:${port}`);\n else if (a.family === \"IPv6\" && !/^fe80:/i.test(a.address) && !/^ff/i.test(a.address)) v6.push(`[${a.address}]:${port}`);\n }\n }\n return [...v4, ...v6];\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms).unref?.());\n}\n"]}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Small synchronous SHA-1 / HMAC-SHA1 and CSPRNG helpers for the signaling hub, so it runs in a browser tab as well as
3
+ * in Node (WebCrypto's digests are async and the hub is sync). SHA-1 is used only for the TURN credential
4
+ * (`base64(HMAC-SHA1(secret, "expiry:connId"))`, coturn's REST scheme) and for hashing client addresses in log lines.
5
+ */
6
+ export declare function sha1(data: Uint8Array): Uint8Array;
7
+ export declare function hmacSha1(key: Uint8Array, msg: Uint8Array): Uint8Array;
8
+ export declare function toHex(b: Uint8Array): string;
9
+ /** `base64(HMAC-SHA1(secret, username))`, the TURN REST credential. */
10
+ export declare function turnCredential(secret: string, username: string): string;
11
+ /** First 8 hex chars of SHA-1 over `text`: a short stable tag for log lines (not a security feature). */
12
+ export declare function shortHash(text: string): string;
13
+ /** `n` random bytes as lowercase hex, from the platform CSPRNG. */
14
+ export declare function randomHex(n: number): string;
15
+ /** Uniform integer in [0, n) from the platform CSPRNG (rejection sampling, no modulo bias). */
16
+ export declare function randomBelow(n: number): number;
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Small synchronous SHA-1 / HMAC-SHA1 and CSPRNG helpers for the signaling hub, so it runs in a browser tab as well as
3
+ * in Node (WebCrypto's digests are async and the hub is sync). SHA-1 is used only for the TURN credential
4
+ * (`base64(HMAC-SHA1(secret, "expiry:connId"))`, coturn's REST scheme) and for hashing client addresses in log lines.
5
+ */
6
+ const enc = new TextEncoder();
7
+ export function sha1(data) {
8
+ const h = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];
9
+ const len = data.length;
10
+ const padded = new Uint8Array((((len + 8) >> 6) << 6) + 64);
11
+ padded.set(data);
12
+ padded[len] = 0x80;
13
+ const dv = new DataView(padded.buffer);
14
+ dv.setUint32(padded.length - 8, Math.floor((len * 8) / 0x100000000));
15
+ dv.setUint32(padded.length - 4, (len * 8) >>> 0);
16
+ const w = new Uint32Array(80);
17
+ for (let off = 0; off < padded.length; off += 64) {
18
+ for (let i = 0; i < 16; i++)
19
+ w[i] = dv.getUint32(off + i * 4);
20
+ for (let i = 16; i < 80; i++) {
21
+ const x = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16];
22
+ w[i] = (x << 1) | (x >>> 31);
23
+ }
24
+ let [a, b, c, d, e] = h;
25
+ for (let i = 0; i < 80; i++) {
26
+ let f;
27
+ let k;
28
+ if (i < 20) {
29
+ f = (b & c) | (~b & d);
30
+ k = 0x5a827999;
31
+ }
32
+ else if (i < 40) {
33
+ f = b ^ c ^ d;
34
+ k = 0x6ed9eba1;
35
+ }
36
+ else if (i < 60) {
37
+ f = (b & c) | (b & d) | (c & d);
38
+ k = 0x8f1bbcdc;
39
+ }
40
+ else {
41
+ f = b ^ c ^ d;
42
+ k = 0xca62c1d6;
43
+ }
44
+ const t = (((a << 5) | (a >>> 27)) + f + e + k + w[i]) | 0;
45
+ e = d;
46
+ d = c;
47
+ c = (b << 30) | (b >>> 2);
48
+ b = a;
49
+ a = t;
50
+ }
51
+ h[0] = (h[0] + a) | 0;
52
+ h[1] = (h[1] + b) | 0;
53
+ h[2] = (h[2] + c) | 0;
54
+ h[3] = (h[3] + d) | 0;
55
+ h[4] = (h[4] + e) | 0;
56
+ }
57
+ const out = new Uint8Array(20);
58
+ const odv = new DataView(out.buffer);
59
+ for (let i = 0; i < 5; i++)
60
+ odv.setUint32(i * 4, h[i] >>> 0);
61
+ return out;
62
+ }
63
+ export function hmacSha1(key, msg) {
64
+ const k = key.length > 64 ? sha1(key) : key;
65
+ const ipad = new Uint8Array(64 + msg.length);
66
+ const opad = new Uint8Array(84);
67
+ for (let i = 0; i < 64; i++) {
68
+ const kb = i < k.length ? k[i] : 0;
69
+ ipad[i] = kb ^ 0x36;
70
+ opad[i] = kb ^ 0x5c;
71
+ }
72
+ ipad.set(msg, 64);
73
+ opad.set(sha1(ipad), 64);
74
+ return sha1(opad);
75
+ }
76
+ export function toHex(b) {
77
+ let s = "";
78
+ for (const x of b)
79
+ s += x.toString(16).padStart(2, "0");
80
+ return s;
81
+ }
82
+ function toBase64(b) {
83
+ let s = "";
84
+ for (const x of b)
85
+ s += String.fromCharCode(x);
86
+ return btoa(s);
87
+ }
88
+ /** `base64(HMAC-SHA1(secret, username))`, the TURN REST credential. */
89
+ export function turnCredential(secret, username) {
90
+ return toBase64(hmacSha1(enc.encode(secret), enc.encode(username)));
91
+ }
92
+ /** First 8 hex chars of SHA-1 over `text`: a short stable tag for log lines (not a security feature). */
93
+ export function shortHash(text) {
94
+ return toHex(sha1(enc.encode(text))).slice(0, 8);
95
+ }
96
+ /** `n` random bytes as lowercase hex, from the platform CSPRNG. */
97
+ export function randomHex(n) {
98
+ return toHex(globalThis.crypto.getRandomValues(new Uint8Array(n)));
99
+ }
100
+ /** Uniform integer in [0, n) from the platform CSPRNG (rejection sampling, no modulo bias). */
101
+ export function randomBelow(n) {
102
+ const range = 0x100000000;
103
+ const limit = range - (range % n);
104
+ const buf = new Uint32Array(1);
105
+ for (;;) {
106
+ globalThis.crypto.getRandomValues(buf);
107
+ if (buf[0] < limit)
108
+ return buf[0] % n;
109
+ }
110
+ }
111
+ //# sourceMappingURL=sha1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sha1.js","sourceRoot":"","sources":["../../src/direct/sha1.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Small synchronous SHA-1 / HMAC-SHA1 and CSPRNG helpers for the signaling hub, so it runs in a browser tab as well as\n * in Node (WebCrypto's digests are async and the hub is sync). SHA-1 is used only for the TURN credential\n * (`base64(HMAC-SHA1(secret, \"expiry:connId\"))`, coturn's REST scheme) and for hashing client addresses in log lines.\n */\n\nconst enc = new TextEncoder();\n\nexport function sha1(data: Uint8Array): Uint8Array {\n const h = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];\n const len = data.length;\n const padded = new Uint8Array((((len + 8) >> 6) << 6) + 64);\n padded.set(data);\n padded[len] = 0x80;\n const dv = new DataView(padded.buffer);\n dv.setUint32(padded.length - 8, Math.floor((len * 8) / 0x100000000));\n dv.setUint32(padded.length - 4, (len * 8) >>> 0);\n const w = new Uint32Array(80);\n for (let off = 0; off < padded.length; off += 64) {\n for (let i = 0; i < 16; i++) w[i] = dv.getUint32(off + i * 4);\n for (let i = 16; i < 80; i++) {\n const x = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16];\n w[i] = (x << 1) | (x >>> 31);\n }\n let [a, b, c, d, e] = h;\n for (let i = 0; i < 80; i++) {\n let f: number;\n let k: number;\n if (i < 20) { f = (b & c) | (~b & d); k = 0x5a827999; }\n else if (i < 40) { f = b ^ c ^ d; k = 0x6ed9eba1; }\n else if (i < 60) { f = (b & c) | (b & d) | (c & d); k = 0x8f1bbcdc; }\n else { f = b ^ c ^ d; k = 0xca62c1d6; }\n const t = (((a << 5) | (a >>> 27)) + f + e + k + w[i]) | 0;\n e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;\n }\n h[0] = (h[0] + a) | 0; h[1] = (h[1] + b) | 0; h[2] = (h[2] + c) | 0; h[3] = (h[3] + d) | 0; h[4] = (h[4] + e) | 0;\n }\n const out = new Uint8Array(20);\n const odv = new DataView(out.buffer);\n for (let i = 0; i < 5; i++) odv.setUint32(i * 4, h[i] >>> 0);\n return out;\n}\n\nexport function hmacSha1(key: Uint8Array, msg: Uint8Array): Uint8Array {\n const k = key.length > 64 ? sha1(key) : key;\n const ipad = new Uint8Array(64 + msg.length);\n const opad = new Uint8Array(84);\n for (let i = 0; i < 64; i++) {\n const kb = i < k.length ? k[i] : 0;\n ipad[i] = kb ^ 0x36;\n opad[i] = kb ^ 0x5c;\n }\n ipad.set(msg, 64);\n opad.set(sha1(ipad), 64);\n return sha1(opad);\n}\n\nexport function toHex(b: Uint8Array): string {\n let s = \"\";\n for (const x of b) s += x.toString(16).padStart(2, \"0\");\n return s;\n}\n\nfunction toBase64(b: Uint8Array): string {\n let s = \"\";\n for (const x of b) s += String.fromCharCode(x);\n return btoa(s);\n}\n\n/** `base64(HMAC-SHA1(secret, username))`, the TURN REST credential. */\nexport function turnCredential(secret: string, username: string): string {\n return toBase64(hmacSha1(enc.encode(secret), enc.encode(username)));\n}\n\n/** First 8 hex chars of SHA-1 over `text`: a short stable tag for log lines (not a security feature). */\nexport function shortHash(text: string): string {\n return toHex(sha1(enc.encode(text))).slice(0, 8);\n}\n\n/** `n` random bytes as lowercase hex, from the platform CSPRNG. */\nexport function randomHex(n: number): string {\n return toHex(globalThis.crypto.getRandomValues(new Uint8Array(n)));\n}\n\n/** Uniform integer in [0, n) from the platform CSPRNG (rejection sampling, no modulo bias). */\nexport function randomBelow(n: number): number {\n const range = 0x100000000;\n const limit = range - (range % n);\n const buf = new Uint32Array(1);\n for (;;) {\n globalThis.crypto.getRandomValues(buf);\n if (buf[0] < limit) return buf[0] % n;\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * A direct-IP host address as a player types it (docs/direct-ip.md s.3): `ip`, `ip:port`, `[v6]:port`, a bare IPv6
2
+ * A direct-IP host address as a player types it (docs/design/direct-ip.md s.3): `ip`, `ip:port`, `[v6]:port`, a bare IPv6
3
3
  * address or a host name (a virtual-LAN name, say). Same rules as OneLobby.Direct's `DirectAddress` in C#.
4
4
  */
5
5
  export interface DirectAddress {
@@ -12,7 +12,7 @@ export interface DirectAddress {
12
12
  url: string;
13
13
  /**
14
14
  * The address as a remote ICE host candidate (UDP, same port number as the TCP listener). Without it a joiner on the
15
- * internet only learns the host's private LAN addresses (docs/direct-ip.md s.2).
15
+ * internet only learns the host's private LAN addresses (docs/design/direct-ip.md s.2).
16
16
  */
17
17
  candidate: string;
18
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"direct-address.js","sourceRoot":"","sources":["../src/direct-address.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A direct-IP host address as a player types it (docs/direct-ip.md s.3): `ip`, `ip:port`, `[v6]:port`, a bare IPv6\n * address or a host name (a virtual-LAN name, say). Same rules as OneLobby.Direct's `DirectAddress` in C#.\n */\nexport interface DirectAddress {\n host: string;\n port: number;\n isIPv6: boolean;\n /** `host:port`, with brackets for IPv6. */\n display: string;\n /** The joiner's signaling URL: `ws://host:port/`. */\n url: string;\n /**\n * The address as a remote ICE host candidate (UDP, same port number as the TCP listener). Without it a joiner on the\n * internet only learns the host's private LAN addresses (docs/direct-ip.md s.2).\n */\n candidate: string;\n}\n\nexport const DEFAULT_DIRECT_PORT = 47810;\n\nconst IPV4 = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/;\nconst HOSTNAME = /^(?=.{1,253}$)([A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)(\\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;\n\nfunction isIPv4(s: string): boolean {\n const m = IPV4.exec(s);\n return !!m && m.slice(1).every((x) => Number(x) <= 255);\n}\n\nfunction isIPv6(s: string): boolean {\n if (!/^[0-9A-Fa-f:.]+$/.test(s) || s.split(\"::\").length > 2 || !s.includes(\":\")) return false;\n const tail = s.split(\":\").pop() ?? \"\";\n const groups = s.split(\":\").filter((g, i, a) => g !== \"\" || (i > 0 && i < a.length - 1));\n if (tail.includes(\".\") && !isIPv4(tail)) return false;\n return groups.every((g) => g === \"\" || g.includes(\".\") || /^[0-9A-Fa-f]{1,4}$/.test(g));\n}\n\nexport function parseDirectAddress(input: string, defaultPort = DEFAULT_DIRECT_PORT): DirectAddress | null {\n let s = input.trim();\n if (/^ws:\\/\\//i.test(s)) s = s.slice(5);\n s = s.replace(/\\/+$/, \"\");\n if (!s) return null;\n let host: string;\n let portText: string | null = null;\n if (s[0] === \"[\") {\n const close = s.indexOf(\"]\");\n if (close < 0) return null;\n host = s.slice(1, close);\n const rest = s.slice(close + 1);\n if (rest) {\n if (rest[0] !== \":\") return null;\n portText = rest.slice(1);\n }\n } else {\n const first = s.indexOf(\":\");\n if (first >= 0 && first === s.lastIndexOf(\":\")) {\n host = s.slice(0, first);\n portText = s.slice(first + 1);\n } else host = s; // no colon, or several (a bare IPv6 address)\n }\n let port = defaultPort;\n if (portText !== null) {\n if (!/^\\d{1,5}$/.test(portText)) return null;\n port = Number(portText);\n if (port < 1 || port > 65535) return null;\n }\n const v6 = isIPv6(host);\n if (!v6 && !isIPv4(host) && !HOSTNAME.test(host)) return null;\n const display = (v6 ? `[${host}]` : host) + `:${port}`;\n return { host, port, isIPv6: v6, display, url: `ws://${display}/`, candidate: `candidate:1 1 UDP 2122317823 ${host} ${port} typ host` };\n}\n"]}
1
+ {"version":3,"file":"direct-address.js","sourceRoot":"","sources":["../src/direct-address.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A direct-IP host address as a player types it (docs/design/direct-ip.md s.3): `ip`, `ip:port`, `[v6]:port`, a bare IPv6\n * address or a host name (a virtual-LAN name, say). Same rules as OneLobby.Direct's `DirectAddress` in C#.\n */\nexport interface DirectAddress {\n host: string;\n port: number;\n isIPv6: boolean;\n /** `host:port`, with brackets for IPv6. */\n display: string;\n /** The joiner's signaling URL: `ws://host:port/`. */\n url: string;\n /**\n * The address as a remote ICE host candidate (UDP, same port number as the TCP listener). Without it a joiner on the\n * internet only learns the host's private LAN addresses (docs/design/direct-ip.md s.2).\n */\n candidate: string;\n}\n\nexport const DEFAULT_DIRECT_PORT = 47810;\n\nconst IPV4 = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/;\nconst HOSTNAME = /^(?=.{1,253}$)([A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)(\\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;\n\nfunction isIPv4(s: string): boolean {\n const m = IPV4.exec(s);\n return !!m && m.slice(1).every((x) => Number(x) <= 255);\n}\n\nfunction isIPv6(s: string): boolean {\n if (!/^[0-9A-Fa-f:.]+$/.test(s) || s.split(\"::\").length > 2 || !s.includes(\":\")) return false;\n const tail = s.split(\":\").pop() ?? \"\";\n const groups = s.split(\":\").filter((g, i, a) => g !== \"\" || (i > 0 && i < a.length - 1));\n if (tail.includes(\".\") && !isIPv4(tail)) return false;\n return groups.every((g) => g === \"\" || g.includes(\".\") || /^[0-9A-Fa-f]{1,4}$/.test(g));\n}\n\nexport function parseDirectAddress(input: string, defaultPort = DEFAULT_DIRECT_PORT): DirectAddress | null {\n let s = input.trim();\n if (/^ws:\\/\\//i.test(s)) s = s.slice(5);\n s = s.replace(/\\/+$/, \"\");\n if (!s) return null;\n let host: string;\n let portText: string | null = null;\n if (s[0] === \"[\") {\n const close = s.indexOf(\"]\");\n if (close < 0) return null;\n host = s.slice(1, close);\n const rest = s.slice(close + 1);\n if (rest) {\n if (rest[0] !== \":\") return null;\n portText = rest.slice(1);\n }\n } else {\n const first = s.indexOf(\":\");\n if (first >= 0 && first === s.lastIndexOf(\":\")) {\n host = s.slice(0, first);\n portText = s.slice(first + 1);\n } else host = s; // no colon, or several (a bare IPv6 address)\n }\n let port = defaultPort;\n if (portText !== null) {\n if (!/^\\d{1,5}$/.test(portText)) return null;\n port = Number(portText);\n if (port < 1 || port > 65535) return null;\n }\n const v6 = isIPv6(host);\n if (!v6 && !isIPv4(host) && !HOSTNAME.test(host)) return null;\n const display = (v6 ? `[${host}]` : host) + `:${port}`;\n return { host, port, isIPv6: v6, display, url: `ws://${display}/`, candidate: `candidate:1 1 UDP 2122317823 ${host} ${port} typ host` };\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import type { IpCodeKind, JoinCodeKind } from "./join-code-kind.js";
1
2
  export interface FriendlyError {
2
3
  /** Stable machine code (the OneLobbyError code, or "unknown"). */
3
4
  code: string;
@@ -30,15 +31,20 @@ export declare const ErrorCodes: {
30
31
  readonly DirectUnreachable: "direct_unreachable";
31
32
  readonly BadAddress: "bad_address";
32
33
  readonly PortInUse: "port_in_use";
34
+ readonly Unsupported: "unsupported";
33
35
  readonly ConnectFailed: "connect_failed";
34
36
  readonly Closed: "closed";
35
37
  readonly ServerLost: "server_lost";
36
38
  readonly InvalidToken: "invalid_token";
37
39
  readonly NoServer: "no_server";
40
+ readonly NotInGame: "not_in_game";
41
+ readonly NotAllowed: "not_allowed";
38
42
  readonly BadConfig: "bad_config";
39
43
  readonly VoiceDisabled: "voice_disabled";
40
44
  readonly ChatDisabled: "chat_disabled";
45
+ readonly PauseDisabled: "pause_disabled";
41
46
  readonly ListingDisabled: "listing_disabled";
47
+ readonly NostrDisabled: "nostr_disabled";
42
48
  readonly IdentityAnonymous: "identity_anonymous";
43
49
  };
44
50
  export type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
@@ -52,5 +58,23 @@ export declare function describeError(err: unknown): FriendlyError;
52
58
  * `base` defaults to the current page; any existing `param` is replaced. Throws on an invalid code.
53
59
  */
54
60
  export declare function shareUrl(code: string, base?: string, param?: string): string;
61
+ /** What a direct host answers at `GET /joininfo` (onelobby/direct). */
62
+ export interface JoinInfo {
63
+ joinCode: string;
64
+ joinCodeKind: JoinCodeKind;
65
+ /** The IP code (address and port); equals `joinCode` when Nostr is off. */
66
+ directCode: string;
67
+ directCodeKind: IpCodeKind;
68
+ /** `http://<public or LAN address>:<port>/` when the host serves pages; else null. */
69
+ joinUrl: string | null;
70
+ port: number;
71
+ }
72
+ /**
73
+ * For a page served by a direct host (`hostDirect` with `http`): the host's current join code and share link, so a
74
+ * player who opened the page at a LAN or localhost address still shares the public one. `base` defaults to the page's
75
+ * origin. Null when the host has no code yet or cannot be reached. Ask again after a while: the code turns "internet"
76
+ * when the router answers a later port-mapping retry.
77
+ */
78
+ export declare function directJoinInfo(base?: string): Promise<JoinInfo | null>;
55
79
  /** The lobby code carried by a share link (see shareUrl), or null when there is none or it is not a valid code. */
56
80
  export declare function codeFromUrl(url?: string, param?: string): string | null;
package/dist/friendly.js CHANGED
@@ -29,16 +29,22 @@ export const ErrorCodes = {
29
29
  DirectUnreachable: "direct_unreachable",
30
30
  BadAddress: "bad_address",
31
31
  PortInUse: "port_in_use",
32
+ Unsupported: "unsupported",
32
33
  ConnectFailed: "connect_failed",
33
34
  Closed: "closed",
34
35
  ServerLost: "server_lost",
35
36
  InvalidToken: "invalid_token",
36
37
  NoServer: "no_server",
38
+ // from the shared pause (lobby.pause)
39
+ NotInGame: "not_in_game",
40
+ NotAllowed: "not_allowed",
37
41
  // from a blueprint (onelobby.json)
38
42
  BadConfig: "bad_config",
39
43
  VoiceDisabled: "voice_disabled",
40
44
  ChatDisabled: "chat_disabled",
45
+ PauseDisabled: "pause_disabled",
41
46
  ListingDisabled: "listing_disabled",
47
+ NostrDisabled: "nostr_disabled",
42
48
  IdentityAnonymous: "identity_anonymous",
43
49
  };
44
50
  const TEXT = {
@@ -64,9 +70,15 @@ const TEXT = {
64
70
  ice_failed: { message: "Couldn't connect to the other players.", hint: "Some networks (school, work, public Wi-Fi) block game connections. Try another network or a phone hotspot." },
65
71
  no_server: { message: "This game has no lobby server address yet.", hint: "Enter one in the multiplayer settings, or host from your own computer with a join code." },
66
72
  timeout: { message: "The connection took too long.", hint: "Check your internet connection, then try again." },
73
+ unsupported: { message: "The host's game is too old for that.", hint: "Ask the host to update the game." },
67
74
  voice_disabled: { message: "Voice chat is turned off in this game." },
68
75
  chat_disabled: { message: "Text chat is turned off in this game." },
76
+ pause_disabled: { message: "Pausing is turned off in this game." },
77
+ not_in_game: { message: "You can only pause while a game is running.", hint: "Start the game first." },
78
+ not_allowed: { message: "You can't do that right now.", hint: "The player who paused, or the host, can resume." },
69
79
  listing_disabled: { message: "This game has no public lobby list.", hint: "Join with a code or a link from the host." },
80
+ direct_unreachable: { message: "Couldn't reach the host.", hint: "Check the code, and that the host is still online. A host in a browser needs its tab open and visible." },
81
+ nostr_disabled: { message: "This game can't be hosted from a browser.", hint: "Host from the desktop version, or let the game's owner know." },
70
82
  identity_anonymous: { message: "This game doesn't use player names.", hint: "Everyone shows up as Player 1, Player 2, and so on." },
71
83
  bad_config: { message: "The game's multiplayer settings file is not valid.", hint: "Let the game's owner know; the details are in the error message." },
72
84
  left: { message: "You left the lobby." },
@@ -146,6 +158,24 @@ export function shareUrl(code, base, param = "join") {
146
158
  u.searchParams.set(param, formatCode(norm).replace(" ", "-"));
147
159
  return u.toString();
148
160
  }
161
+ /**
162
+ * For a page served by a direct host (`hostDirect` with `http`): the host's current join code and share link, so a
163
+ * player who opened the page at a LAN or localhost address still shares the public one. `base` defaults to the page's
164
+ * origin. Null when the host has no code yet or cannot be reached. Ask again after a while: the code turns "internet"
165
+ * when the router answers a later port-mapping retry.
166
+ */
167
+ export async function directJoinInfo(base) {
168
+ const b = base ?? currentHref();
169
+ if (!b)
170
+ return null;
171
+ try {
172
+ const res = await fetch(new URL("/joininfo", b), { cache: "no-store" });
173
+ return res.ok ? (await res.json()) : null;
174
+ }
175
+ catch {
176
+ return null;
177
+ }
178
+ }
149
179
  /** The lobby code carried by a share link (see shareUrl), or null when there is none or it is not a valid code. */
150
180
  export function codeFromUrl(url, param = "join") {
151
181
  const href = url ?? currentHref();