onelobby 0.2.0 → 0.2.2
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.
- package/README.md +2 -2
- package/dist/direct/hub-host.js +23 -0
- package/dist/direct/hub-host.js.map +1 -1
- package/dist/direct/hub.js +23 -5
- package/dist/direct/hub.js.map +1 -1
- package/dist/direct/index.d.ts +8 -1
- package/dist/direct/index.js +17 -8
- package/dist/direct/index.js.map +1 -1
- package/dist/direct/portmap.d.ts +12 -1
- package/dist/direct/portmap.js +61 -14
- package/dist/direct/portmap.js.map +1 -1
- package/dist/lobby.d.ts +43 -4
- package/dist/lobby.js +98 -21
- package/dist/lobby.js.map +1 -1
- package/dist/onelobby.bundle.mjs +5 -5
- package/dist/onelobby.bundle.mjs.map +3 -3
- package/dist/onelobby.d.ts +1 -1
- package/dist/onelobby.global.js +186 -32
- package/dist/onelobby.global.js.map +2 -2
- package/dist/onelobby.global.min.js +5 -5
- package/dist/onelobby.global.min.js.map +3 -3
- package/dist/onelobby.js +17 -3
- package/dist/onelobby.js.map +1 -1
- package/dist/signaling.d.ts +5 -1
- package/dist/signaling.js +17 -2
- package/dist/signaling.js.map +1 -1
- package/dist/socket.d.ts +11 -5
- package/dist/socket.js +34 -10
- package/dist/socket.js.map +1 -1
- package/dist/testing.js +13 -3
- package/dist/testing.js.map +1 -1
- package/dist/webrtc.d.ts +12 -0
- package/dist/webrtc.js +30 -1
- package/dist/webrtc.js.map +1 -1
- package/package.json +1 -1
package/dist/direct/portmap.js
CHANGED
|
@@ -36,6 +36,12 @@ export class PortMapper {
|
|
|
36
36
|
natPmpAt = null;
|
|
37
37
|
renew = null;
|
|
38
38
|
stopped = false;
|
|
39
|
+
opening = null;
|
|
40
|
+
/**
|
|
41
|
+
* Every mapping a request was sent for and the router did not refuse ("upnp TCP", "pmp 1", ...): what close()
|
|
42
|
+
* deletes. Added before the request goes out, so a host that quits mid-request still undoes it.
|
|
43
|
+
*/
|
|
44
|
+
maybeMapped = new Set();
|
|
39
45
|
constructor(port, options = {}) {
|
|
40
46
|
this.port = port;
|
|
41
47
|
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
@@ -52,7 +58,10 @@ export class PortMapper {
|
|
|
52
58
|
};
|
|
53
59
|
}
|
|
54
60
|
/** Finds the router and maps TCP + UDP `port`. Never rejects for network trouble: see `detail`. */
|
|
55
|
-
|
|
61
|
+
open() {
|
|
62
|
+
return (this.opening = this.openBoth());
|
|
63
|
+
}
|
|
64
|
+
async openBoth() {
|
|
56
65
|
const notes = [];
|
|
57
66
|
if (this.o.tryUpnp) {
|
|
58
67
|
try {
|
|
@@ -141,11 +150,27 @@ export class PortMapper {
|
|
|
141
150
|
return { mapped: true, method: "upnp", externalIPv4: external, localIPv4: local, detail: "UPnP" };
|
|
142
151
|
}
|
|
143
152
|
async addUpnpBoth(local, lease) {
|
|
144
|
-
for (const proto of ["TCP", "UDP"])
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
153
|
+
for (const proto of ["TCP", "UDP"]) {
|
|
154
|
+
if (this.stopped)
|
|
155
|
+
throw new Error("closed before the router answered");
|
|
156
|
+
const key = `upnp ${proto}`;
|
|
157
|
+
this.maybeMapped.add(key);
|
|
158
|
+
try {
|
|
159
|
+
await this.soap("AddPortMapping", [
|
|
160
|
+
["NewRemoteHost", ""], ["NewExternalPort", String(this.port)], ["NewProtocol", proto], ["NewInternalPort", String(this.port)],
|
|
161
|
+
["NewInternalClient", local], ["NewEnabled", "1"], ["NewPortMappingDescription", this.o.description], ["NewLeaseDuration", String(lease)],
|
|
162
|
+
]);
|
|
163
|
+
}
|
|
164
|
+
catch (e) {
|
|
165
|
+
// refused (e.g. 718: another device holds the port): not ours, so close() must not delete it
|
|
166
|
+
if (e instanceof UpnpError)
|
|
167
|
+
this.maybeMapped.delete(key);
|
|
168
|
+
throw e;
|
|
169
|
+
}
|
|
170
|
+
// close() ran while this request was out: its delete may have reached the router first, so undo it now
|
|
171
|
+
if (this.stopped)
|
|
172
|
+
await this.undo([key]);
|
|
173
|
+
}
|
|
149
174
|
}
|
|
150
175
|
/**
|
|
151
176
|
* SSDP search: multicast once per interface that has a gateway (so a Hyper-V, WSL or Docker adapter cannot swallow
|
|
@@ -257,15 +282,24 @@ export class PortMapper {
|
|
|
257
282
|
/** Maps UDP then TCP; null on success, else why. A different external port counts as failure (and is undone). */
|
|
258
283
|
async natPmpMapBoth(lifetime) {
|
|
259
284
|
for (const op of [1, 2]) {
|
|
285
|
+
if (this.stopped)
|
|
286
|
+
return "closed before the router answered";
|
|
287
|
+
const key = `pmp ${op}`;
|
|
288
|
+
this.maybeMapped.add(key);
|
|
260
289
|
const reply = await this.natPmpRequest(this.natPmpAt, this.mapRequest(op, lifetime), 16);
|
|
290
|
+
if (this.stopped)
|
|
291
|
+
await this.undo([key]);
|
|
261
292
|
if (!reply)
|
|
262
293
|
return "no answer to the mapping request";
|
|
263
294
|
const rc = reply.readUInt16BE(2);
|
|
264
|
-
if (rc !== 0)
|
|
295
|
+
if (rc !== 0) {
|
|
296
|
+
this.maybeMapped.delete(key);
|
|
265
297
|
return `result code ${rc}`;
|
|
298
|
+
}
|
|
266
299
|
const mapped = reply.readUInt16BE(10);
|
|
267
300
|
if (lifetime > 0 && mapped !== this.port) {
|
|
268
301
|
await this.natPmpRequest(this.natPmpAt, this.mapRequest(op, 0), 16);
|
|
302
|
+
this.maybeMapped.delete(key);
|
|
269
303
|
return `router offered port ${mapped} instead of ${this.port}`;
|
|
270
304
|
}
|
|
271
305
|
}
|
|
@@ -307,20 +341,30 @@ export class PortMapper {
|
|
|
307
341
|
s.bind(0, attempt);
|
|
308
342
|
});
|
|
309
343
|
}
|
|
310
|
-
/**
|
|
344
|
+
/**
|
|
345
|
+
* Stops renewing and deletes every mapping it may have made, even while {@link open} is still talking to the router
|
|
346
|
+
* (best effort, bounded to about two seconds; a request still out when it returns undoes itself when it lands).
|
|
347
|
+
*/
|
|
311
348
|
async close() {
|
|
312
349
|
if (this.stopped)
|
|
313
350
|
return;
|
|
314
351
|
this.stopped = true;
|
|
315
352
|
if (this.renew)
|
|
316
353
|
clearInterval(this.renew);
|
|
317
|
-
|
|
318
|
-
|
|
354
|
+
if (this.opening)
|
|
355
|
+
await Promise.race([this.opening.catch(() => { }), delay(500)]);
|
|
356
|
+
await this.undo([...this.maybeMapped]);
|
|
357
|
+
}
|
|
358
|
+
async undo(keys) {
|
|
359
|
+
if (keys.length === 0)
|
|
319
360
|
return;
|
|
320
|
-
const work =
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
361
|
+
const work = Promise.all(keys.map((k) => {
|
|
362
|
+
this.maybeMapped.delete(k);
|
|
363
|
+
return k.startsWith("upnp ")
|
|
364
|
+
? this.soap("DeletePortMapping", [["NewRemoteHost", ""], ["NewExternalPort", String(this.port)], ["NewProtocol", k.slice(5)]])
|
|
365
|
+
: this.natPmpOnce(this.mapRequest(Number(k.slice(4)), 0));
|
|
366
|
+
}));
|
|
367
|
+
await Promise.race([work.catch(() => { }), delay(1500)]);
|
|
324
368
|
}
|
|
325
369
|
natPmpOnce(req) {
|
|
326
370
|
return new Promise((resolve) => {
|
|
@@ -462,4 +506,7 @@ export function localAddresses(port) {
|
|
|
462
506
|
}
|
|
463
507
|
return [...v4, ...v6];
|
|
464
508
|
}
|
|
509
|
+
function delay(ms) {
|
|
510
|
+
return new Promise((r) => setTimeout(r, ms).unref?.());
|
|
511
|
+
}
|
|
465
512
|
//# sourceMappingURL=portmap.js.map
|
|
@@ -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\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\">> & { natPmp?: { address: string; port: number } };\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\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 async open(): 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 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 }\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 const reply = await this.natPmpRequest(this.natPmpAt!, this.mapRequest(op, lifetime), 16);\n if (!reply) return \"no answer to the mapping request\";\n const rc = reply.readUInt16BE(2);\n if (rc !== 0) return `result code ${rc}`;\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 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 /** Deletes the mappings (best effort, bounded to about 1.5 s) and stops renewing. */\n async close(): Promise<void> {\n if (this.stopped) return;\n this.stopped = true;\n if (this.renew) clearInterval(this.renew);\n const r = this.result;\n if (!r?.mapped) return;\n const work =\n r.method === \"upnp\"\n ? Promise.all([\"TCP\", \"UDP\"].map((p) => this.soap(\"DeletePortMapping\", [[\"NewRemoteHost\", \"\"], [\"NewExternalPort\", String(this.port)], [\"NewProtocol\", p]])))\n : Promise.all([1, 2].map((op) => this.natPmpOnce(this.mapRequest(op, 0))));\n await Promise.race([work.catch(() => {}), new Promise((r2) => setTimeout(r2, 1500).unref?.())]);\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, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\").replace(/'/g, \"'\");\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"]}
|
|
1
|
+
{"version":3,"file":"portmap.js","sourceRoot":"","sources":["../../src/direct/portmap.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,OAAO,EAAE,YAAY,EAA4B,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AA+B9C,MAAM,cAAc,GAAG;IACrB,qDAAqD;IACrD,qDAAqD;IACrD,gDAAgD;CACjD,CAAC;AACF,MAAM,aAAa,GAAG;IACpB,gDAAgD;IAChD,gDAAgD;IAChD,iDAAiD;CAClD,CAAC;AAEF,MAAM,SAAU,SAAQ,KAAK;IACN;IAArB,YAAqB,IAAY,EAAE,OAAe;QAChD,KAAK,CAAC,OAAO,CAAC,CAAC;QADI,SAAI,GAAJ,IAAI,CAAQ;IAEjC,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,OAAO,UAAU;IAgBA;IAfrB,MAAM,GAAyB,IAAI,CAAC;IACnB,CAAC,CAA+F;IACzG,OAAO,GAAe,IAAI,CAAC;IAC3B,OAAO,GAAG,EAAE,CAAC;IACb,KAAK,GAAG,CAAC,CAAC;IACV,QAAQ,GAA6C,IAAI,CAAC;IAC1D,KAAK,GAA0C,IAAI,CAAC;IACpD,OAAO,GAAG,KAAK,CAAC;IAChB,OAAO,GAAkC,IAAI,CAAC;IACtD;;;OAGG;IACc,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;IAEjD,YAAqB,IAAY,EAAE,UAA6B,EAAE;QAA7C,SAAI,GAAJ,IAAI,CAAQ;QAC/B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK;YAAE,MAAM,IAAI,UAAU,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;QAClG,IAAI,CAAC,CAAC,GAAG;YACP,IAAI,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,IAAI,EAAE;YAChD,kBAAkB,EAAE,IAAI;YACxB,gBAAgB,EAAE,IAAI;YACtB,YAAY,EAAE,IAAI;YAClB,WAAW,EAAE,UAAU;YACvB,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI;YACf,GAAG,OAAO;SACX,CAAC;IACJ,CAAC;IAED,mGAAmG;IACnG,IAAI;QACF,OAAO,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC1C,CAAC;IAEO,KAAK,CAAC,QAAQ;QACpB,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;YACnB,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC/B,IAAI,CAAC;oBAAE,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAC3B,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;YACzC,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,KAAK,CAAC,IAAI,CAAC,SAAU,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;gBACjC,IAAI,CAAC;oBAAE,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAC3B,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YAClC,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,KAAK,CAAC,IAAI,CAAC,YAAa,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1H,CAAC;IAEO,IAAI,CAAC,CAAgB;QAC3B,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAChB,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,EAAE,CAAC;YAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC;YAC7F,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;gBAC5B,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,SAAU,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;gBACrH,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,oEAAoE;YACzF,CAAC,EAAE,OAAO,CAAC,CAAC;YACZ,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;QACvB,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,4GAA4G;IAEpG,KAAK,CAAC,OAAO;QACnB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACvC,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC3B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QACxD,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAC3C,MAAM,IAAI,GAAG,QAAQ,IAAI,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QACvF,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;YACjC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,+BAA+B,CAAC,IAAI,EAAE,EAAE,CAAC;gBACzE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI;oBAAE,SAAS;gBAC9D,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,IAAI,EAAE,CAAC;gBAC3C,IAAI,CAAC,GAAG;oBAAE,SAAS;gBACnB,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAClC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;gBACpB,MAAM;YACR,CAAC;YACD,IAAI,IAAI,CAAC,OAAO;gBAAE,MAAM;QAC1B,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,6CAA6C,EAAE,CAAC;QAExJ,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/F,IAAI,QAAQ,GAAkB,IAAI,CAAC;QACnC,IAAI,CAAC;YACH,QAAQ,GAAG,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,sBAAsB,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;QAC7G,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,CAAC,CAAC,YAAY,SAAS,CAAC;gBAAE,MAAM,CAAC,CAAC,CAAC,yCAAyC;QACnF,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC;QACjC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,CAAC,CAAC,YAAY,SAAS,CAAC;gBAAE,MAAM,CAAC,CAAC;YACvC,IAAI,CAAC,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC;gBACnB,+BAA+B;gBAC/B,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;gBACf,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YACnC,CAAC;;gBAAM,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QACzH,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACpG,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,KAAa,EAAE,KAAa;QACpD,KAAK,MAAM,KAAK,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACvE,MAAM,GAAG,GAAG,QAAQ,KAAK,EAAE,CAAC;YAC5B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC1B,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE;oBAChC,CAAC,eAAe,EAAE,EAAE,CAAC,EAAE,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC7H,CAAC,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,GAAG,CAAC,EAAE,CAAC,2BAA2B,EAAE,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,kBAAkB,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;iBAC1I,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,6FAA6F;gBAC7F,IAAI,CAAC,YAAY,SAAS;oBAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACzD,MAAM,CAAC,CAAC;YACV,CAAC;YACD,uGAAuG;YACvG,IAAI,IAAI,CAAC,OAAO;gBAAE,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,QAAQ;QACd,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;QACnE,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,MAAM,OAAO,GAAgB,EAAE,CAAC;YAChC,IAAI,QAAQ,GAAG,KAAK,CAAC;YACrB,MAAM,MAAM,GAAG,CAAC,CAAa,EAAE,EAAE;gBAC/B,IAAI,QAAQ;oBAAE,OAAO;gBACrB,QAAQ,GAAG,IAAI,CAAC;gBAChB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,KAAK,MAAM,CAAC,IAAI,OAAO;oBAAE,CAAC,CAAC,KAAK,EAAE,CAAC;gBACnC,OAAO,CAAC,CAAC,CAAC,CAAC;YACb,CAAC,CAAC;YACF,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;YACxE,KAAK,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,MAAM,EAAE,CAAC;gBACxC,MAAM,CAAC,GAAG,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAChB,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACxB,CAAC,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;oBACpB,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;oBAC1C,IAAI,CAAC;wBAAE,MAAM,CAAC,CAAC,CAAC,CAAC;gBACnB,CAAC,CAAC,CAAC;gBACH,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE;oBACtD,IAAI,CAAC;wBACH,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;wBACrB,IAAI,KAAK,KAAK,SAAS;4BAAE,CAAC,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC;oBAC1D,CAAC;oBAAC,MAAM,CAAC;wBACP,iDAAiD;oBACnD,CAAC;oBACD,KAAK,MAAM,EAAE,IAAI,cAAc,EAAE,CAAC;wBAChC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,6FAA6F,EAAE,UAAU,CAAC,CAAC;wBACjI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;wBAC3D,IAAI,OAAO;4BAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;oBAClD,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,IAAI,CAAC,MAAc,EAAE,IAAwB;QACzD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5E,MAAM,IAAI,GACR,mJAAmJ;YACnJ,cAAc,MAAM,aAAa,IAAI,CAAC,OAAO,KAAK,KAAK,OAAO,MAAM,yBAAyB,CAAC;QAChG,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAQ,EAAE,IAAI,EAAE,EAAE,cAAc,EAAE,2BAA2B,EAAE,UAAU,EAAE,IAAI,IAAI,CAAC,OAAO,IAAI,MAAM,GAAG,EAAE,CAAC,CAAC;QACrJ,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;YAC1C,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;YACxC,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,kBAAkB,CAAC,IAAI,EAAE,CAAC;YACrD,MAAM,IAAI,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,MAAM,UAAU,IAAI,IAAI,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QACjG,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;;OAGG;IACK,IAAI,CAAC,MAAc,EAAE,GAAQ,EAAE,IAAmB,EAAE,OAA+B;QACzF,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,CAAC,GAAG,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;YAC9C,MAAM,GAAG,GAAG,WAAW,CACrB,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,gBAAgB,EAAE,KAAK,EAAE,KAAK;gBACrI,OAAO,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,EACpF,CAAC,GAAG,EAAE,EAAE;gBACN,IAAI,IAAI,GAAG,EAAE,CAAC;gBACd,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;gBACxB,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;gBACnC,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,UAAU,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAC5E,CAAC,CACF,CAAC;YACF,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,QAAQ,YAAY,CAAC,CAAC,CAAC,CAAC;YACvF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACxB,IAAI,IAAI,KAAK,IAAI;gBAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACnC,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC;IAED,2GAA2G;IAEnG,KAAK,CAAC,SAAS;QACrB,0EAA0E;QAC1E,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC;QAChC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,MAAM,GAAG,CAAC,MAAM,sBAAsB,EAAE,CAAC,IAAI,iBAAiB,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC;YAC/G,IAAI,MAAM;gBAAE,GAAG,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACpD,CAAC;QACD,MAAM,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpC,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;YAC5B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAClE,IAAI,CAAC,GAAG;gBAAE,SAAS;YACnB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;YACnB,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;YAC5D,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YAChG,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;YAC1D,IAAI,GAAG;gBAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,GAAG,EAAE,EAAE,CAAC;YACxH,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QACzG,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,iHAAiH;IACzG,KAAK,CAAC,aAAa,CAAC,QAAgB;QAC1C,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACxB,IAAI,IAAI,CAAC,OAAO;gBAAE,OAAO,mCAAmC,CAAC;YAC7D,MAAM,GAAG,GAAG,OAAO,EAAE,EAAE,CAAC;YACxB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC1B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAS,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1F,IAAI,IAAI,CAAC,OAAO;gBAAE,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACzC,IAAI,CAAC,KAAK;gBAAE,OAAO,kCAAkC,CAAC;YACtD,MAAM,EAAE,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACjC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;gBACb,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC7B,OAAO,eAAe,EAAE,EAAE,CAAC;YAC7B,CAAC;YACD,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;YACtC,IAAI,QAAQ,GAAG,CAAC,IAAI,MAAM,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;gBACzC,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAS,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACrE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC7B,OAAO,uBAAuB,MAAM,eAAe,IAAI,CAAC,IAAI,EAAE,CAAC;YACjE,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,UAAU,CAAC,EAAU,EAAE,QAAgB;QAC7C,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QACV,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9B,CAAC,CAAC,aAAa,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACjD,CAAC,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC7B,OAAO,CAAC,CAAC;IACX,CAAC;IAED,sGAAsG;IAC9F,aAAa,CAAC,EAAqC,EAAE,GAAW,EAAE,WAAmB;QAC3F,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,MAAM,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YAC/B,IAAI,IAAI,GAAG,GAAG,CAAC;YACf,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,IAAI,KAAK,GAAyC,IAAI,CAAC;YACvD,MAAM,MAAM,GAAG,CAAC,CAAgB,EAAE,EAAE;gBAClC,IAAI,KAAK;oBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;gBAC/B,CAAC,CAAC,KAAK,EAAE,CAAC;gBACV,OAAO,CAAC,CAAC,CAAC,CAAC;YACb,CAAC,CAAC;YACF,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,+DAA+D;YACxF,CAAC,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;gBACpB,IAAI,CAAC,CAAC,MAAM,IAAI,WAAW,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG;oBAAE,MAAM,CAAC,CAAC,CAAC,CAAC;YAChF,CAAC,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,GAAG,EAAE;gBACnB,IAAI,KAAK,EAAE,IAAI,CAAC;oBAAE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;gBACtC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBAC3C,KAAK,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;gBAClC,IAAI,IAAI,CAAC,CAAC;YACZ,CAAC,CAAC;YACF,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,IAAI,CAAC,KAAK;YAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,IAAI,CAAC,OAAO;YAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACjF,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;IACzC,CAAC;IAEO,KAAK,CAAC,IAAI,CAAC,IAAc;QAC/B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC9B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CACtB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACb,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC3B,OAAO,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC;gBAC1B,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC,eAAe,EAAE,EAAE,CAAC,EAAE,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC9H,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9D,CAAC,CAAC,CACH,CAAC;QACF,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC;IAEO,UAAU,CAAC,GAAW;QAC5B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,MAAM,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YAC/B,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACxB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,QAAS,CAAC,IAAI,EAAE,IAAI,CAAC,QAAS,CAAC,OAAO,EAAE,GAAG,EAAE;gBAC5D,CAAC,CAAC,KAAK,EAAE,CAAC;gBACV,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED,2GAA2G;AAE3G;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAAkC;IAC7D,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,MAAM,CAAC,GAAG,8CAA8C,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACvE,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACrB,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1D,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,GAAG;QAAE,OAAO,KAAK,CAAC;IAC/D,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,GAAG;QAAE,OAAO,KAAK,CAAC;IAClD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,KAAK,CAAC;IACzC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE;QAAE,OAAO,KAAK,CAAC;IACjD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,KAAK,CAAC;IACzC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,GAAG,CAAC,GAAW,EAAE,IAAY;IACpC,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,uBAAuB,IAAI,kDAAkD,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrH,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,CAAC;AAED,SAAS,SAAS,CAAC,CAAS;IAC1B,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC9H,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACvC,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC;YAAE,SAAS;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACnD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACvC,IAAI,IAAI,KAAK,UAAU;YAAE,QAAQ,GAAG,KAAK,CAAC;QAC1C,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,CAAC,IAAI,uCAAuC,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,GAAG,IAAI,CAAC;IAC/G,CAAC;IACD,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB;IACxB,MAAM,GAAG,GAAgD,EAAE,CAAC;IAC5D,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC,EAAE,CAAC;QACvD,KAAK,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE,EAAE,CAAC;YAC5B,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;gBAAE,SAAS;YACpF,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC5C,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC9C,MAAM,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1C,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QAClH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,0HAA0H;AAC1H,SAAS,sBAAsB;IAC7B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;QACzC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;YAC3H,IAAI,GAAG;gBAAE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;YAC9B,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,gDAAgD,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,kCAAkC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAChI,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,8FAA8F;AAC9F,SAAS,kBAAkB,CAAC,IAAY,EAAE,IAAY;IACpD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QAC/B,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;YAClB,CAAC,CAAC,KAAK,EAAE,CAAC;YACV,MAAM,CAAC,CAAC,CAAC,CAAC;QACZ,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE;YACzB,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC;YAC9B,CAAC,CAAC,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,CAAC,CAAC,CAAC;QACb,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,gHAAgH;AAChH,MAAM,CAAC,KAAK,UAAU,OAAO;IAC3B,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,kBAAkB,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,wDAAwD;QAC5G,IAAI,CAAC,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;IAC3E,CAAC;IACD,OAAO,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC;AAC/C,CAAC;AAED,yGAAyG;AACzG,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,EAAE,GAAa,EAAE,CAAC;IACxB,MAAM,EAAE,GAAa,EAAE,CAAC;IACxB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC,EAAE,CAAC;QACvD,KAAK,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE,EAAE,CAAC;YAC5B,IAAI,CAAC,CAAC,QAAQ;gBAAE,SAAS;YACzB,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;gBAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC,CAAC;iBACzF,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;gBAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC,CAAC;QAC3H,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;AACxB,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACzD,CAAC","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\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\">> & { natPmp?: { address: string; port: number } };\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 }\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, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\").replace(/'/g, \"'\");\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"]}
|
package/dist/lobby.d.ts
CHANGED
|
@@ -8,6 +8,20 @@ import type { ChannelName, IceServer, LinkFactory, PeerLink } from "./transport.
|
|
|
8
8
|
import { Voice, type VoiceDeps } from "./voice.js";
|
|
9
9
|
import { type LobbySocket, type LobbySocketOptions } from "./socket.js";
|
|
10
10
|
export type Phase = "lobby" | "in_game";
|
|
11
|
+
/** The close code and reason a host chose with `kick()` / `disconnect()`, passed to the removed player's sockets. */
|
|
12
|
+
export interface CloseInfo {
|
|
13
|
+
code?: number;
|
|
14
|
+
reason?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Options for `lobby.kick()`. */
|
|
17
|
+
export interface KickOptions {
|
|
18
|
+
/** Default true: the player's address cannot rejoin this lobby while it lasts. false = `disconnect()`. */
|
|
19
|
+
ban?: boolean;
|
|
20
|
+
/** Close code for the player's `asWebSocket()` onclose: 1000 or 3000-4999. */
|
|
21
|
+
code?: number;
|
|
22
|
+
/** Close reason for that onclose, at most 120 characters. */
|
|
23
|
+
reason?: string;
|
|
24
|
+
}
|
|
11
25
|
export type Peer = PeerInfo;
|
|
12
26
|
export type LobbyEvents = {
|
|
13
27
|
peerJoined: [Peer];
|
|
@@ -15,12 +29,14 @@ export type LobbyEvents = {
|
|
|
15
29
|
peerReady: [Peer];
|
|
16
30
|
/** Joiner: the link to the host is open (the host itself is ready from the start). Also available as `lobby.ready`. */
|
|
17
31
|
ready: [];
|
|
18
|
-
|
|
32
|
+
/** reason "left", "kicked", "disconnected" (kick with ban false), "timeout", ...; `close` when the host gave one. */
|
|
33
|
+
peerLeft: [Peer, reason: string, close?: CloseInfo];
|
|
19
34
|
joinRequested: [Peer];
|
|
20
35
|
hostChanged: [hostId: number];
|
|
21
36
|
phase: [Phase];
|
|
22
37
|
message: [from: number, bytes: Uint8Array, channel: ChannelName];
|
|
23
|
-
|
|
38
|
+
/** `close` is the code and reason the host gave when it removed this player (`kick()` / `disconnect()`). */
|
|
39
|
+
sessionEnded: [reason: string, close?: CloseInfo];
|
|
24
40
|
/** The signaling server went away. The game continues on the data channels (s.9). */
|
|
25
41
|
serverLost: [];
|
|
26
42
|
metaChanged: [Record<string, string>];
|
|
@@ -64,6 +80,8 @@ export interface RateLimit {
|
|
|
64
80
|
}
|
|
65
81
|
/** The smallest `peerTimeoutMs` honoured: three missed pings. */
|
|
66
82
|
export declare const MIN_PEER_TIMEOUT_MS = 6000;
|
|
83
|
+
/** Host: how long a kicked / disconnected peer's link stays open for the hub's notice to reach it first. */
|
|
84
|
+
export declare const KICK_LINGER_MS = 3000;
|
|
67
85
|
/** The name shown for a peer that chose none: "Player N", N = its seat (peer id, join order). */
|
|
68
86
|
export declare function seatName(p: PeerInfo): PeerInfo;
|
|
69
87
|
/** One joined lobby: roster, star of peer links, and the lockstep/chat/voice engines riding on them. */
|
|
@@ -96,6 +114,8 @@ export declare class Lobby extends Emitter<LobbyEvents> {
|
|
|
96
114
|
private cfg;
|
|
97
115
|
private roster;
|
|
98
116
|
private links;
|
|
117
|
+
/** ICE from a peer that has no link yet: its candidates can overtake its offer (node-datachannel). */
|
|
118
|
+
private earlyIce;
|
|
99
119
|
private connected;
|
|
100
120
|
private hiSentTo;
|
|
101
121
|
private epoch;
|
|
@@ -115,12 +135,14 @@ export declare class Lobby extends Emitter<LobbyEvents> {
|
|
|
115
135
|
private relayRetry;
|
|
116
136
|
/** clock.now() of the last frame from each peer (peerTimeoutMs). */
|
|
117
137
|
private lastHeard;
|
|
138
|
+
/** Host: links of kicked / disconnected peers, kept open briefly (removePeer `linger`). */
|
|
139
|
+
private readonly lingering;
|
|
118
140
|
/** Host: per-peer fixed window for rateLimit. */
|
|
119
141
|
private rate;
|
|
120
142
|
/**
|
|
121
143
|
* Resolves when this peer can exchange data: immediately for the host, once the link to the host is open for a
|
|
122
144
|
* joiner. Rejects with OneLobbyError("ice_failed") when the joiner cannot reach the host in `readyTimeoutMs`
|
|
123
|
-
* (or with "closed"/"kicked" when the lobby ends first).
|
|
145
|
+
* (or with "closed"/"kicked" when the lobby ends first; "closed" also when the host disconnected it).
|
|
124
146
|
*/
|
|
125
147
|
readonly ready: Promise<void>;
|
|
126
148
|
constructor(cfg: LobbyConfig);
|
|
@@ -147,7 +169,18 @@ export declare class Lobby extends Emitter<LobbyEvents> {
|
|
|
147
169
|
_begin(): void;
|
|
148
170
|
start(): Promise<void>;
|
|
149
171
|
setMeta(meta: Record<string, string>): Promise<void>;
|
|
150
|
-
|
|
172
|
+
/**
|
|
173
|
+
* Host: removes a player. By default it is a ban: the hub refuses that player's address for the rest of this lobby
|
|
174
|
+
* (a new tab or a reload included). `{ ban: false }` is `disconnect()`. `code` / `reason` reach the player's
|
|
175
|
+
* `asWebSocket()` onclose (and `sessionEnded`'s second argument); without them its socket closes with 4000 "kicked".
|
|
176
|
+
*/
|
|
177
|
+
kick(peerId: number, opts?: KickOptions): Promise<void>;
|
|
178
|
+
/**
|
|
179
|
+
* Host: ends one player's connection without a ban, like a server closing one WebSocket. The player's
|
|
180
|
+
* `asWebSocket()` gets onclose with `code` (default 1000) and `reason` (default "disconnected"), its lobby ends with
|
|
181
|
+
* `sessionEnded("disconnected")`, and it may join again (a new tab, a reload). Same as `kick(peerId, { ban: false, code, reason })`.
|
|
182
|
+
*/
|
|
183
|
+
disconnect(peerId: number, code?: number, reason?: string): Promise<void>;
|
|
151
184
|
approve(peerId: number, ok: boolean): Promise<void>;
|
|
152
185
|
leave(): Promise<void>;
|
|
153
186
|
/** raw mode (and any extra game data): to one peer. */
|
|
@@ -188,7 +221,13 @@ export declare class Lobby extends Emitter<LobbyEvents> {
|
|
|
188
221
|
private onHostClaim;
|
|
189
222
|
private onSignaling;
|
|
190
223
|
private onSignal;
|
|
224
|
+
/**
|
|
225
|
+
* `linger` (host kick / disconnect): stop using the peer's link at once but leave it open until that peer closes it
|
|
226
|
+
* or KICK_LINGER_MS pass. The hub tells the peer over its WebSocket; closing the data link first would make it look
|
|
227
|
+
* like the host vanished (a migration and a 1001 instead of the host's close code).
|
|
228
|
+
*/
|
|
191
229
|
private removePeer;
|
|
230
|
+
/** Lockstep drops (stalled, desynced): removed without a ban, so the player can come back (a rejoin resyncs). */
|
|
192
231
|
private dropPeer;
|
|
193
232
|
private setPhase;
|
|
194
233
|
private onServerClosed;
|