onelobby 0.2.0 → 0.2.1

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/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
- peerLeft: [Peer, reason: string];
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
- sessionEnded: [reason: string];
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. */
@@ -115,12 +133,14 @@ export declare class Lobby extends Emitter<LobbyEvents> {
115
133
  private relayRetry;
116
134
  /** clock.now() of the last frame from each peer (peerTimeoutMs). */
117
135
  private lastHeard;
136
+ /** Host: links of kicked / disconnected peers, kept open briefly (removePeer `linger`). */
137
+ private readonly lingering;
118
138
  /** Host: per-peer fixed window for rateLimit. */
119
139
  private rate;
120
140
  /**
121
141
  * Resolves when this peer can exchange data: immediately for the host, once the link to the host is open for a
122
142
  * 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).
143
+ * (or with "closed"/"kicked" when the lobby ends first; "closed" also when the host disconnected it).
124
144
  */
125
145
  readonly ready: Promise<void>;
126
146
  constructor(cfg: LobbyConfig);
@@ -147,7 +167,18 @@ export declare class Lobby extends Emitter<LobbyEvents> {
147
167
  _begin(): void;
148
168
  start(): Promise<void>;
149
169
  setMeta(meta: Record<string, string>): Promise<void>;
150
- kick(peerId: number): Promise<void>;
170
+ /**
171
+ * Host: removes a player. By default it is a ban: the hub refuses that player's address for the rest of this lobby
172
+ * (a new tab or a reload included). `{ ban: false }` is `disconnect()`. `code` / `reason` reach the player's
173
+ * `asWebSocket()` onclose (and `sessionEnded`'s second argument); without them its socket closes with 4000 "kicked".
174
+ */
175
+ kick(peerId: number, opts?: KickOptions): Promise<void>;
176
+ /**
177
+ * Host: ends one player's connection without a ban, like a server closing one WebSocket. The player's
178
+ * `asWebSocket()` gets onclose with `code` (default 1000) and `reason` (default "disconnected"), its lobby ends with
179
+ * `sessionEnded("disconnected")`, and it may join again (a new tab, a reload). Same as `kick(peerId, { ban: false, code, reason })`.
180
+ */
181
+ disconnect(peerId: number, code?: number, reason?: string): Promise<void>;
151
182
  approve(peerId: number, ok: boolean): Promise<void>;
152
183
  leave(): Promise<void>;
153
184
  /** raw mode (and any extra game data): to one peer. */
@@ -188,7 +219,13 @@ export declare class Lobby extends Emitter<LobbyEvents> {
188
219
  private onHostClaim;
189
220
  private onSignaling;
190
221
  private onSignal;
222
+ /**
223
+ * `linger` (host kick / disconnect): stop using the peer's link at once but leave it open until that peer closes it
224
+ * or KICK_LINGER_MS pass. The hub tells the peer over its WebSocket; closing the data link first would make it look
225
+ * like the host vanished (a migration and a 1001 instead of the host's close code).
226
+ */
191
227
  private removePeer;
228
+ /** Lockstep drops (stalled, desynced): removed without a ban, so the player can come back (a rejoin resyncs). */
192
229
  private dropPeer;
193
230
  private setPhase;
194
231
  private onServerClosed;
package/dist/lobby.js CHANGED
@@ -9,6 +9,8 @@ import { Voice } from "./voice.js";
9
9
  import { hostConnections, joinerSocket } from "./socket.js";
10
10
  /** The smallest `peerTimeoutMs` honoured: three missed pings. */
11
11
  export const MIN_PEER_TIMEOUT_MS = 6000;
12
+ /** Host: how long a kicked / disconnected peer's link stays open for the hub's notice to reach it first. */
13
+ export const KICK_LINGER_MS = 3000;
12
14
  /** The name shown for a peer that chose none: "Player N", N = its seat (peer id, join order). */
13
15
  export function seatName(p) {
14
16
  const n = typeof p.name === "string" ? p.name.trim() : "";
@@ -71,12 +73,14 @@ export class Lobby extends Emitter {
71
73
  relayRetry = false;
72
74
  /** clock.now() of the last frame from each peer (peerTimeoutMs). */
73
75
  lastHeard = new Map();
76
+ /** Host: links of kicked / disconnected peers, kept open briefly (removePeer `linger`). */
77
+ lingering = new Set();
74
78
  /** Host: per-peer fixed window for rateLimit. */
75
79
  rate = new Map();
76
80
  /**
77
81
  * Resolves when this peer can exchange data: immediately for the host, once the link to the host is open for a
78
82
  * joiner. Rejects with OneLobbyError("ice_failed") when the joiner cannot reach the host in `readyTimeoutMs`
79
- * (or with "closed"/"kicked" when the lobby ends first).
83
+ * (or with "closed"/"kicked" when the lobby ends first; "closed" also when the host disconnected it).
80
84
  */
81
85
  ready = new Promise((res, rej) => {
82
86
  this.markReady = () => {
@@ -205,11 +209,37 @@ export class Lobby extends Emitter {
205
209
  this.signaling.send({ t: "meta", meta });
206
210
  this.emit("metaChanged", this.meta);
207
211
  }
208
- async kick(peerId) {
212
+ /**
213
+ * Host: removes a player. By default it is a ban: the hub refuses that player's address for the rest of this lobby
214
+ * (a new tab or a reload included). `{ ban: false }` is `disconnect()`. `code` / `reason` reach the player's
215
+ * `asWebSocket()` onclose (and `sessionEnded`'s second argument); without them its socket closes with 4000 "kicked".
216
+ */
217
+ async kick(peerId, opts = {}) {
209
218
  if (!this.isHost)
210
219
  throw new Error("only the host can kick");
211
- this.signaling.send({ t: "kick", peerId });
212
- this.removePeer(peerId, "kicked");
220
+ const { ban = true, code, reason } = opts;
221
+ if (code !== undefined && !(code === 1000 || (Number.isInteger(code) && code >= 3000 && code <= 4999)))
222
+ throw new RangeError("close code must be 1000 or 3000-4999");
223
+ if (reason !== undefined && reason.length > 120)
224
+ throw new RangeError("close reason must be at most 120 characters");
225
+ const msg = { t: "kick", peerId };
226
+ if (!ban)
227
+ msg.ban = false;
228
+ if (code !== undefined)
229
+ msg.closeCode = code;
230
+ if (reason !== undefined)
231
+ msg.closeReason = reason;
232
+ this.signaling.send(msg);
233
+ const close = code !== undefined || reason !== undefined ? { code, reason } : undefined;
234
+ this.removePeer(peerId, ban ? "kicked" : "disconnected", close, true);
235
+ }
236
+ /**
237
+ * Host: ends one player's connection without a ban, like a server closing one WebSocket. The player's
238
+ * `asWebSocket()` gets onclose with `code` (default 1000) and `reason` (default "disconnected"), its lobby ends with
239
+ * `sessionEnded("disconnected")`, and it may join again (a new tab, a reload). Same as `kick(peerId, { ban: false, code, reason })`.
240
+ */
241
+ disconnect(peerId, code, reason) {
242
+ return this.kick(peerId, { ban: false, code, reason });
213
243
  }
214
244
  async approve(peerId, ok) {
215
245
  if (!this.isHost)
@@ -691,8 +721,15 @@ export class Lobby extends Emitter {
691
721
  void this.onSignal(Number(m.from), m);
692
722
  break;
693
723
  case "error":
694
- if (m.code === "kicked")
695
- this.teardown("kicked");
724
+ if (m.code === "kicked") {
725
+ const d = (m.data ?? {});
726
+ const close = {};
727
+ if (typeof d.closeCode === "number")
728
+ close.code = d.closeCode;
729
+ if (typeof d.closeReason === "string")
730
+ close.reason = d.closeReason;
731
+ this.teardown(d.ban === false ? "disconnected" : "kicked", close.code !== undefined || close.reason !== undefined ? close : undefined);
732
+ }
696
733
  else
697
734
  this.reportError(new OneLobbyError(String(m.code), String(m.msg ?? ""), m.data));
698
735
  break;
@@ -713,7 +750,12 @@ export class Lobby extends Emitter {
713
750
  payload.ice = s.ice;
714
751
  await link.handleSignal(payload);
715
752
  }
716
- removePeer(peerId, reason) {
753
+ /**
754
+ * `linger` (host kick / disconnect): stop using the peer's link at once but leave it open until that peer closes it
755
+ * or KICK_LINGER_MS pass. The hub tells the peer over its WebSocket; closing the data link first would make it look
756
+ * like the host vanished (a migration and a 1001 instead of the host's close code).
757
+ */
758
+ removePeer(peerId, reason, close, linger = false) {
717
759
  const peer = this.roster.get(peerId);
718
760
  if (peerId === this.localPeerId) {
719
761
  this.teardown(reason === "kicked" ? "kicked" : reason);
@@ -723,11 +765,25 @@ export class Lobby extends Emitter {
723
765
  this.roster.delete(peerId);
724
766
  const link = this.links.get(peerId);
725
767
  if (link && peerId !== this.hostPeerId) {
726
- link.onClose = null;
727
768
  link.onMessage = null;
728
- link.close();
729
769
  this.links.delete(peerId);
730
770
  this.hiSentTo.delete(link);
771
+ if (linger) {
772
+ this.lingering.add(link);
773
+ const done = () => {
774
+ if (!this.lingering.delete(link))
775
+ return;
776
+ cancel();
777
+ link.onClose = null;
778
+ link.close();
779
+ };
780
+ const cancel = this.cfg.clock.setTimeout(done, KICK_LINGER_MS);
781
+ link.onClose = done;
782
+ }
783
+ else {
784
+ link.onClose = null;
785
+ link.close();
786
+ }
731
787
  }
732
788
  this.connected.delete(peerId);
733
789
  this.outbox.delete(peerId);
@@ -737,14 +793,15 @@ export class Lobby extends Emitter {
737
793
  this.chat.onPeerLeft(peerId);
738
794
  this.voice.onPeerLeft(peerId);
739
795
  if (peer)
740
- this.emit("peerLeft", peer, reason);
796
+ this.emit("peerLeft", peer, reason, close);
741
797
  if (peerId === this.hostPeerId && !this.isHost) {
742
798
  this.handleHostLost(reason);
743
799
  }
744
800
  }
801
+ /** Lockstep drops (stalled, desynced): removed without a ban, so the player can come back (a rejoin resyncs). */
745
802
  dropPeer(peerId, reason) {
746
- this.signaling.send({ t: "kick", peerId });
747
- this.removePeer(peerId, reason);
803
+ this.signaling.send({ t: "kick", peerId, ban: false, closeReason: reason });
804
+ this.removePeer(peerId, reason, undefined, true);
748
805
  }
749
806
  setPhase(p) {
750
807
  if (p !== "lobby" && p !== "in_game")
@@ -807,7 +864,7 @@ export class Lobby extends Emitter {
807
864
  return;
808
865
  this.sendTo(this.hostPeerId, { type: "ping", n: ++this.pingN, t: this.cfg.clock.now() >>> 0 }, 0, "fast");
809
866
  }
810
- teardown(reason) {
867
+ teardown(reason, close) {
811
868
  if (this.ended)
812
869
  return;
813
870
  this.ended = true;
@@ -820,16 +877,17 @@ export class Lobby extends Emitter {
820
877
  this.cancelPing?.();
821
878
  this.lockstep.stop();
822
879
  this.voice.close();
823
- for (const l of this.links.values()) {
880
+ for (const l of [...this.links.values(), ...this.lingering]) {
824
881
  l.onClose = null;
825
882
  l.onMessage = null;
826
883
  l.close();
827
884
  }
828
885
  this.links.clear();
886
+ this.lingering.clear();
829
887
  this.signaling.onClose = null;
830
888
  this.signaling.onMessage = null;
831
889
  this.signaling.close();
832
- this.emit("sessionEnded", reason);
890
+ this.emit("sessionEnded", reason, close);
833
891
  }
834
892
  /** Total in-flight links (diagnostics and tests). */
835
893
  get linkCount() {
package/dist/lobby.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"lobby.js","sourceRoot":"","sources":["../src/lobby.ts"],"names":[],"mappings":"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","sourcesContent":["import { Chat } from \"./chat.js\";\nimport type { Clock } from \"./clock.js\";\nimport {\n CodecError,\n MAX_FRAME_BYTES,\n MODE_LOCKSTEP,\n MODE_RAW,\n PROTO,\n decodeMessage,\n encodeMessage,\n type Message,\n} from \"./codec.js\";\nimport { Reassembler, splitChunks } from \"./chunking.js\";\nimport { Emitter } from \"./emitter.js\";\nimport type { Hub } from \"./hub.js\";\nimport { Lockstep } from \"./lockstep.js\";\nimport { claimWinsWrapped, pickNewHost } from \"./migration.js\";\nimport { OneLobbyError, type LobbyState, type PeerInfo, type SignalingClient, type ServerMsg } from \"./signaling.js\";\nimport type { ChannelName, IceServer, LinkFactory, PeerLink, SignalPayload } from \"./transport.js\";\nimport { Voice, type VoiceDeps } from \"./voice.js\";\nimport { hostConnections, joinerSocket, type LobbySocket, type LobbySocketOptions } from \"./socket.js\";\n\nexport type Phase = \"lobby\" | \"in_game\";\nexport type Peer = PeerInfo;\n\nexport type LobbyEvents = {\n peerJoined: [Peer];\n /** The peer's data channels are open and the handshake is done: reliable sends reach it now (earlier ones were queued and flushed). */\n peerReady: [Peer];\n /** Joiner: the link to the host is open (the host itself is ready from the start). Also available as `lobby.ready`. */\n ready: [];\n peerLeft: [Peer, reason: string];\n joinRequested: [Peer];\n hostChanged: [hostId: number];\n phase: [Phase];\n message: [from: number, bytes: Uint8Array, channel: ChannelName];\n sessionEnded: [reason: string];\n /** The signaling server went away. The game continues on the data channels (s.9). */\n serverLost: [];\n metaChanged: [Record<string, string>];\n};\n\nexport interface LobbyConfig {\n signaling: SignalingClient;\n state: LobbyState;\n ice: IceServer[];\n links: LinkFactory;\n clock: Clock;\n wall: () => number;\n hashEveryTicks: number;\n relayOnly: boolean;\n voice: VoiceDeps;\n displayName: string;\n /**\n * Joiner: give up on reaching the host after this many ms (0 or absent: wait forever). When the ICE list has a\n * TURN server and the lobby is not relay-only already, the second half of the budget is a relay-only retry.\n * On failure `ready` rejects with OneLobbyError(\"ice_failed\"), the error is reported and the lobby is left.\n */\n readyTimeoutMs?: number;\n /**\n * Direct IP (docs/direct-ip.md): the hub lives in the host, so there is no migration. A joiner that loses the host\n * (link, peer_left, a host_changed from the hub as it shuts down, or the signaling socket) ends with \"host_left\".\n */\n direct?: boolean;\n /**\n * Treat a peer as gone after this many ms without hearing anything from it (0 or absent: off, and a silent peer\n * surfaces only when its link or signaling socket times out, about 30 s). Joiners ping the host every 2 s and the\n * host answers, so the host drops a silent joiner (`peerLeft`, \"timeout\") and a joiner handles a silent host as\n * lost (a direct lobby ends with \"host_left\"). Values under 6000 are raised to 6000.\n */\n peerTimeoutMs?: number;\n /** Host: per-peer cap on incoming raw messages; the excess is dropped before `message` fires or is relayed. */\n rateLimit?: RateLimit;\n}\n\n/** At most `messages` raw messages per peer in any `perMs` window (a fixed window, reset every `perMs`). */\nexport interface RateLimit {\n messages: number;\n perMs: number;\n}\n\n/** The smallest `peerTimeoutMs` honoured: three missed pings. */\nexport const MIN_PEER_TIMEOUT_MS = 6000;\n\n/** The name shown for a peer that chose none: \"Player N\", N = its seat (peer id, join order). */\nexport function seatName(p: PeerInfo): PeerInfo {\n const n = typeof p.name === \"string\" ? p.name.trim() : \"\";\n // \"Player\" is onelobby-server's stand-in for an empty name\n if (n && n !== \"Player\") return p;\n return { ...p, name: `Player ${p.peerId}` };\n}\n\nfunction hasRelay(ice: IceServer[]): boolean {\n return ice.some((s) => (Array.isArray(s.urls) ? s.urls : [s.urls]).some((u) => /^turns?:/i.test(String(u))));\n}\n\nconst HOST_WATCHDOG_MS = 250;\nconst PING_EVERY_MS = 2000;\n\n/** One joined lobby: roster, star of peer links, and the lockstep/chat/voice engines riding on them. */\nexport class Lobby extends Emitter<LobbyEvents> {\n readonly code: string;\n readonly mode: \"lockstep\" | \"raw\";\n readonly tickRate: number;\n readonly lockstep: Lockstep;\n readonly chat: Chat;\n readonly voice: Voice;\n\n localPeerId: number;\n hostPeerId: number;\n phase: Phase;\n meta: Record<string, string>;\n resumeToken: string;\n /** Last measured round trip to the host in ms (joiners), or 0. */\n rtt = 0;\n /**\n * Direct-IP host only (onelobby/direct): the code friends paste to join, e.g. \"6B01-RGFE-P2B\" (docs/direct-ip.md\n * s.2a). Show it with joinCodeKind. Empty when the machine has no IPv4 address, and on joiners.\n */\n joinCode = \"\";\n /** \"internet\": the router forwarded the port and the code carries its public address; \"same_network\": the LAN address. */\n joinCodeKind: \"internet\" | \"same_network\" | \"none\" = \"none\";\n /** Direct-IP host only: this machine's addresses with the port, for an \"Advanced\" fold-out. */\n directAddresses: string[] = [];\n /** Direct-IP host only: how the router port-open went (\"UPnP\", \"no UPnP gateway answered; ...\", \"off\"). */\n portMapping = \"\";\n\n private signaling: SignalingClient;\n private cfg: LobbyConfig;\n private roster = new Map<number, Peer>();\n private links = new Map<number, PeerLink>();\n private connected = new Set<number>(); // host: peers that said hi\n private hiSentTo = new Set<PeerLink>();\n private epoch = 0;\n private ended = false;\n private serverUp = true;\n private cancelWatchdog: (() => void) | null = null;\n private cancelPing: (() => void) | null = null;\n private pingN = 0;\n private chunkId = 1;\n private reassemblers = new Map<number, Reassembler>();\n private hub: Hub;\n private outbox = new Map<number, { msg: Message; route: number; channel?: ChannelName }[]>();\n private markReady: () => void = () => {};\n private failReady: (e: Error) => void = () => {};\n private isReady = false;\n private cancelReadyTimer: (() => void) | null = null;\n private relayRetry = false;\n /** clock.now() of the last frame from each peer (peerTimeoutMs). */\n private lastHeard = new Map<number, number>();\n /** Host: per-peer fixed window for rateLimit. */\n private rate = new Map<number, { start: number; n: number }>();\n /**\n * Resolves when this peer can exchange data: immediately for the host, once the link to the host is open for a\n * joiner. Rejects with OneLobbyError(\"ice_failed\") when the joiner cannot reach the host in `readyTimeoutMs`\n * (or with \"closed\"/\"kicked\" when the lobby ends first).\n */\n readonly ready: Promise<void> = new Promise<void>((res, rej) => {\n this.markReady = () => {\n if (this.isReady) return;\n this.isReady = true;\n this.cancelReadyTimer?.();\n this.cancelReadyTimer = null;\n res();\n };\n this.failReady = rej;\n });\n\n constructor(cfg: LobbyConfig) {\n super();\n this.cfg = cfg;\n this.signaling = cfg.signaling;\n const st = cfg.state;\n this.code = st.code;\n this.mode = st.mode;\n this.tickRate = st.tickRate;\n this.localPeerId = st.you;\n this.hostPeerId = st.hostId;\n this.phase = st.phase;\n this.meta = { ...st.meta };\n this.resumeToken = st.resumeToken;\n for (const p of st.peers) this.roster.set(p.peerId, seatName(p));\n this.ready.catch(() => {}); // a rejection is also reported through errorSink; awaiting `ready` stays optional\n\n const self = this;\n this.hub = {\n get clock() { return self.cfg.clock; },\n get localPeerId() { return self.localPeerId; },\n get hostPeerId() { return self.hostPeerId; },\n get isHost() { return self.isHost; },\n get tickRate() { return self.tickRate; },\n connectedPeers: () => self.connectedPeerIds(),\n sendTo: (peerId, msg, route, channel) => self.sendTo(peerId, msg, route ?? 0, channel),\n sendToHost: (msg, route, channel) => {\n if (!self.isHost) self.sendTo(self.hostPeerId, msg, route ?? 0, channel);\n },\n dropPeer: (peerId, reason) => self.dropPeer(peerId, reason),\n reportError: (e) => self.reportError(e),\n nextChunkId: () => self.chunkId++ >>> 0,\n };\n\n this.lockstep = new Lockstep(this.hub, { hashEveryTicks: cfg.hashEveryTicks });\n this.chat = new Chat(this.hub, cfg.wall, (id) => this.voice.isMutedPeer(id));\n this.voice = new Voice(this.hub, cfg.voice);\n this.lockstep.on(\"started\", () => this.setPhase(\"in_game\"));\n this.lockstep.on(\"error\", (e) => this.reportError(e));\n\n this.signaling.onMessage = (m) => this.onSignaling(m);\n this.signaling.onClose = () => this.onServerClosed();\n\n if (this.isHost) this.markReady();\n else this.armReadyTimer();\n if (this.isHost && this.mode === \"lockstep\") {\n if (this.phase === \"in_game\") this.lockstep.hostStart();\n else this.lockstep.hostIdle();\n }\n this.cancelWatchdog = cfg.clock.setInterval(() => this.watchdog(), HOST_WATCHDOG_MS);\n this.cancelPing = cfg.clock.setInterval(() => this.pingHost(), PING_EVERY_MS);\n }\n\n // ---- state -----------------------------------------------------------------------------------------------------\n\n get isHost(): boolean {\n return this.localPeerId === this.hostPeerId;\n }\n get peers(): Peer[] {\n return [...this.roster.values()].sort((a, b) => a.peerId - b.peerId);\n }\n peer(peerId: number): Peer | undefined {\n return this.roster.get(peerId);\n }\n /** Peers whose link is open and handshake done (host: the ready joiners; joiner: the host once ready). */\n get connectedPeers(): number[] {\n return this.connectedPeerIds();\n }\n\n /**\n * Joiner: the link to the host as a WebSocket-shaped object (text by default), so WebSocket client code runs\n * unchanged. It opens when `ready` resolves and closes when the session ends (`host_left` gives code 1001).\n */\n asWebSocket(opts?: LobbySocketOptions): LobbySocket {\n return joinerSocket(this, opts);\n }\n\n /** Host: `handler(conn)` once per joiner (a WebSocket-shaped connection), the server-side mirror of asWebSocket(). */\n onConnection(handler: (conn: LobbySocket) => void, opts?: LobbySocketOptions): () => void {\n return hostConnections(this, handler, opts);\n }\n\n set snapshotChunkSize(n: number) {\n this.lockstep.chunkSize = n;\n }\n\n /** Current migration epoch (0 until the first host change). */\n get hostEpoch(): number {\n return this.epoch;\n }\n\n /** @internal Host role: create the link to `peerId` and start negotiating (adapters and tests). */\n _offer(peerId: number): PeerLink {\n this.offerTo(peerId);\n return this.links.get(peerId)!;\n }\n\n /** @internal Joiner role: create the answering link to `peerId` (adapters and tests). */\n _answer(peerId: number): PeerLink {\n return this.makeLink(peerId);\n }\n\n /** @internal Called by OneLobby right after construction: the host waits for joiners, a joiner waits for the host's offer. */\n _begin(): void {\n /* joiners are passive until the host offers; hosts create links on peer_joined */\n }\n\n // ---- game-facing actions ---------------------------------------------------------------------------------------\n\n async start(): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can start the game\");\n if (this.phase === \"in_game\") return;\n this.signaling.send({ t: \"phase\", phase: \"in_game\" });\n this.setPhase(\"in_game\");\n if (this.mode === \"lockstep\") this.lockstep.hostStart();\n }\n\n async setMeta(meta: Record<string, string>): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can set metadata\");\n this.meta = { ...meta };\n this.signaling.send({ t: \"meta\", meta });\n this.emit(\"metaChanged\", this.meta);\n }\n\n async kick(peerId: number): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can kick\");\n this.signaling.send({ t: \"kick\", peerId });\n this.removePeer(peerId, \"kicked\");\n }\n\n async approve(peerId: number, ok: boolean): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can approve joins\");\n this.signaling.send({ t: \"approve\", peerId, ok });\n }\n\n async leave(): Promise<void> {\n if (this.ended) return;\n this.signaling.send({ t: \"leave\" });\n this.teardown(\"left\");\n }\n\n /** raw mode (and any extra game data): to one peer. */\n send(peerId: number, bytes: Uint8Array, opts: { channel?: \"reliable\" | \"fast\" } = {}): void {\n const channel = opts.channel ?? \"reliable\";\n if (this.isHost) this.sendTo(peerId, { type: \"raw\", bytes }, this.localPeerId, channel);\n else this.sendTo(this.hostPeerId, { type: \"raw\", bytes }, peerId, channel);\n }\n\n /** To everyone else in the lobby. */\n broadcast(bytes: Uint8Array, opts: { channel?: \"reliable\" | \"fast\" } = {}): void {\n const channel = opts.channel ?? \"reliable\";\n if (this.isHost) {\n // peers whose channels are not open yet get reliable broadcasts queued and flushed in order\n for (const p of this.roster.keys()) if (p !== this.localPeerId) this.sendTo(p, { type: \"raw\", bytes }, this.localPeerId, channel);\n } else {\n this.sendTo(this.hostPeerId, { type: \"raw\", bytes }, 0, channel);\n }\n }\n\n // ---- sending ---------------------------------------------------------------------------------------------------\n\n private channelFor(msg: Message): ChannelName {\n if (msg.type === \"voice\") return \"voice\";\n if (msg.type === \"ping\" || msg.type === \"pong\") return \"fast\";\n return \"reliable\";\n }\n\n private sendTo(peerId: number, msg: Message, route: number, channel?: ChannelName): void {\n const link = this.links.get(peerId);\n const ch0 = channel ?? this.channelFor(msg);\n const queueable = msg.type === \"raw\" || msg.type === \"chat\" || msg.type === \"cmd\";\n // game data to a host-side peer waits for its `hi`; protocol messages only need the link\n const ready = !!link?.isOpen && (!queueable || !this.isHost || this.connected.has(peerId));\n if (!ready) {\n // Reliable game data for a peer that is in the roster (or is the host) but not connected yet waits for its handshake.\n const known = this.roster.has(peerId) || peerId === this.hostPeerId;\n if (queueable && ch0 === \"reliable\" && known && !this.ended) {\n let q = this.outbox.get(peerId);\n if (!q) this.outbox.set(peerId, (q = []));\n if (q.length >= 1000) q.shift();\n q.push({ msg, route, channel });\n }\n return;\n }\n if (!link) return;\n try {\n const ch = ch0;\n let bytes: Uint8Array;\n try {\n bytes = encodeMessage(msg, route);\n } catch (e) {\n if (!(e instanceof CodecError) || e.code !== \"too_long\") throw e;\n bytes = encodeMessage(msg, route, true);\n }\n if (bytes.length > MAX_FRAME_BYTES) {\n // Oversized frame: send the whole inner frame as a chunk set (spec/binary.md \"Large non-snapshot frames\").\n for (const c of splitChunks(this.chunkId++ >>> 0, bytes)) link.send(ch, encodeMessage(c, route));\n } else {\n link.send(ch, bytes);\n }\n } catch (e) {\n this.reportError(e instanceof Error ? e : new Error(String(e)));\n }\n }\n\n private connectedPeerIds(): number[] {\n if (this.isHost) return [...this.connected].filter((id) => this.links.get(id)?.isOpen).sort((a, b) => a - b);\n const l = this.links.get(this.hostPeerId);\n return l?.isOpen ? [this.hostPeerId] : [];\n }\n\n private reportError(e: Error): void {\n this.errorSink?.(e);\n }\n /** @internal set by OneLobby so lobby errors reach `kit.on(\"error\")`. */\n errorSink: ((e: Error) => void) | null = null;\n /** @internal set by OneLobby: the server issued a new resume token (rememberSeat). */\n seatSink: ((token: string) => void) | null = null;\n\n // ---- joiner connect timeout -------------------------------------------------------------------------------------\n\n private armReadyTimer(): void {\n const total = this.cfg.readyTimeoutMs ?? 0;\n if (!(total > 0)) return;\n const canRelay = !this.cfg.relayOnly && hasRelay(this.cfg.ice);\n const first = canRelay ? Math.ceil(total / 2) : total;\n this.cancelReadyTimer = this.cfg.clock.setTimeout(() => {\n if (this.isReady || this.ended) return;\n if (canRelay) this.retryRelayed(total - first);\n else this.giveUpConnecting();\n }, first);\n }\n\n /** The direct attempt stalled: dial the host ourselves through the TURN relay (a host answers any offer). */\n private retryRelayed(budget: number): void {\n this.relayRetry = true;\n const link = this.makeLink(this.hostPeerId, true);\n link.startOffer();\n this.cancelReadyTimer = this.cfg.clock.setTimeout(() => {\n if (!this.isReady && !this.ended) this.giveUpConnecting();\n }, budget);\n }\n\n private giveUpConnecting(): void {\n const err = new OneLobbyError(\"ice_failed\", `could not open a connection to the host${this.relayRetry ? \" (direct or relayed)\" : \"\"}`);\n this.failReady(err);\n this.reportError(err);\n if (this.ended) return;\n this.signaling.send({ t: \"leave\" });\n this.teardown(\"ice_failed\");\n }\n\n // ---- links -----------------------------------------------------------------------------------------------------\n\n private makeLink(peerId: number, relayOnly = this.cfg.relayOnly): PeerLink {\n const old = this.links.get(peerId);\n if (old) {\n old.onClose = null;\n old.onMessage = null;\n old.close();\n }\n const link = this.cfg.links.create({ remoteId: peerId, iceServers: this.cfg.ice, relayOnly });\n this.links.set(peerId, link);\n link.onSignal = (s) => this.signaling.send({ t: \"signal\", to: peerId, ...s });\n link.onOpen = () => this.onLinkOpen(peerId, link);\n link.onClose = (reason) => this.onLinkClosed(peerId, link, reason);\n link.onMessage = (ch, bytes) => this.onData(peerId, ch, bytes);\n link.onPath = (path) => this.signaling.send({ t: \"path\", path });\n return link;\n }\n\n /** Host side: offer to a joiner. */\n private offerTo(peerId: number): void {\n const link = this.makeLink(peerId);\n link.startOffer();\n }\n\n private onLinkOpen(peerId: number, link: PeerLink): void {\n if (this.isHost) {\n // Joiner speaks first (`hi`). After a migration the new host announces itself so the joiner knows who won.\n if (this.epoch > 0) this.sendTo(peerId, { type: \"host_claim\", epoch: this.epoch, hostId: this.localPeerId, tick: this.lockstep.lastTick }, 0);\n return;\n }\n if (peerId === this.hostPeerId) this.sendHi(link);\n // else: an unexpected offerer; wait for its host_claim before trusting it\n }\n\n private sendHi(link: PeerLink): void {\n if (this.hiSentTo.has(link)) return;\n this.hiSentTo.add(link);\n this.lockstep.touch();\n link.send(\"reliable\", encodeMessage(this.lockstep.hiMessage(this.localPeerId)));\n this.markReady();\n this.emit(\"ready\");\n this.emit(\"peerReady\", this.roster.get(link.remoteId) ?? { peerId: link.remoteId, name: \"\" });\n this.flush(link.remoteId);\n }\n\n private onLinkClosed(peerId: number, link: PeerLink, _reason: string): void {\n if (this.links.get(peerId) !== link) return; // replaced\n this.links.delete(peerId);\n this.hiSentTo.delete(link);\n if (this.ended) return;\n if (this.isHost) {\n this.connected.delete(peerId);\n this.lockstep.onPeerLeft(peerId);\n this.voice.onPeerLeft(peerId);\n // The server announces the departure; if it is gone, drop the peer ourselves.\n if (!this.serverUp && this.roster.has(peerId)) this.removePeer(peerId, \"timeout\");\n } else if (peerId === this.hostPeerId) {\n // Never connected yet (ICE failed): not a host loss. The ready timer retries over the relay or gives up.\n if (!this.isReady && this.cancelReadyTimer) return;\n this.handleHostLost(\"link closed\");\n }\n }\n\n // ---- data channel dispatch -------------------------------------------------------------------------------------\n\n private onData(from: number, channel: ChannelName, bytes: Uint8Array, reassembled = false): void {\n let d;\n try {\n d = decodeMessage(bytes, reassembled);\n } catch (e) {\n this.reportError(e instanceof Error ? e : new Error(String(e)));\n return;\n }\n if (!d) return;\n if (!reassembled) this.lastHeard.set(from, this.cfg.clock.now());\n const { msg, route } = d;\n switch (msg.type) {\n case \"hi\":\n if (this.isHost) this.onHi(from, msg.lastTick);\n break;\n case \"welcome_dc\":\n if (!this.isHost) {\n if (msg.hostId !== this.hostPeerId) this.setHost(msg.hostId);\n this.lockstep.touch();\n }\n break;\n case \"cmd\": case \"frame\": case \"hash\": case \"desync\":\n case \"snapshot_req\": case \"snapshot\":\n if (from === this.hostPeerId || this.isHost) this.lockstep.handle(from, msg);\n break;\n case \"chunk\": {\n if (reassembled) break; // a chunk set never nests another\n let r = this.reassemblers.get(from);\n if (!r) this.reassemblers.set(from, (r = new Reassembler()));\n let whole;\n try {\n whole = r.push(msg);\n } catch (e) {\n this.reportError(e instanceof Error ? e : new Error(String(e)));\n break;\n }\n if (!whole) break;\n if (this.lockstep.snapshotPending && from === this.hostPeerId) this.lockstep.onSnapshotPayload(whole);\n else this.onData(from, channel, whole, true); // an oversized inner frame\n break;\n }\n case \"chat\": case \"chat_history\": case \"chat_reject\":\n this.chat.handle(from, route, msg);\n break;\n case \"voice\":\n if (channel === \"voice\") this.voice.handle(from, route, msg); // a voice frame on another channel is ignored\n break;\n case \"raw\":\n this.onRaw(from, route, msg.bytes, channel);\n break;\n case \"ping\":\n this.sendTo(from, { type: \"pong\", n: msg.n, t: msg.t }, 0, \"fast\");\n break;\n case \"pong\":\n this.rtt = Math.max(0, (this.cfg.clock.now() >>> 0) - msg.t);\n break;\n case \"host_claim\":\n this.onHostClaim(from, msg.epoch, msg.hostId);\n break;\n }\n }\n\n private onHi(from: number, lastTick: number): void {\n this.connected.add(from);\n this.sendTo(from, {\n type: \"welcome_dc\",\n // the tick the snapshot will carry (the game's applied tick), so welcome_dc.tick == snapshot.tick even when\n // the game loop has not yet consumed every emitted frame; 0 before the game starts\n tick: this.mode === \"lockstep\" ? this.lockstep.currentTick : 0,\n tickRate: this.tickRate,\n mode: this.mode === \"lockstep\" ? MODE_LOCKSTEP : MODE_RAW,\n hostId: this.localPeerId,\n }, 0);\n this.chat.sendHistory(from);\n if (this.mode === \"lockstep\") this.lockstep.onPeerHi(from, lastTick);\n this.emit(\"peerReady\", this.roster.get(from) ?? { peerId: from, name: \"\" });\n this.flush(from);\n }\n\n private flush(peerId: number): void {\n const q = this.outbox.get(peerId);\n if (!q) return;\n this.outbox.delete(peerId);\n for (const m of q) this.sendTo(peerId, m.msg, m.route, m.channel);\n }\n\n private onRaw(from: number, route: number, bytes: Uint8Array, channel: ChannelName): void {\n if (!this.isHost) {\n this.emit(\"message\", route, bytes, channel);\n return;\n }\n if (!this.allowRaw(from)) return;\n if (route === 0 || route === this.localPeerId) {\n this.emit(\"message\", from, bytes, channel);\n }\n if (route === 0) {\n for (const p of this.connectedPeerIds()) if (p !== from) this.sendTo(p, { type: \"raw\", bytes }, from, channel);\n } else if (route !== this.localPeerId) {\n this.sendTo(route, { type: \"raw\", bytes }, from, channel);\n }\n }\n\n private allowRaw(from: number): boolean {\n const lim = this.cfg.rateLimit;\n if (!lim || !(lim.messages > 0) || !(lim.perMs > 0)) return true;\n const now = this.cfg.clock.now();\n let w = this.rate.get(from);\n if (!w || now - w.start >= lim.perMs) this.rate.set(from, (w = { start: now, n: 0 }));\n return ++w.n <= lim.messages;\n }\n\n // ---- migration -------------------------------------------------------------------------------------------------\n\n private setHost(hostId: number): void {\n if (hostId === this.hostPeerId) return;\n this.hostPeerId = hostId;\n this.emit(\"hostChanged\", hostId);\n }\n\n /** The host is gone (link closed, no frames for 3 s, or the server said so): run the s.9 rule. */\n private handleHostLost(reason: string): void {\n if (this.isHost || this.ended) return;\n if (this.cfg.direct) {\n this.teardown(\"host_left\");\n return;\n }\n const failed = this.hostPeerId;\n const gone = this.roster.get(failed);\n if (gone) {\n this.roster.delete(failed);\n this.emit(\"peerLeft\", gone, reason === \"link closed\" ? \"timeout\" : reason);\n }\n const old = this.links.get(failed);\n if (old) {\n old.onClose = null;\n old.onMessage = null;\n old.close();\n this.links.delete(failed);\n this.hiSentTo.delete(old);\n }\n const candidate = pickNewHost([...this.roster.keys(), this.localPeerId], failed) ?? this.localPeerId;\n if (candidate === this.localPeerId) this.becomeHost();\n // else: wait for the candidate's host_claim (or the server's host_changed); it offers to us and we answer with hi\n }\n\n private becomeHost(): void {\n this.epoch = (this.epoch + 1) & 0xffff;\n this.hostPeerId = this.localPeerId;\n this.markReady();\n this.connected.clear();\n this.hiSentTo.clear();\n this.lastHeard.clear(); // joiners spoke to the old host; their clocks start when they say hi to us\n this.lockstep.becomeHost();\n this.emit(\"hostChanged\", this.localPeerId);\n if (this.serverUp) this.signaling.send({ t: \"host_changed\", hostId: this.localPeerId, epoch: this.epoch });\n for (const p of this.roster.keys()) {\n if (p !== this.localPeerId) this.offerTo(p);\n }\n }\n\n private onHostClaim(from: number, epoch: number, hostId: number): void {\n const mine = { epoch: this.epoch, hostId: this.hostPeerId };\n const theirs = { epoch, hostId };\n if (hostId === this.hostPeerId && epoch === this.epoch && !this.isHost) {\n const l = this.links.get(from);\n if (l) this.sendHi(l);\n return;\n }\n if (!claimWinsWrapped(theirs, mine)) return; // we hold the better claim\n const wasHost = this.isHost;\n this.epoch = epoch;\n if (wasHost) {\n // We lose: demote. Everyone else will be offered to by the winner.\n for (const [id, l] of this.links) {\n if (id === from) continue;\n l.onClose = null;\n l.onMessage = null;\n l.close();\n this.links.delete(id);\n }\n this.connected.clear();\n this.lockstep.becomeJoiner();\n }\n this.setHost(hostId);\n const link = this.links.get(from);\n if (link && from === hostId) this.sendHi(link);\n }\n\n // ---- signaling -------------------------------------------------------------------------------------------------\n\n private onSignaling(m: ServerMsg): void {\n switch (m.t) {\n case \"peer_joined\": {\n if (!m.peer || this.roster.has((m.peer as Peer).peerId)) return;\n const peer = seatName(m.peer as Peer);\n this.roster.set(peer.peerId, peer);\n this.emit(\"peerJoined\", peer);\n if (this.isHost) this.offerTo(peer.peerId);\n break;\n }\n case \"peer_left\":\n this.removePeer(Number(m.peerId), String(m.reason ?? \"left\"));\n break;\n case \"host_changed\": {\n if (this.cfg.direct) {\n // the hub promotes a joiner as the host leaves; in direct mode the hub is going with it\n if (!this.isHost) this.teardown(\"host_left\");\n break;\n }\n const id = Number(m.hostId);\n if (typeof m.epoch === \"number\" && m.epoch > this.epoch) this.epoch = m.epoch & 0xffff;\n if (id === this.hostPeerId) break;\n if (id === this.localPeerId && !this.isHost) {\n const failed = this.hostPeerId;\n this.roster.delete(failed);\n this.becomeHost();\n } else {\n this.setHost(id);\n }\n break;\n }\n case \"join_request\":\n this.emit(\"joinRequested\", seatName(m.peer as Peer));\n break;\n case \"lobby\": {\n const st = m as unknown as LobbyState;\n this.meta = { ...st.meta };\n if (st.resumeToken && st.resumeToken !== this.resumeToken) {\n this.resumeToken = st.resumeToken;\n this.seatSink?.(this.resumeToken);\n }\n this.roster = new Map(st.peers.map((p) => [p.peerId, seatName(p)]));\n if (st.hostId !== this.hostPeerId && !this.isHost) this.setHost(st.hostId);\n this.setPhase(st.phase);\n break;\n }\n case \"meta\":\n this.meta = { ...(m.meta as Record<string, string>) };\n this.emit(\"metaChanged\", this.meta);\n break;\n case \"phase\":\n this.setPhase(m.phase as Phase);\n break;\n case \"signal\":\n void this.onSignal(Number(m.from), m as unknown as SignalPayload);\n break;\n case \"error\":\n if (m.code === \"kicked\") this.teardown(\"kicked\");\n else this.reportError(new OneLobbyError(String(m.code), String(m.msg ?? \"\"), m.data as Record<string, unknown> | undefined));\n break;\n }\n }\n\n private async onSignal(from: number, s: SignalPayload): Promise<void> {\n let link = this.links.get(from);\n if (s.sdp?.type === \"offer\") {\n // We are the answerer; an offer always comes from the (new) host.\n link = this.makeLink(from);\n }\n if (!link) return;\n const payload: SignalPayload = {};\n if (s.sdp) payload.sdp = s.sdp;\n if (s.ice) payload.ice = s.ice;\n await link.handleSignal(payload);\n }\n\n private removePeer(peerId: number, reason: string): void {\n const peer = this.roster.get(peerId);\n if (peerId === this.localPeerId) {\n this.teardown(reason === \"kicked\" ? \"kicked\" : reason);\n return;\n }\n if (peer) this.roster.delete(peerId);\n const link = this.links.get(peerId);\n if (link && peerId !== this.hostPeerId) {\n link.onClose = null;\n link.onMessage = null;\n link.close();\n this.links.delete(peerId);\n this.hiSentTo.delete(link);\n }\n this.connected.delete(peerId);\n this.outbox.delete(peerId);\n this.lastHeard.delete(peerId);\n this.rate.delete(peerId);\n this.lockstep.onPeerLeft(peerId);\n this.chat.onPeerLeft(peerId);\n this.voice.onPeerLeft(peerId);\n if (peer) this.emit(\"peerLeft\", peer, reason);\n if (peerId === this.hostPeerId && !this.isHost) {\n this.handleHostLost(reason);\n }\n }\n\n private dropPeer(peerId: number, reason: string): void {\n this.signaling.send({ t: \"kick\", peerId });\n this.removePeer(peerId, reason);\n }\n\n private setPhase(p: Phase): void {\n if (p !== \"lobby\" && p !== \"in_game\") return;\n if (this.phase === p) return;\n this.phase = p;\n if (p === \"in_game\" && !this.lockstep.started) this.lockstep.markStarted();\n this.emit(\"phase\", p);\n }\n\n private onServerClosed(): void {\n if (this.ended) return;\n if (this.cfg.direct && !this.isHost) {\n this.teardown(\"host_left\");\n return;\n }\n this.serverUp = false;\n this.emit(\"serverLost\");\n // Alone with no peers: nothing keeps this session alive.\n if (this.links.size === 0 && this.roster.size <= 1) this.teardown(\"server_lost\");\n }\n\n // ---- housekeeping ----------------------------------------------------------------------------------------------\n\n private watchdog(): void {\n if (this.ended) return;\n const timeout = this.cfg.peerTimeoutMs ?? 0;\n if (timeout > 0) this.dropSilent(Math.max(timeout, MIN_PEER_TIMEOUT_MS));\n if (this.ended || this.isHost) return;\n if (this.mode === \"lockstep\" && this.lockstep.hostSilent()) {\n this.lockstep.touch();\n this.lockstep.pokeHost(); // a live-but-stalled host answers with a snapshot; a dead one is replaced below\n this.handleHostLost(\"timeout\");\n }\n }\n\n /** peerTimeoutMs: the host drops joiners it has not heard from; a joiner handles a silent host as lost. */\n private dropSilent(timeout: number): void {\n const now = this.cfg.clock.now();\n if (this.isHost) {\n for (const id of [...this.connected]) {\n const last = this.lastHeard.get(id);\n if (last !== undefined && now - last > timeout) this.removePeer(id, \"timeout\");\n }\n } else if (this.isReady) {\n const last = this.lastHeard.get(this.hostPeerId);\n if (last !== undefined && now - last > timeout) {\n this.lastHeard.delete(this.hostPeerId);\n this.handleHostLost(\"timeout\");\n }\n }\n }\n\n private pingHost(): void {\n if (this.ended || this.isHost) return;\n this.sendTo(this.hostPeerId, { type: \"ping\", n: ++this.pingN, t: this.cfg.clock.now() >>> 0 }, 0, \"fast\");\n }\n\n private teardown(reason: string): void {\n if (this.ended) return;\n this.ended = true;\n this.cancelReadyTimer?.();\n if (!this.isReady) {\n const code = reason === \"ice_failed\" || reason === \"kicked\" ? reason : \"closed\";\n this.failReady(new OneLobbyError(code, `the lobby ended before connecting (${reason})`));\n }\n this.cancelWatchdog?.();\n this.cancelPing?.();\n this.lockstep.stop();\n this.voice.close();\n for (const l of this.links.values()) {\n l.onClose = null;\n l.onMessage = null;\n l.close();\n }\n this.links.clear();\n this.signaling.onClose = null;\n this.signaling.onMessage = null;\n this.signaling.close();\n this.emit(\"sessionEnded\", reason);\n }\n\n /** Total in-flight links (diagnostics and tests). */\n get linkCount(): number {\n return this.links.size;\n }\n}\n\nexport { PROTO };\n"]}
1
+ {"version":3,"file":"lobby.js","sourceRoot":"","sources":["../src/lobby.ts"],"names":[],"mappings":"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","sourcesContent":["import { Chat } from \"./chat.js\";\nimport type { Clock } from \"./clock.js\";\nimport {\n CodecError,\n MAX_FRAME_BYTES,\n MODE_LOCKSTEP,\n MODE_RAW,\n PROTO,\n decodeMessage,\n encodeMessage,\n type Message,\n} from \"./codec.js\";\nimport { Reassembler, splitChunks } from \"./chunking.js\";\nimport { Emitter } from \"./emitter.js\";\nimport type { Hub } from \"./hub.js\";\nimport { Lockstep } from \"./lockstep.js\";\nimport { claimWinsWrapped, pickNewHost } from \"./migration.js\";\nimport { OneLobbyError, type LobbyState, type PeerInfo, type SignalingClient, type ServerMsg } from \"./signaling.js\";\nimport type { ChannelName, IceServer, LinkFactory, PeerLink, SignalPayload } from \"./transport.js\";\nimport { Voice, type VoiceDeps } from \"./voice.js\";\nimport { hostConnections, joinerSocket, type LobbySocket, type LobbySocketOptions } from \"./socket.js\";\n\nexport type Phase = \"lobby\" | \"in_game\";\n/** The close code and reason a host chose with `kick()` / `disconnect()`, passed to the removed player's sockets. */\nexport interface CloseInfo {\n code?: number;\n reason?: string;\n}\n/** Options for `lobby.kick()`. */\nexport interface KickOptions {\n /** Default true: the player's address cannot rejoin this lobby while it lasts. false = `disconnect()`. */\n ban?: boolean;\n /** Close code for the player's `asWebSocket()` onclose: 1000 or 3000-4999. */\n code?: number;\n /** Close reason for that onclose, at most 120 characters. */\n reason?: string;\n}\nexport type Peer = PeerInfo;\n\nexport type LobbyEvents = {\n peerJoined: [Peer];\n /** The peer's data channels are open and the handshake is done: reliable sends reach it now (earlier ones were queued and flushed). */\n peerReady: [Peer];\n /** Joiner: the link to the host is open (the host itself is ready from the start). Also available as `lobby.ready`. */\n ready: [];\n /** reason \"left\", \"kicked\", \"disconnected\" (kick with ban false), \"timeout\", ...; `close` when the host gave one. */\n peerLeft: [Peer, reason: string, close?: CloseInfo];\n joinRequested: [Peer];\n hostChanged: [hostId: number];\n phase: [Phase];\n message: [from: number, bytes: Uint8Array, channel: ChannelName];\n /** `close` is the code and reason the host gave when it removed this player (`kick()` / `disconnect()`). */\n sessionEnded: [reason: string, close?: CloseInfo];\n /** The signaling server went away. The game continues on the data channels (s.9). */\n serverLost: [];\n metaChanged: [Record<string, string>];\n};\n\nexport interface LobbyConfig {\n signaling: SignalingClient;\n state: LobbyState;\n ice: IceServer[];\n links: LinkFactory;\n clock: Clock;\n wall: () => number;\n hashEveryTicks: number;\n relayOnly: boolean;\n voice: VoiceDeps;\n displayName: string;\n /**\n * Joiner: give up on reaching the host after this many ms (0 or absent: wait forever). When the ICE list has a\n * TURN server and the lobby is not relay-only already, the second half of the budget is a relay-only retry.\n * On failure `ready` rejects with OneLobbyError(\"ice_failed\"), the error is reported and the lobby is left.\n */\n readyTimeoutMs?: number;\n /**\n * Direct IP (docs/direct-ip.md): the hub lives in the host, so there is no migration. A joiner that loses the host\n * (link, peer_left, a host_changed from the hub as it shuts down, or the signaling socket) ends with \"host_left\".\n */\n direct?: boolean;\n /**\n * Treat a peer as gone after this many ms without hearing anything from it (0 or absent: off, and a silent peer\n * surfaces only when its link or signaling socket times out, about 30 s). Joiners ping the host every 2 s and the\n * host answers, so the host drops a silent joiner (`peerLeft`, \"timeout\") and a joiner handles a silent host as\n * lost (a direct lobby ends with \"host_left\"). Values under 6000 are raised to 6000.\n */\n peerTimeoutMs?: number;\n /** Host: per-peer cap on incoming raw messages; the excess is dropped before `message` fires or is relayed. */\n rateLimit?: RateLimit;\n}\n\n/** At most `messages` raw messages per peer in any `perMs` window (a fixed window, reset every `perMs`). */\nexport interface RateLimit {\n messages: number;\n perMs: number;\n}\n\n/** The smallest `peerTimeoutMs` honoured: three missed pings. */\nexport const MIN_PEER_TIMEOUT_MS = 6000;\n/** Host: how long a kicked / disconnected peer's link stays open for the hub's notice to reach it first. */\nexport const KICK_LINGER_MS = 3000;\n\n/** The name shown for a peer that chose none: \"Player N\", N = its seat (peer id, join order). */\nexport function seatName(p: PeerInfo): PeerInfo {\n const n = typeof p.name === \"string\" ? p.name.trim() : \"\";\n // \"Player\" is onelobby-server's stand-in for an empty name\n if (n && n !== \"Player\") return p;\n return { ...p, name: `Player ${p.peerId}` };\n}\n\nfunction hasRelay(ice: IceServer[]): boolean {\n return ice.some((s) => (Array.isArray(s.urls) ? s.urls : [s.urls]).some((u) => /^turns?:/i.test(String(u))));\n}\n\nconst HOST_WATCHDOG_MS = 250;\nconst PING_EVERY_MS = 2000;\n\n/** One joined lobby: roster, star of peer links, and the lockstep/chat/voice engines riding on them. */\nexport class Lobby extends Emitter<LobbyEvents> {\n readonly code: string;\n readonly mode: \"lockstep\" | \"raw\";\n readonly tickRate: number;\n readonly lockstep: Lockstep;\n readonly chat: Chat;\n readonly voice: Voice;\n\n localPeerId: number;\n hostPeerId: number;\n phase: Phase;\n meta: Record<string, string>;\n resumeToken: string;\n /** Last measured round trip to the host in ms (joiners), or 0. */\n rtt = 0;\n /**\n * Direct-IP host only (onelobby/direct): the code friends paste to join, e.g. \"6B01-RGFE-P2B\" (docs/direct-ip.md\n * s.2a). Show it with joinCodeKind. Empty when the machine has no IPv4 address, and on joiners.\n */\n joinCode = \"\";\n /** \"internet\": the router forwarded the port and the code carries its public address; \"same_network\": the LAN address. */\n joinCodeKind: \"internet\" | \"same_network\" | \"none\" = \"none\";\n /** Direct-IP host only: this machine's addresses with the port, for an \"Advanced\" fold-out. */\n directAddresses: string[] = [];\n /** Direct-IP host only: how the router port-open went (\"UPnP\", \"no UPnP gateway answered; ...\", \"off\"). */\n portMapping = \"\";\n\n private signaling: SignalingClient;\n private cfg: LobbyConfig;\n private roster = new Map<number, Peer>();\n private links = new Map<number, PeerLink>();\n private connected = new Set<number>(); // host: peers that said hi\n private hiSentTo = new Set<PeerLink>();\n private epoch = 0;\n private ended = false;\n private serverUp = true;\n private cancelWatchdog: (() => void) | null = null;\n private cancelPing: (() => void) | null = null;\n private pingN = 0;\n private chunkId = 1;\n private reassemblers = new Map<number, Reassembler>();\n private hub: Hub;\n private outbox = new Map<number, { msg: Message; route: number; channel?: ChannelName }[]>();\n private markReady: () => void = () => {};\n private failReady: (e: Error) => void = () => {};\n private isReady = false;\n private cancelReadyTimer: (() => void) | null = null;\n private relayRetry = false;\n /** clock.now() of the last frame from each peer (peerTimeoutMs). */\n private lastHeard = new Map<number, number>();\n /** Host: links of kicked / disconnected peers, kept open briefly (removePeer `linger`). */\n private readonly lingering = new Set<PeerLink>();\n /** Host: per-peer fixed window for rateLimit. */\n private rate = new Map<number, { start: number; n: number }>();\n /**\n * Resolves when this peer can exchange data: immediately for the host, once the link to the host is open for a\n * joiner. Rejects with OneLobbyError(\"ice_failed\") when the joiner cannot reach the host in `readyTimeoutMs`\n * (or with \"closed\"/\"kicked\" when the lobby ends first; \"closed\" also when the host disconnected it).\n */\n readonly ready: Promise<void> = new Promise<void>((res, rej) => {\n this.markReady = () => {\n if (this.isReady) return;\n this.isReady = true;\n this.cancelReadyTimer?.();\n this.cancelReadyTimer = null;\n res();\n };\n this.failReady = rej;\n });\n\n constructor(cfg: LobbyConfig) {\n super();\n this.cfg = cfg;\n this.signaling = cfg.signaling;\n const st = cfg.state;\n this.code = st.code;\n this.mode = st.mode;\n this.tickRate = st.tickRate;\n this.localPeerId = st.you;\n this.hostPeerId = st.hostId;\n this.phase = st.phase;\n this.meta = { ...st.meta };\n this.resumeToken = st.resumeToken;\n for (const p of st.peers) this.roster.set(p.peerId, seatName(p));\n this.ready.catch(() => {}); // a rejection is also reported through errorSink; awaiting `ready` stays optional\n\n const self = this;\n this.hub = {\n get clock() { return self.cfg.clock; },\n get localPeerId() { return self.localPeerId; },\n get hostPeerId() { return self.hostPeerId; },\n get isHost() { return self.isHost; },\n get tickRate() { return self.tickRate; },\n connectedPeers: () => self.connectedPeerIds(),\n sendTo: (peerId, msg, route, channel) => self.sendTo(peerId, msg, route ?? 0, channel),\n sendToHost: (msg, route, channel) => {\n if (!self.isHost) self.sendTo(self.hostPeerId, msg, route ?? 0, channel);\n },\n dropPeer: (peerId, reason) => self.dropPeer(peerId, reason),\n reportError: (e) => self.reportError(e),\n nextChunkId: () => self.chunkId++ >>> 0,\n };\n\n this.lockstep = new Lockstep(this.hub, { hashEveryTicks: cfg.hashEveryTicks });\n this.chat = new Chat(this.hub, cfg.wall, (id) => this.voice.isMutedPeer(id));\n this.voice = new Voice(this.hub, cfg.voice);\n this.lockstep.on(\"started\", () => this.setPhase(\"in_game\"));\n this.lockstep.on(\"error\", (e) => this.reportError(e));\n\n this.signaling.onMessage = (m) => this.onSignaling(m);\n this.signaling.onClose = () => this.onServerClosed();\n\n if (this.isHost) this.markReady();\n else this.armReadyTimer();\n if (this.isHost && this.mode === \"lockstep\") {\n if (this.phase === \"in_game\") this.lockstep.hostStart();\n else this.lockstep.hostIdle();\n }\n this.cancelWatchdog = cfg.clock.setInterval(() => this.watchdog(), HOST_WATCHDOG_MS);\n this.cancelPing = cfg.clock.setInterval(() => this.pingHost(), PING_EVERY_MS);\n }\n\n // ---- state -----------------------------------------------------------------------------------------------------\n\n get isHost(): boolean {\n return this.localPeerId === this.hostPeerId;\n }\n get peers(): Peer[] {\n return [...this.roster.values()].sort((a, b) => a.peerId - b.peerId);\n }\n peer(peerId: number): Peer | undefined {\n return this.roster.get(peerId);\n }\n /** Peers whose link is open and handshake done (host: the ready joiners; joiner: the host once ready). */\n get connectedPeers(): number[] {\n return this.connectedPeerIds();\n }\n\n /**\n * Joiner: the link to the host as a WebSocket-shaped object (text by default), so WebSocket client code runs\n * unchanged. It opens when `ready` resolves and closes when the session ends (`host_left` gives code 1001).\n */\n asWebSocket(opts?: LobbySocketOptions): LobbySocket {\n return joinerSocket(this, opts);\n }\n\n /** Host: `handler(conn)` once per joiner (a WebSocket-shaped connection), the server-side mirror of asWebSocket(). */\n onConnection(handler: (conn: LobbySocket) => void, opts?: LobbySocketOptions): () => void {\n return hostConnections(this, handler, opts);\n }\n\n set snapshotChunkSize(n: number) {\n this.lockstep.chunkSize = n;\n }\n\n /** Current migration epoch (0 until the first host change). */\n get hostEpoch(): number {\n return this.epoch;\n }\n\n /** @internal Host role: create the link to `peerId` and start negotiating (adapters and tests). */\n _offer(peerId: number): PeerLink {\n this.offerTo(peerId);\n return this.links.get(peerId)!;\n }\n\n /** @internal Joiner role: create the answering link to `peerId` (adapters and tests). */\n _answer(peerId: number): PeerLink {\n return this.makeLink(peerId);\n }\n\n /** @internal Called by OneLobby right after construction: the host waits for joiners, a joiner waits for the host's offer. */\n _begin(): void {\n /* joiners are passive until the host offers; hosts create links on peer_joined */\n }\n\n // ---- game-facing actions ---------------------------------------------------------------------------------------\n\n async start(): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can start the game\");\n if (this.phase === \"in_game\") return;\n this.signaling.send({ t: \"phase\", phase: \"in_game\" });\n this.setPhase(\"in_game\");\n if (this.mode === \"lockstep\") this.lockstep.hostStart();\n }\n\n async setMeta(meta: Record<string, string>): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can set metadata\");\n this.meta = { ...meta };\n this.signaling.send({ t: \"meta\", meta });\n this.emit(\"metaChanged\", this.meta);\n }\n\n /**\n * Host: removes a player. By default it is a ban: the hub refuses that player's address for the rest of this lobby\n * (a new tab or a reload included). `{ ban: false }` is `disconnect()`. `code` / `reason` reach the player's\n * `asWebSocket()` onclose (and `sessionEnded`'s second argument); without them its socket closes with 4000 \"kicked\".\n */\n async kick(peerId: number, opts: KickOptions = {}): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can kick\");\n const { ban = true, code, reason } = opts;\n if (code !== undefined && !(code === 1000 || (Number.isInteger(code) && code >= 3000 && code <= 4999)))\n throw new RangeError(\"close code must be 1000 or 3000-4999\");\n if (reason !== undefined && reason.length > 120) throw new RangeError(\"close reason must be at most 120 characters\");\n const msg: Record<string, unknown> = { t: \"kick\", peerId };\n if (!ban) msg.ban = false;\n if (code !== undefined) msg.closeCode = code;\n if (reason !== undefined) msg.closeReason = reason;\n this.signaling.send(msg as { t: \"kick\"; peerId: number });\n const close: CloseInfo | undefined = code !== undefined || reason !== undefined ? { code, reason } : undefined;\n this.removePeer(peerId, ban ? \"kicked\" : \"disconnected\", close, true);\n }\n\n /**\n * Host: ends one player's connection without a ban, like a server closing one WebSocket. The player's\n * `asWebSocket()` gets onclose with `code` (default 1000) and `reason` (default \"disconnected\"), its lobby ends with\n * `sessionEnded(\"disconnected\")`, and it may join again (a new tab, a reload). Same as `kick(peerId, { ban: false, code, reason })`.\n */\n disconnect(peerId: number, code?: number, reason?: string): Promise<void> {\n return this.kick(peerId, { ban: false, code, reason });\n }\n\n async approve(peerId: number, ok: boolean): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can approve joins\");\n this.signaling.send({ t: \"approve\", peerId, ok });\n }\n\n async leave(): Promise<void> {\n if (this.ended) return;\n this.signaling.send({ t: \"leave\" });\n this.teardown(\"left\");\n }\n\n /** raw mode (and any extra game data): to one peer. */\n send(peerId: number, bytes: Uint8Array, opts: { channel?: \"reliable\" | \"fast\" } = {}): void {\n const channel = opts.channel ?? \"reliable\";\n if (this.isHost) this.sendTo(peerId, { type: \"raw\", bytes }, this.localPeerId, channel);\n else this.sendTo(this.hostPeerId, { type: \"raw\", bytes }, peerId, channel);\n }\n\n /** To everyone else in the lobby. */\n broadcast(bytes: Uint8Array, opts: { channel?: \"reliable\" | \"fast\" } = {}): void {\n const channel = opts.channel ?? \"reliable\";\n if (this.isHost) {\n // peers whose channels are not open yet get reliable broadcasts queued and flushed in order\n for (const p of this.roster.keys()) if (p !== this.localPeerId) this.sendTo(p, { type: \"raw\", bytes }, this.localPeerId, channel);\n } else {\n this.sendTo(this.hostPeerId, { type: \"raw\", bytes }, 0, channel);\n }\n }\n\n // ---- sending ---------------------------------------------------------------------------------------------------\n\n private channelFor(msg: Message): ChannelName {\n if (msg.type === \"voice\") return \"voice\";\n if (msg.type === \"ping\" || msg.type === \"pong\") return \"fast\";\n return \"reliable\";\n }\n\n private sendTo(peerId: number, msg: Message, route: number, channel?: ChannelName): void {\n const link = this.links.get(peerId);\n const ch0 = channel ?? this.channelFor(msg);\n const queueable = msg.type === \"raw\" || msg.type === \"chat\" || msg.type === \"cmd\";\n // game data to a host-side peer waits for its `hi`; protocol messages only need the link\n const ready = !!link?.isOpen && (!queueable || !this.isHost || this.connected.has(peerId));\n if (!ready) {\n // Reliable game data for a peer that is in the roster (or is the host) but not connected yet waits for its handshake.\n const known = this.roster.has(peerId) || peerId === this.hostPeerId;\n if (queueable && ch0 === \"reliable\" && known && !this.ended) {\n let q = this.outbox.get(peerId);\n if (!q) this.outbox.set(peerId, (q = []));\n if (q.length >= 1000) q.shift();\n q.push({ msg, route, channel });\n }\n return;\n }\n if (!link) return;\n try {\n const ch = ch0;\n let bytes: Uint8Array;\n try {\n bytes = encodeMessage(msg, route);\n } catch (e) {\n if (!(e instanceof CodecError) || e.code !== \"too_long\") throw e;\n bytes = encodeMessage(msg, route, true);\n }\n if (bytes.length > MAX_FRAME_BYTES) {\n // Oversized frame: send the whole inner frame as a chunk set (spec/binary.md \"Large non-snapshot frames\").\n for (const c of splitChunks(this.chunkId++ >>> 0, bytes)) link.send(ch, encodeMessage(c, route));\n } else {\n link.send(ch, bytes);\n }\n } catch (e) {\n this.reportError(e instanceof Error ? e : new Error(String(e)));\n }\n }\n\n private connectedPeerIds(): number[] {\n if (this.isHost) return [...this.connected].filter((id) => this.links.get(id)?.isOpen).sort((a, b) => a - b);\n const l = this.links.get(this.hostPeerId);\n return l?.isOpen ? [this.hostPeerId] : [];\n }\n\n private reportError(e: Error): void {\n this.errorSink?.(e);\n }\n /** @internal set by OneLobby so lobby errors reach `kit.on(\"error\")`. */\n errorSink: ((e: Error) => void) | null = null;\n /** @internal set by OneLobby: the server issued a new resume token (rememberSeat). */\n seatSink: ((token: string) => void) | null = null;\n\n // ---- joiner connect timeout -------------------------------------------------------------------------------------\n\n private armReadyTimer(): void {\n const total = this.cfg.readyTimeoutMs ?? 0;\n if (!(total > 0)) return;\n const canRelay = !this.cfg.relayOnly && hasRelay(this.cfg.ice);\n const first = canRelay ? Math.ceil(total / 2) : total;\n this.cancelReadyTimer = this.cfg.clock.setTimeout(() => {\n if (this.isReady || this.ended) return;\n if (canRelay) this.retryRelayed(total - first);\n else this.giveUpConnecting();\n }, first);\n }\n\n /** The direct attempt stalled: dial the host ourselves through the TURN relay (a host answers any offer). */\n private retryRelayed(budget: number): void {\n this.relayRetry = true;\n const link = this.makeLink(this.hostPeerId, true);\n link.startOffer();\n this.cancelReadyTimer = this.cfg.clock.setTimeout(() => {\n if (!this.isReady && !this.ended) this.giveUpConnecting();\n }, budget);\n }\n\n private giveUpConnecting(): void {\n const err = new OneLobbyError(\"ice_failed\", `could not open a connection to the host${this.relayRetry ? \" (direct or relayed)\" : \"\"}`);\n this.failReady(err);\n this.reportError(err);\n if (this.ended) return;\n this.signaling.send({ t: \"leave\" });\n this.teardown(\"ice_failed\");\n }\n\n // ---- links -----------------------------------------------------------------------------------------------------\n\n private makeLink(peerId: number, relayOnly = this.cfg.relayOnly): PeerLink {\n const old = this.links.get(peerId);\n if (old) {\n old.onClose = null;\n old.onMessage = null;\n old.close();\n }\n const link = this.cfg.links.create({ remoteId: peerId, iceServers: this.cfg.ice, relayOnly });\n this.links.set(peerId, link);\n link.onSignal = (s) => this.signaling.send({ t: \"signal\", to: peerId, ...s });\n link.onOpen = () => this.onLinkOpen(peerId, link);\n link.onClose = (reason) => this.onLinkClosed(peerId, link, reason);\n link.onMessage = (ch, bytes) => this.onData(peerId, ch, bytes);\n link.onPath = (path) => this.signaling.send({ t: \"path\", path });\n return link;\n }\n\n /** Host side: offer to a joiner. */\n private offerTo(peerId: number): void {\n const link = this.makeLink(peerId);\n link.startOffer();\n }\n\n private onLinkOpen(peerId: number, link: PeerLink): void {\n if (this.isHost) {\n // Joiner speaks first (`hi`). After a migration the new host announces itself so the joiner knows who won.\n if (this.epoch > 0) this.sendTo(peerId, { type: \"host_claim\", epoch: this.epoch, hostId: this.localPeerId, tick: this.lockstep.lastTick }, 0);\n return;\n }\n if (peerId === this.hostPeerId) this.sendHi(link);\n // else: an unexpected offerer; wait for its host_claim before trusting it\n }\n\n private sendHi(link: PeerLink): void {\n if (this.hiSentTo.has(link)) return;\n this.hiSentTo.add(link);\n this.lockstep.touch();\n link.send(\"reliable\", encodeMessage(this.lockstep.hiMessage(this.localPeerId)));\n this.markReady();\n this.emit(\"ready\");\n this.emit(\"peerReady\", this.roster.get(link.remoteId) ?? { peerId: link.remoteId, name: \"\" });\n this.flush(link.remoteId);\n }\n\n private onLinkClosed(peerId: number, link: PeerLink, _reason: string): void {\n if (this.links.get(peerId) !== link) return; // replaced\n this.links.delete(peerId);\n this.hiSentTo.delete(link);\n if (this.ended) return;\n if (this.isHost) {\n this.connected.delete(peerId);\n this.lockstep.onPeerLeft(peerId);\n this.voice.onPeerLeft(peerId);\n // The server announces the departure; if it is gone, drop the peer ourselves.\n if (!this.serverUp && this.roster.has(peerId)) this.removePeer(peerId, \"timeout\");\n } else if (peerId === this.hostPeerId) {\n // Never connected yet (ICE failed): not a host loss. The ready timer retries over the relay or gives up.\n if (!this.isReady && this.cancelReadyTimer) return;\n this.handleHostLost(\"link closed\");\n }\n }\n\n // ---- data channel dispatch -------------------------------------------------------------------------------------\n\n private onData(from: number, channel: ChannelName, bytes: Uint8Array, reassembled = false): void {\n let d;\n try {\n d = decodeMessage(bytes, reassembled);\n } catch (e) {\n this.reportError(e instanceof Error ? e : new Error(String(e)));\n return;\n }\n if (!d) return;\n if (!reassembled) this.lastHeard.set(from, this.cfg.clock.now());\n const { msg, route } = d;\n switch (msg.type) {\n case \"hi\":\n if (this.isHost) this.onHi(from, msg.lastTick);\n break;\n case \"welcome_dc\":\n if (!this.isHost) {\n if (msg.hostId !== this.hostPeerId) this.setHost(msg.hostId);\n this.lockstep.touch();\n }\n break;\n case \"cmd\": case \"frame\": case \"hash\": case \"desync\":\n case \"snapshot_req\": case \"snapshot\":\n if (from === this.hostPeerId || this.isHost) this.lockstep.handle(from, msg);\n break;\n case \"chunk\": {\n if (reassembled) break; // a chunk set never nests another\n let r = this.reassemblers.get(from);\n if (!r) this.reassemblers.set(from, (r = new Reassembler()));\n let whole;\n try {\n whole = r.push(msg);\n } catch (e) {\n this.reportError(e instanceof Error ? e : new Error(String(e)));\n break;\n }\n if (!whole) break;\n if (this.lockstep.snapshotPending && from === this.hostPeerId) this.lockstep.onSnapshotPayload(whole);\n else this.onData(from, channel, whole, true); // an oversized inner frame\n break;\n }\n case \"chat\": case \"chat_history\": case \"chat_reject\":\n this.chat.handle(from, route, msg);\n break;\n case \"voice\":\n if (channel === \"voice\") this.voice.handle(from, route, msg); // a voice frame on another channel is ignored\n break;\n case \"raw\":\n this.onRaw(from, route, msg.bytes, channel);\n break;\n case \"ping\":\n this.sendTo(from, { type: \"pong\", n: msg.n, t: msg.t }, 0, \"fast\");\n break;\n case \"pong\":\n this.rtt = Math.max(0, (this.cfg.clock.now() >>> 0) - msg.t);\n break;\n case \"host_claim\":\n this.onHostClaim(from, msg.epoch, msg.hostId);\n break;\n }\n }\n\n private onHi(from: number, lastTick: number): void {\n this.connected.add(from);\n this.sendTo(from, {\n type: \"welcome_dc\",\n // the tick the snapshot will carry (the game's applied tick), so welcome_dc.tick == snapshot.tick even when\n // the game loop has not yet consumed every emitted frame; 0 before the game starts\n tick: this.mode === \"lockstep\" ? this.lockstep.currentTick : 0,\n tickRate: this.tickRate,\n mode: this.mode === \"lockstep\" ? MODE_LOCKSTEP : MODE_RAW,\n hostId: this.localPeerId,\n }, 0);\n this.chat.sendHistory(from);\n if (this.mode === \"lockstep\") this.lockstep.onPeerHi(from, lastTick);\n this.emit(\"peerReady\", this.roster.get(from) ?? { peerId: from, name: \"\" });\n this.flush(from);\n }\n\n private flush(peerId: number): void {\n const q = this.outbox.get(peerId);\n if (!q) return;\n this.outbox.delete(peerId);\n for (const m of q) this.sendTo(peerId, m.msg, m.route, m.channel);\n }\n\n private onRaw(from: number, route: number, bytes: Uint8Array, channel: ChannelName): void {\n if (!this.isHost) {\n this.emit(\"message\", route, bytes, channel);\n return;\n }\n if (!this.allowRaw(from)) return;\n if (route === 0 || route === this.localPeerId) {\n this.emit(\"message\", from, bytes, channel);\n }\n if (route === 0) {\n for (const p of this.connectedPeerIds()) if (p !== from) this.sendTo(p, { type: \"raw\", bytes }, from, channel);\n } else if (route !== this.localPeerId) {\n this.sendTo(route, { type: \"raw\", bytes }, from, channel);\n }\n }\n\n private allowRaw(from: number): boolean {\n const lim = this.cfg.rateLimit;\n if (!lim || !(lim.messages > 0) || !(lim.perMs > 0)) return true;\n const now = this.cfg.clock.now();\n let w = this.rate.get(from);\n if (!w || now - w.start >= lim.perMs) this.rate.set(from, (w = { start: now, n: 0 }));\n return ++w.n <= lim.messages;\n }\n\n // ---- migration -------------------------------------------------------------------------------------------------\n\n private setHost(hostId: number): void {\n if (hostId === this.hostPeerId) return;\n this.hostPeerId = hostId;\n this.emit(\"hostChanged\", hostId);\n }\n\n /** The host is gone (link closed, no frames for 3 s, or the server said so): run the s.9 rule. */\n private handleHostLost(reason: string): void {\n if (this.isHost || this.ended) return;\n if (this.cfg.direct) {\n this.teardown(\"host_left\");\n return;\n }\n const failed = this.hostPeerId;\n const gone = this.roster.get(failed);\n if (gone) {\n this.roster.delete(failed);\n this.emit(\"peerLeft\", gone, reason === \"link closed\" ? \"timeout\" : reason);\n }\n const old = this.links.get(failed);\n if (old) {\n old.onClose = null;\n old.onMessage = null;\n old.close();\n this.links.delete(failed);\n this.hiSentTo.delete(old);\n }\n const candidate = pickNewHost([...this.roster.keys(), this.localPeerId], failed) ?? this.localPeerId;\n if (candidate === this.localPeerId) this.becomeHost();\n // else: wait for the candidate's host_claim (or the server's host_changed); it offers to us and we answer with hi\n }\n\n private becomeHost(): void {\n this.epoch = (this.epoch + 1) & 0xffff;\n this.hostPeerId = this.localPeerId;\n this.markReady();\n this.connected.clear();\n this.hiSentTo.clear();\n this.lastHeard.clear(); // joiners spoke to the old host; their clocks start when they say hi to us\n this.lockstep.becomeHost();\n this.emit(\"hostChanged\", this.localPeerId);\n if (this.serverUp) this.signaling.send({ t: \"host_changed\", hostId: this.localPeerId, epoch: this.epoch });\n for (const p of this.roster.keys()) {\n if (p !== this.localPeerId) this.offerTo(p);\n }\n }\n\n private onHostClaim(from: number, epoch: number, hostId: number): void {\n const mine = { epoch: this.epoch, hostId: this.hostPeerId };\n const theirs = { epoch, hostId };\n if (hostId === this.hostPeerId && epoch === this.epoch && !this.isHost) {\n const l = this.links.get(from);\n if (l) this.sendHi(l);\n return;\n }\n if (!claimWinsWrapped(theirs, mine)) return; // we hold the better claim\n const wasHost = this.isHost;\n this.epoch = epoch;\n if (wasHost) {\n // We lose: demote. Everyone else will be offered to by the winner.\n for (const [id, l] of this.links) {\n if (id === from) continue;\n l.onClose = null;\n l.onMessage = null;\n l.close();\n this.links.delete(id);\n }\n this.connected.clear();\n this.lockstep.becomeJoiner();\n }\n this.setHost(hostId);\n const link = this.links.get(from);\n if (link && from === hostId) this.sendHi(link);\n }\n\n // ---- signaling -------------------------------------------------------------------------------------------------\n\n private onSignaling(m: ServerMsg): void {\n switch (m.t) {\n case \"peer_joined\": {\n if (!m.peer || this.roster.has((m.peer as Peer).peerId)) return;\n const peer = seatName(m.peer as Peer);\n this.roster.set(peer.peerId, peer);\n this.emit(\"peerJoined\", peer);\n if (this.isHost) this.offerTo(peer.peerId);\n break;\n }\n case \"peer_left\":\n this.removePeer(Number(m.peerId), String(m.reason ?? \"left\"));\n break;\n case \"host_changed\": {\n if (this.cfg.direct) {\n // the hub promotes a joiner as the host leaves; in direct mode the hub is going with it\n if (!this.isHost) this.teardown(\"host_left\");\n break;\n }\n const id = Number(m.hostId);\n if (typeof m.epoch === \"number\" && m.epoch > this.epoch) this.epoch = m.epoch & 0xffff;\n if (id === this.hostPeerId) break;\n if (id === this.localPeerId && !this.isHost) {\n const failed = this.hostPeerId;\n this.roster.delete(failed);\n this.becomeHost();\n } else {\n this.setHost(id);\n }\n break;\n }\n case \"join_request\":\n this.emit(\"joinRequested\", seatName(m.peer as Peer));\n break;\n case \"lobby\": {\n const st = m as unknown as LobbyState;\n this.meta = { ...st.meta };\n if (st.resumeToken && st.resumeToken !== this.resumeToken) {\n this.resumeToken = st.resumeToken;\n this.seatSink?.(this.resumeToken);\n }\n this.roster = new Map(st.peers.map((p) => [p.peerId, seatName(p)]));\n if (st.hostId !== this.hostPeerId && !this.isHost) this.setHost(st.hostId);\n this.setPhase(st.phase);\n break;\n }\n case \"meta\":\n this.meta = { ...(m.meta as Record<string, string>) };\n this.emit(\"metaChanged\", this.meta);\n break;\n case \"phase\":\n this.setPhase(m.phase as Phase);\n break;\n case \"signal\":\n void this.onSignal(Number(m.from), m as unknown as SignalPayload);\n break;\n case \"error\":\n if (m.code === \"kicked\") {\n const d = (m.data ?? {}) as { ban?: unknown; closeCode?: unknown; closeReason?: unknown };\n const close: CloseInfo = {};\n if (typeof d.closeCode === \"number\") close.code = d.closeCode;\n if (typeof d.closeReason === \"string\") close.reason = d.closeReason;\n this.teardown(d.ban === false ? \"disconnected\" : \"kicked\", close.code !== undefined || close.reason !== undefined ? close : undefined);\n }\n else this.reportError(new OneLobbyError(String(m.code), String(m.msg ?? \"\"), m.data as Record<string, unknown> | undefined));\n break;\n }\n }\n\n private async onSignal(from: number, s: SignalPayload): Promise<void> {\n let link = this.links.get(from);\n if (s.sdp?.type === \"offer\") {\n // We are the answerer; an offer always comes from the (new) host.\n link = this.makeLink(from);\n }\n if (!link) return;\n const payload: SignalPayload = {};\n if (s.sdp) payload.sdp = s.sdp;\n if (s.ice) payload.ice = s.ice;\n await link.handleSignal(payload);\n }\n\n /**\n * `linger` (host kick / disconnect): stop using the peer's link at once but leave it open until that peer closes it\n * or KICK_LINGER_MS pass. The hub tells the peer over its WebSocket; closing the data link first would make it look\n * like the host vanished (a migration and a 1001 instead of the host's close code).\n */\n private removePeer(peerId: number, reason: string, close?: CloseInfo, linger = false): void {\n const peer = this.roster.get(peerId);\n if (peerId === this.localPeerId) {\n this.teardown(reason === \"kicked\" ? \"kicked\" : reason);\n return;\n }\n if (peer) this.roster.delete(peerId);\n const link = this.links.get(peerId);\n if (link && peerId !== this.hostPeerId) {\n link.onMessage = null;\n this.links.delete(peerId);\n this.hiSentTo.delete(link);\n if (linger) {\n this.lingering.add(link);\n const done = () => {\n if (!this.lingering.delete(link)) return;\n cancel();\n link.onClose = null;\n link.close();\n };\n const cancel = this.cfg.clock.setTimeout(done, KICK_LINGER_MS);\n link.onClose = done;\n } else {\n link.onClose = null;\n link.close();\n }\n }\n this.connected.delete(peerId);\n this.outbox.delete(peerId);\n this.lastHeard.delete(peerId);\n this.rate.delete(peerId);\n this.lockstep.onPeerLeft(peerId);\n this.chat.onPeerLeft(peerId);\n this.voice.onPeerLeft(peerId);\n if (peer) this.emit(\"peerLeft\", peer, reason, close);\n if (peerId === this.hostPeerId && !this.isHost) {\n this.handleHostLost(reason);\n }\n }\n\n /** Lockstep drops (stalled, desynced): removed without a ban, so the player can come back (a rejoin resyncs). */\n private dropPeer(peerId: number, reason: string): void {\n this.signaling.send({ t: \"kick\", peerId, ban: false, closeReason: reason } as { t: \"kick\"; peerId: number });\n this.removePeer(peerId, reason, undefined, true);\n }\n\n private setPhase(p: Phase): void {\n if (p !== \"lobby\" && p !== \"in_game\") return;\n if (this.phase === p) return;\n this.phase = p;\n if (p === \"in_game\" && !this.lockstep.started) this.lockstep.markStarted();\n this.emit(\"phase\", p);\n }\n\n private onServerClosed(): void {\n if (this.ended) return;\n if (this.cfg.direct && !this.isHost) {\n this.teardown(\"host_left\");\n return;\n }\n this.serverUp = false;\n this.emit(\"serverLost\");\n // Alone with no peers: nothing keeps this session alive.\n if (this.links.size === 0 && this.roster.size <= 1) this.teardown(\"server_lost\");\n }\n\n // ---- housekeeping ----------------------------------------------------------------------------------------------\n\n private watchdog(): void {\n if (this.ended) return;\n const timeout = this.cfg.peerTimeoutMs ?? 0;\n if (timeout > 0) this.dropSilent(Math.max(timeout, MIN_PEER_TIMEOUT_MS));\n if (this.ended || this.isHost) return;\n if (this.mode === \"lockstep\" && this.lockstep.hostSilent()) {\n this.lockstep.touch();\n this.lockstep.pokeHost(); // a live-but-stalled host answers with a snapshot; a dead one is replaced below\n this.handleHostLost(\"timeout\");\n }\n }\n\n /** peerTimeoutMs: the host drops joiners it has not heard from; a joiner handles a silent host as lost. */\n private dropSilent(timeout: number): void {\n const now = this.cfg.clock.now();\n if (this.isHost) {\n for (const id of [...this.connected]) {\n const last = this.lastHeard.get(id);\n if (last !== undefined && now - last > timeout) this.removePeer(id, \"timeout\");\n }\n } else if (this.isReady) {\n const last = this.lastHeard.get(this.hostPeerId);\n if (last !== undefined && now - last > timeout) {\n this.lastHeard.delete(this.hostPeerId);\n this.handleHostLost(\"timeout\");\n }\n }\n }\n\n private pingHost(): void {\n if (this.ended || this.isHost) return;\n this.sendTo(this.hostPeerId, { type: \"ping\", n: ++this.pingN, t: this.cfg.clock.now() >>> 0 }, 0, \"fast\");\n }\n\n private teardown(reason: string, close?: CloseInfo): void {\n if (this.ended) return;\n this.ended = true;\n this.cancelReadyTimer?.();\n if (!this.isReady) {\n const code = reason === \"ice_failed\" || reason === \"kicked\" ? reason : \"closed\";\n this.failReady(new OneLobbyError(code, `the lobby ended before connecting (${reason})`));\n }\n this.cancelWatchdog?.();\n this.cancelPing?.();\n this.lockstep.stop();\n this.voice.close();\n for (const l of [...this.links.values(), ...this.lingering]) {\n l.onClose = null;\n l.onMessage = null;\n l.close();\n }\n this.links.clear();\n this.lingering.clear();\n this.signaling.onClose = null;\n this.signaling.onMessage = null;\n this.signaling.close();\n this.emit(\"sessionEnded\", reason, close);\n }\n\n /** Total in-flight links (diagnostics and tests). */\n get linkCount(): number {\n return this.links.size;\n }\n}\n\nexport { PROTO };\n"]}