twinwire 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/LICENSE +21 -0
  3. package/README.md +128 -2
  4. package/dist/browser/twinwire.js +2075 -0
  5. package/dist/browser/twinwire.js.map +7 -0
  6. package/dist/browser/twinwire.min.js +1 -0
  7. package/dist/browser/twinwire.mjs +2052 -0
  8. package/dist/browser/twinwire.mjs.map +7 -0
  9. package/dist/browser.d.ts +5 -0
  10. package/dist/browser.js +6 -0
  11. package/dist/browser.js.map +1 -0
  12. package/dist/client/client.d.ts +128 -0
  13. package/dist/client/client.js +470 -0
  14. package/dist/client/client.js.map +1 -0
  15. package/dist/client/index.d.ts +3 -0
  16. package/dist/client/index.js +4 -0
  17. package/dist/client/index.js.map +1 -0
  18. package/dist/client/lobby.d.ts +40 -0
  19. package/dist/client/lobby.js +122 -0
  20. package/dist/client/lobby.js.map +1 -0
  21. package/dist/client/rtc.d.ts +17 -0
  22. package/dist/client/rtc.js +102 -0
  23. package/dist/client/rtc.js.map +1 -0
  24. package/dist/core/budget.d.ts +27 -0
  25. package/dist/core/budget.js +39 -0
  26. package/dist/core/budget.js.map +1 -0
  27. package/dist/core/endpoint.d.ts +144 -0
  28. package/dist/core/endpoint.js +501 -0
  29. package/dist/core/endpoint.js.map +1 -0
  30. package/dist/core/lobby.d.ts +59 -0
  31. package/dist/core/lobby.js +53 -0
  32. package/dist/core/lobby.js.map +1 -0
  33. package/dist/core/protocol.d.ts +52 -0
  34. package/dist/core/protocol.js +100 -0
  35. package/dist/core/protocol.js.map +1 -0
  36. package/dist/core/reliable.d.ts +52 -0
  37. package/dist/core/reliable.js +116 -0
  38. package/dist/core/reliable.js.map +1 -0
  39. package/dist/core/rtc.d.ts +28 -0
  40. package/dist/core/rtc.js +21 -0
  41. package/dist/core/rtc.js.map +1 -0
  42. package/dist/index.d.ts +6 -0
  43. package/dist/index.js +7 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/netcode/clock.d.ts +15 -0
  46. package/dist/netcode/clock.js +37 -0
  47. package/dist/netcode/clock.js.map +1 -0
  48. package/dist/netcode/codec.d.ts +10 -0
  49. package/dist/netcode/codec.js +95 -0
  50. package/dist/netcode/codec.js.map +1 -0
  51. package/dist/netcode/index.d.ts +9 -0
  52. package/dist/netcode/index.js +10 -0
  53. package/dist/netcode/index.js.map +1 -0
  54. package/dist/netcode/inputs.d.ts +7 -0
  55. package/dist/netcode/inputs.js +43 -0
  56. package/dist/netcode/inputs.js.map +1 -0
  57. package/dist/netcode/interpolation.d.ts +44 -0
  58. package/dist/netcode/interpolation.js +101 -0
  59. package/dist/netcode/interpolation.js.map +1 -0
  60. package/dist/netcode/prediction.d.ts +40 -0
  61. package/dist/netcode/prediction.js +97 -0
  62. package/dist/netcode/prediction.js.map +1 -0
  63. package/dist/netcode/replication.d.ts +36 -0
  64. package/dist/netcode/replication.js +90 -0
  65. package/dist/netcode/replication.js.map +1 -0
  66. package/dist/netcode/snapshots.d.ts +29 -0
  67. package/dist/netcode/snapshots.js +78 -0
  68. package/dist/netcode/snapshots.js.map +1 -0
  69. package/dist/netcode/spatial.d.ts +16 -0
  70. package/dist/netcode/spatial.js +63 -0
  71. package/dist/netcode/spatial.js.map +1 -0
  72. package/dist/netcode/timing.d.ts +37 -0
  73. package/dist/netcode/timing.js +41 -0
  74. package/dist/netcode/timing.js.map +1 -0
  75. package/dist/server/index.d.ts +4 -0
  76. package/dist/server/index.js +5 -0
  77. package/dist/server/index.js.map +1 -0
  78. package/dist/server/lobby.d.ts +134 -0
  79. package/dist/server/lobby.js +462 -0
  80. package/dist/server/lobby.js.map +1 -0
  81. package/dist/server/rtc.d.ts +38 -0
  82. package/dist/server/rtc.js +102 -0
  83. package/dist/server/rtc.js.map +1 -0
  84. package/dist/server/server.d.ts +145 -0
  85. package/dist/server/server.js +457 -0
  86. package/dist/server/server.js.map +1 -0
  87. package/dist/server/turn.d.ts +22 -0
  88. package/dist/server/turn.js +52 -0
  89. package/dist/server/turn.js.map +1 -0
  90. package/docs/ADOPTING.md +64 -0
  91. package/docs/API.md +181 -0
  92. package/docs/ARCHITECTURE.md +101 -0
  93. package/docs/OPERATIONS.md +93 -0
  94. package/docs/RELEASE-CHECKLIST.md +25 -0
  95. package/package.json +100 -4
@@ -0,0 +1,52 @@
1
+ /** Versioned binary frames. All integer fields are little-endian. */
2
+ export declare const VERSION = 3;
3
+ export declare const HEADER_BYTES = 22;
4
+ /** A payload this size or smaller fits one datagram on any path we target (no SCTP/IP fragmentation). */
5
+ export declare const MTU_STATE_BYTES: number;
6
+ /** Hard protocol ceiling for one frame. Endpoints choose a lower `maxStateBytes`. */
7
+ export declare const MAX_FRAME_BYTES: number;
8
+ export declare const MAX_STATE_BYTES: number;
9
+ export declare const DEFAULT_STATE_BYTES: number;
10
+ /** Upper bound of one JSON control/event message on the WebSocket. */
11
+ export declare const MAX_CONTROL_BYTES: number;
12
+ /** Kept for API compatibility: the largest datagram that avoids fragmentation. */
13
+ export declare const MAX_DATAGRAM_BYTES = 1100;
14
+ /**
15
+ * state: latest-wins application bytes. stateAcked: the same, and the receiver reports the newest seq it saw (kind sack).
16
+ * probe/reply: datagram liveness. events: reliable events mirrored on the datagram path (seq field = receiver ack).
17
+ */
18
+ export declare const FrameKind: {
19
+ readonly state: 1;
20
+ readonly probe: 2;
21
+ readonly reply: 3;
22
+ readonly events: 4;
23
+ readonly sack: 5;
24
+ readonly stateAcked: 6;
25
+ };
26
+ export type FrameKind = typeof FrameKind[keyof typeof FrameKind];
27
+ export type Json = null | boolean | number | string | Json[] | {
28
+ [key: string]: Json;
29
+ };
30
+ export interface Frame {
31
+ kind: FrameKind;
32
+ epoch: number;
33
+ stream: number;
34
+ seq: number;
35
+ time: number;
36
+ payload: Uint8Array;
37
+ }
38
+ export declare const isUint: (v: unknown, max?: number) => v is number;
39
+ export declare function encodeFrame(f: Frame): Uint8Array;
40
+ export declare function decodeFrame(b: Uint8Array, maxBytes?: number): Frame | null;
41
+ /** RFC-1982-style comparison. Live windows must be smaller than half the sequence space. */
42
+ export declare function newer(a: number, b: number): boolean;
43
+ export declare function record(value: unknown): value is Record<string, unknown>;
44
+ export declare const utf8: (s: string) => Uint8Array<ArrayBufferLike>;
45
+ export declare const fromUtf8: (b: Uint8Array) => string;
46
+ /** UTF-8 byte length without allocating. */
47
+ export declare function utf8Length(s: string): number;
48
+ export declare function readControl(raw: string, maxBytes?: number): Record<string, unknown> | null;
49
+ /** Standard JSON semantics, as games expect from JSON.stringify: undefined, functions and symbols inside objects are
50
+ * left out (null in arrays) and NaN/Infinity become null. A top-level value that isn't JSON, a BigInt or an oversized
51
+ * result throws. */
52
+ export declare function stringify(value: unknown, maxBytes?: number): string;
@@ -0,0 +1,100 @@
1
+ /** Versioned binary frames. All integer fields are little-endian. */
2
+ export const VERSION = 3;
3
+ export const HEADER_BYTES = 22;
4
+ /** A payload this size or smaller fits one datagram on any path we target (no SCTP/IP fragmentation). */
5
+ export const MTU_STATE_BYTES = 1100 - HEADER_BYTES;
6
+ /** Hard protocol ceiling for one frame. Endpoints choose a lower `maxStateBytes`. */
7
+ export const MAX_FRAME_BYTES = 256 * 1024;
8
+ export const MAX_STATE_BYTES = MAX_FRAME_BYTES - HEADER_BYTES;
9
+ export const DEFAULT_STATE_BYTES = 64 * 1024;
10
+ /** Upper bound of one JSON control/event message on the WebSocket. */
11
+ export const MAX_CONTROL_BYTES = 128 * 1024;
12
+ /** Kept for API compatibility: the largest datagram that avoids fragmentation. */
13
+ export const MAX_DATAGRAM_BYTES = 1100;
14
+ const MAGIC = 0x5754; // "TW"
15
+ /**
16
+ * state: latest-wins application bytes. stateAcked: the same, and the receiver reports the newest seq it saw (kind sack).
17
+ * probe/reply: datagram liveness. events: reliable events mirrored on the datagram path (seq field = receiver ack).
18
+ */
19
+ export const FrameKind = { state: 1, probe: 2, reply: 3, events: 4, sack: 5, stateAcked: 6 };
20
+ const KINDS = new Set(Object.values(FrameKind));
21
+ export const isUint = (v, max = 0xffffffff) => typeof v === 'number' && Number.isInteger(v) && v >= 0 && v <= max;
22
+ const empty = (k) => k === FrameKind.probe || k === FrameKind.reply;
23
+ const streamed = (k) => k === FrameKind.state || k === FrameKind.stateAcked;
24
+ export function encodeFrame(f) {
25
+ if (!KINDS.has(f.kind) || !isUint(f.epoch) || !f.epoch || !isUint(f.stream, 65535) ||
26
+ !isUint(f.seq) || !Number.isFinite(f.time) || f.payload.length > MAX_STATE_BYTES ||
27
+ (empty(f.kind) && f.payload.length !== 0) || (!streamed(f.kind) && f.stream !== 0))
28
+ throw new RangeError('Invalid frame');
29
+ const b = new Uint8Array(HEADER_BYTES + f.payload.length), v = new DataView(b.buffer);
30
+ v.setUint16(0, MAGIC, true);
31
+ v.setUint8(2, VERSION);
32
+ v.setUint8(3, f.kind);
33
+ v.setUint32(4, f.epoch, true);
34
+ v.setUint16(8, f.stream, true);
35
+ v.setUint32(10, f.seq, true);
36
+ v.setFloat64(14, f.time, true);
37
+ b.set(f.payload, HEADER_BYTES);
38
+ return b;
39
+ }
40
+ export function decodeFrame(b, maxBytes = MAX_FRAME_BYTES) {
41
+ if (b.byteLength < HEADER_BYTES || b.byteLength > Math.min(maxBytes, MAX_FRAME_BYTES))
42
+ return null;
43
+ const v = new DataView(b.buffer, b.byteOffset, b.byteLength);
44
+ if (v.getUint16(0, true) !== MAGIC || v.getUint8(2) !== VERSION)
45
+ return null;
46
+ const kind = v.getUint8(3), epoch = v.getUint32(4, true), time = v.getFloat64(14, true), stream = v.getUint16(8, true);
47
+ if (!KINDS.has(kind) || !epoch || !Number.isFinite(time) ||
48
+ (empty(kind) && b.byteLength !== HEADER_BYTES) || (!streamed(kind) && stream !== 0))
49
+ return null;
50
+ return { kind: kind, epoch, stream, seq: v.getUint32(10, true), time, payload: b.slice(HEADER_BYTES) };
51
+ }
52
+ /** RFC-1982-style comparison. Live windows must be smaller than half the sequence space. */
53
+ export function newer(a, b) { return a !== b && ((a - b) >>> 0) < 0x80000000; }
54
+ export function record(value) {
55
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
56
+ }
57
+ const encoder = new TextEncoder(), decoder = new TextDecoder();
58
+ export const utf8 = (s) => encoder.encode(s);
59
+ export const fromUtf8 = (b) => decoder.decode(b);
60
+ /** UTF-8 byte length without allocating. */
61
+ export function utf8Length(s) {
62
+ let n = 0;
63
+ for (let i = 0; i < s.length; i++) {
64
+ const c = s.charCodeAt(i);
65
+ if (c < 0x80)
66
+ n += 1;
67
+ else if (c < 0x800)
68
+ n += 2;
69
+ else if (c >= 0xd800 && c <= 0xdbff && i + 1 < s.length) {
70
+ n += 4;
71
+ i++;
72
+ }
73
+ else
74
+ n += 3;
75
+ }
76
+ return n;
77
+ }
78
+ export function readControl(raw, maxBytes = MAX_CONTROL_BYTES) {
79
+ if (raw.length > maxBytes || utf8Length(raw) > maxBytes)
80
+ return null;
81
+ try {
82
+ const m = JSON.parse(raw);
83
+ return record(m) && typeof m.t === 'string' ? m : null;
84
+ }
85
+ catch {
86
+ return null;
87
+ }
88
+ }
89
+ /** Standard JSON semantics, as games expect from JSON.stringify: undefined, functions and symbols inside objects are
90
+ * left out (null in arrays) and NaN/Infinity become null. A top-level value that isn't JSON, a BigInt or an oversized
91
+ * result throws. */
92
+ export function stringify(value, maxBytes = MAX_CONTROL_BYTES) {
93
+ const s = JSON.stringify(value);
94
+ if (s === undefined)
95
+ throw new TypeError('Value is not JSON');
96
+ if (utf8Length(s) > maxBytes)
97
+ throw new RangeError('Control frame too large');
98
+ return s;
99
+ }
100
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/core/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { type Json } from './protocol.js';
2
+ export interface PendingEvent {
3
+ seq: number;
4
+ data: Json;
5
+ bytes: number;
6
+ text: string;
7
+ datagramAt: number;
8
+ datagramTries: number;
9
+ }
10
+ export interface ReliableCheckpoint {
11
+ next: number;
12
+ received: number;
13
+ acknowledged: number;
14
+ pending: {
15
+ seq: number;
16
+ data: Json;
17
+ }[];
18
+ }
19
+ export interface ReliableOptions {
20
+ maxEvents?: number;
21
+ maxBytes?: number;
22
+ maxEventBytes?: number;
23
+ maxEarly?: number;
24
+ }
25
+ /** Ordered event delivery with replay/deduplication within a retained logical session.
26
+ * Copies may arrive on two paths (WebSocket and datagrams), so early events wait in a bounded buffer.
27
+ * An ACK means the synchronous receiver accepted the event, NOT that a database transaction committed. */
28
+ export declare class ReliableEvents {
29
+ private next;
30
+ received: number;
31
+ acknowledged: number;
32
+ private highestSent;
33
+ private bytes;
34
+ private pending;
35
+ private early;
36
+ readonly maxEvents: number;
37
+ readonly maxBytes: number;
38
+ readonly maxEventBytes: number;
39
+ readonly maxEarly: number;
40
+ constructor(o?: ReliableOptions | number, maxBytes?: number);
41
+ push(data: Json): number;
42
+ get size(): number;
43
+ get queuedBytes(): number;
44
+ get sentThrough(): number;
45
+ entries(): IterableIterator<PendingEvent>;
46
+ sent(seq: number): void;
47
+ ack(seq: number): boolean;
48
+ /** Returns how many events were delivered. Early events wait (bounded); duplicates are dropped. */
49
+ receive(seq: number, data: Json, deliver: (data: Json, seq: number) => void): number;
50
+ checkpoint(): ReliableCheckpoint;
51
+ restore(s: ReliableCheckpoint): void;
52
+ }
@@ -0,0 +1,116 @@
1
+ import { stringify, utf8Length } from './protocol.js';
2
+ /** Ordered event delivery with replay/deduplication within a retained logical session.
3
+ * Copies may arrive on two paths (WebSocket and datagrams), so early events wait in a bounded buffer.
4
+ * An ACK means the synchronous receiver accepted the event, NOT that a database transaction committed. */
5
+ export class ReliableEvents {
6
+ next = 1;
7
+ received = 0;
8
+ acknowledged = 0;
9
+ highestSent = 0;
10
+ bytes = 0;
11
+ pending = new Map();
12
+ early = new Map();
13
+ maxEvents;
14
+ maxBytes;
15
+ maxEventBytes;
16
+ maxEarly;
17
+ constructor(o = {}, maxBytes) {
18
+ const opts = typeof o === 'number' ? { maxEvents: o, maxBytes } : o;
19
+ this.maxEvents = opts.maxEvents ?? 512;
20
+ this.maxBytes = opts.maxBytes ?? 1024 * 1024;
21
+ this.maxEventBytes = opts.maxEventBytes ?? 64 * 1024;
22
+ this.maxEarly = opts.maxEarly ?? 256;
23
+ if (![this.maxEvents, this.maxBytes, this.maxEventBytes, this.maxEarly].every(v => Number.isInteger(v) && v > 0))
24
+ throw new RangeError('Invalid event limits');
25
+ }
26
+ push(data) {
27
+ const text = stringify(data, this.maxEventBytes), bytes = utf8Length(text) + 64;
28
+ if (bytes > this.maxEventBytes + 64)
29
+ throw new RangeError('Event payload too large');
30
+ if (this.pending.size >= this.maxEvents || this.bytes + bytes > this.maxBytes)
31
+ throw new Error('Reliable outbox full');
32
+ if (!Number.isSafeInteger(this.next + 1))
33
+ throw new Error('Reliable sequence exhausted');
34
+ const seq = this.next++;
35
+ this.pending.set(seq, { seq, data: JSON.parse(text), bytes, text, datagramAt: -Infinity, datagramTries: 0 });
36
+ this.bytes += bytes;
37
+ return seq;
38
+ }
39
+ get size() { return this.pending.size; }
40
+ get queuedBytes() { return this.bytes; }
41
+ get sentThrough() { return this.highestSent; }
42
+ entries() { return this.pending.values(); }
43
+ sent(seq) { this.highestSent = Math.max(this.highestSent, seq); }
44
+ ack(seq) {
45
+ if (!Number.isSafeInteger(seq) || seq < 0 || seq > this.highestSent)
46
+ throw new Error('Invalid event acknowledgement');
47
+ if (seq <= this.acknowledged)
48
+ return false;
49
+ this.acknowledged = seq;
50
+ for (const [id, e] of this.pending) {
51
+ if (id > seq)
52
+ break;
53
+ this.pending.delete(id);
54
+ this.bytes -= e.bytes;
55
+ }
56
+ return true;
57
+ }
58
+ /** Returns how many events were delivered. Early events wait (bounded); duplicates are dropped. */
59
+ receive(seq, data, deliver) {
60
+ if (!Number.isSafeInteger(seq) || seq < 1)
61
+ throw new Error('Invalid event sequence');
62
+ if (seq <= this.received)
63
+ return 0;
64
+ if (seq !== this.received + 1) {
65
+ if (seq - this.received > this.maxEarly)
66
+ throw new Error('Event sequence gap');
67
+ if (!this.early.has(seq))
68
+ this.early.set(seq, data);
69
+ return 0;
70
+ }
71
+ deliver(data, seq);
72
+ this.received = seq;
73
+ let n = 1;
74
+ for (let s = seq + 1; this.early.has(s); s++) {
75
+ deliver(this.early.get(s), s);
76
+ this.early.delete(s);
77
+ this.received = s;
78
+ n++;
79
+ }
80
+ for (const s of this.early.keys())
81
+ if (s <= this.received)
82
+ this.early.delete(s);
83
+ return n;
84
+ }
85
+ checkpoint() {
86
+ return { next: this.next, received: this.received, acknowledged: this.acknowledged,
87
+ pending: Array.from(this.pending.values(), e => ({ seq: e.seq, data: structuredClone(e.data) })) };
88
+ }
89
+ restore(s) {
90
+ if (this.next !== 1 || this.received || this.pending.size)
91
+ throw new Error('Restore requires a fresh channel');
92
+ if (![s.next, s.received, s.acknowledged].every(v => Number.isSafeInteger(v) && v >= 0) ||
93
+ s.next < 1 || s.acknowledged >= s.next || !Array.isArray(s.pending) || s.pending.length > this.maxEvents)
94
+ throw new Error('Invalid checkpoint');
95
+ if (s.pending.length !== s.next - s.acknowledged - 1)
96
+ throw new Error('Incomplete checkpoint');
97
+ const saved = [];
98
+ let total = 0, expected = s.acknowledged + 1;
99
+ for (const e of s.pending) {
100
+ if (e.seq !== expected++)
101
+ throw new Error('Invalid checkpoint sequence');
102
+ const text = stringify(e.data, this.maxEventBytes), bytes = utf8Length(text) + 64;
103
+ saved.push({ seq: e.seq, data: JSON.parse(text), bytes, text, datagramAt: -Infinity, datagramTries: 0 });
104
+ total += bytes;
105
+ }
106
+ if (total > this.maxBytes)
107
+ throw new Error('Checkpoint exceeds outbox limit');
108
+ this.next = s.next;
109
+ this.received = s.received;
110
+ this.acknowledged = s.acknowledged;
111
+ this.highestSent = s.next - 1;
112
+ this.pending = new Map(saved.map(e => [e.seq, e]));
113
+ this.bytes = total;
114
+ }
115
+ }
116
+ //# sourceMappingURL=reliable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reliable.js","sourceRoot":"","sources":["../../src/core/reliable.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { DatagramLink } from './endpoint.js';
2
+ export type RtcSignal = {
3
+ kind: 'offer' | 'answer';
4
+ sdp: string;
5
+ } | {
6
+ kind: 'candidate';
7
+ candidate: string;
8
+ mid: string;
9
+ };
10
+ export interface RtcCallbacks {
11
+ signal: (message: RtcSignal) => void;
12
+ open: (link: DatagramLink) => void;
13
+ data: (bytes: Uint8Array) => void;
14
+ closed: () => void;
15
+ error: (error: Error) => void;
16
+ }
17
+ export interface RtcPeer {
18
+ signal(message: RtcSignal): void | Promise<void>;
19
+ close(): void;
20
+ }
21
+ /** The browser's RTCIceServer shape: STUN, or TURN with credentials. */
22
+ export interface IceServer {
23
+ urls: string | string[];
24
+ username?: string;
25
+ credential?: string;
26
+ }
27
+ export declare function validSignal(m: unknown): m is RtcSignal;
28
+ export declare function validIceServers(v: unknown): v is IceServer[];
@@ -0,0 +1,21 @@
1
+ export function validSignal(m) {
2
+ if (!m || typeof m !== 'object')
3
+ return false;
4
+ const v = m;
5
+ if (v.kind === 'offer' || v.kind === 'answer')
6
+ return typeof v.sdp === 'string' && v.sdp.length > 0 && v.sdp.length <= 12000;
7
+ return v.kind === 'candidate' && typeof v.candidate === 'string' && v.candidate.length <= 1500 &&
8
+ typeof v.mid === 'string' && v.mid.length <= 128;
9
+ }
10
+ const ICE_URL = /^(stuns?|turns?):[^\s]{1,250}$/;
11
+ export function validIceServers(v) {
12
+ return Array.isArray(v) && v.length <= 8 && v.every(s => {
13
+ if (!s || typeof s !== 'object')
14
+ return false;
15
+ const o = s, urls = Array.isArray(o.urls) ? o.urls : [o.urls];
16
+ return urls.length >= 1 && urls.length <= 8 && urls.every(u => typeof u === 'string' && ICE_URL.test(u)) &&
17
+ (o.username === undefined || typeof o.username === 'string' && o.username.length <= 256) &&
18
+ (o.credential === undefined || typeof o.credential === 'string' && o.credential.length <= 256);
19
+ });
20
+ }
21
+ //# sourceMappingURL=rtc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rtc.js","sourceRoot":"","sources":["../../src/core/rtc.ts"],"names":[],"mappings":"AAYA,MAAM,UAAU,WAAW,CAAC,CAAU;IACpC,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC9C,MAAM,CAAC,GAAG,CAA4B,CAAC;IACvC,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC;IAC7H,OAAO,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,IAAI,IAAI;QAC5F,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC;AACrD,CAAC;AACD,MAAM,OAAO,GAAG,gCAAgC,CAAC;AACjD,MAAM,UAAU,eAAe,CAAC,CAAU;IACxC,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;QACtD,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAC9C,MAAM,CAAC,GAAG,CAA4B,EAAE,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzF,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACtG,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,IAAI,GAAG,CAAC;YACxF,CAAC,CAAC,CAAC,UAAU,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC;IACnG,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './core/endpoint.js';
2
+ export * from './core/protocol.js';
3
+ export * from './core/budget.js';
4
+ export * from './core/reliable.js';
5
+ export * from './core/rtc.js';
6
+ export * from './core/lobby.js';
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export * from './core/endpoint.js';
2
+ export * from './core/protocol.js';
3
+ export * from './core/budget.js';
4
+ export * from './core/reliable.js';
5
+ export * from './core/rtc.js';
6
+ export * from './core/lobby.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,15 @@
1
+ /** Offset estimator using low-RTT exchanges. RTT/2 is NOT a measured one-way latency. */
2
+ export declare class NetworkClock {
3
+ private samples;
4
+ private offset;
5
+ private target;
6
+ private initialized;
7
+ private last;
8
+ get synced(): boolean;
9
+ rttMs: number;
10
+ uncertaintyMs: number;
11
+ reset(): void;
12
+ observe(sent: number, received: number, remoteTime: number): boolean;
13
+ advance(dtMs: number): void;
14
+ serverTime(localTime: number): number;
15
+ }
@@ -0,0 +1,37 @@
1
+ /** Offset estimator using low-RTT exchanges. RTT/2 is NOT a measured one-way latency. */
2
+ export class NetworkClock {
3
+ samples = [];
4
+ offset = 0;
5
+ target = 0;
6
+ initialized = false;
7
+ last = -Infinity;
8
+ get synced() { return this.initialized; }
9
+ rttMs = 0;
10
+ uncertaintyMs = Infinity;
11
+ reset() { this.samples = []; this.offset = this.target = 0; this.initialized = false; this.last = -Infinity; this.uncertaintyMs = Infinity; }
12
+ observe(sent, received, remoteTime) {
13
+ const rtt = received - sent;
14
+ if (![sent, received, remoteTime].every(Number.isFinite) || rtt < 0 || rtt > 15000)
15
+ return false;
16
+ this.samples.push({ rtt, offset: remoteTime - (sent + received) / 2 });
17
+ if (this.samples.length > 16)
18
+ this.samples.shift();
19
+ const best = [...this.samples].sort((a, b) => a.rtt - b.rtt).slice(0, 3);
20
+ this.target = best.reduce((sum, s) => sum + s.offset, 0) / best.length;
21
+ this.rttMs = best[0].rtt;
22
+ this.uncertaintyMs = Math.max(...best.map(s => Math.abs(s.offset - this.target) + s.rtt / 2));
23
+ if (!this.initialized) {
24
+ this.offset = this.target;
25
+ this.initialized = true;
26
+ }
27
+ return true;
28
+ }
29
+ advance(dtMs) {
30
+ if (!Number.isFinite(dtMs) || dtMs < 0)
31
+ throw new RangeError('Invalid time step');
32
+ const max = dtMs * 0.05;
33
+ this.offset += Math.max(-max, Math.min(max, this.target - this.offset));
34
+ }
35
+ serverTime(localTime) { this.last = Math.max(this.last, localTime + this.offset); return this.last; }
36
+ }
37
+ //# sourceMappingURL=clock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock.js","sourceRoot":"","sources":["../../src/netcode/clock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export type Scalar = 'u8' | 'i8' | 'u16' | 'i16' | 'u32' | 'f32' | 'f64';
2
+ export interface Field {
3
+ type: Scalar;
4
+ scale?: number;
5
+ }
6
+ export declare function defineSchema<F extends Record<string, Field>>(schema: F): {
7
+ byteLength: number;
8
+ encode(value: { [K in keyof F]: number; }): Uint8Array;
9
+ decode(b: Uint8Array): { [K in keyof F]: number; } | null;
10
+ };
@@ -0,0 +1,95 @@
1
+ const sizes = { u8: 1, i8: 1, u16: 2, i16: 2, u32: 4, f32: 4, f64: 8 };
2
+ const bounds = {
3
+ u8: [0, 255], i8: [-128, 127], u16: [0, 65535], i16: [-32768, 32767], u32: [0, 4294967295],
4
+ f32: [-3.4028234663852886e38, 3.4028234663852886e38], f64: [-Number.MAX_VALUE, Number.MAX_VALUE],
5
+ };
6
+ export function defineSchema(schema) {
7
+ const fields = Object.entries(schema).map(([key, f]) => ({ key, type: f.type, scale: f.scale ?? 1 }));
8
+ for (const f of fields)
9
+ if (!Object.hasOwn(sizes, f.type) || !(f.scale > 0) || !Number.isFinite(f.scale) || ['__proto__', 'prototype', 'constructor'].includes(f.key))
10
+ throw new RangeError('Invalid field');
11
+ const byteLength = fields.reduce((n, f) => n + sizes[f.type], 0);
12
+ if (!byteLength || byteLength > 1078)
13
+ throw new RangeError('Schema must fit one state payload');
14
+ return {
15
+ byteLength,
16
+ encode(value) {
17
+ const b = new Uint8Array(byteLength), v = new DataView(b.buffer);
18
+ let at = 0;
19
+ for (const f of fields) {
20
+ const source = value[f.key];
21
+ if (!Number.isFinite(source))
22
+ throw new RangeError(`Invalid ${f.key}`);
23
+ let n = source * f.scale;
24
+ if (!f.type.startsWith('f'))
25
+ n = Math.round(n);
26
+ const [min, max] = bounds[f.type];
27
+ if (!Number.isFinite(n) || n < min || n > max)
28
+ throw new RangeError(`Out of range: ${f.key}`);
29
+ switch (f.type) {
30
+ case 'u8':
31
+ v.setUint8(at, n);
32
+ break;
33
+ case 'i8':
34
+ v.setInt8(at, n);
35
+ break;
36
+ case 'u16':
37
+ v.setUint16(at, n, true);
38
+ break;
39
+ case 'i16':
40
+ v.setInt16(at, n, true);
41
+ break;
42
+ case 'u32':
43
+ v.setUint32(at, n, true);
44
+ break;
45
+ case 'f32':
46
+ v.setFloat32(at, n, true);
47
+ break;
48
+ case 'f64':
49
+ v.setFloat64(at, n, true);
50
+ break;
51
+ }
52
+ at += sizes[f.type];
53
+ }
54
+ return b;
55
+ },
56
+ decode(b) {
57
+ if (b.length !== byteLength)
58
+ return null;
59
+ const v = new DataView(b.buffer, b.byteOffset, b.byteLength), out = Object.create(null);
60
+ let at = 0;
61
+ for (const f of fields) {
62
+ let n;
63
+ switch (f.type) {
64
+ case 'u8':
65
+ n = v.getUint8(at);
66
+ break;
67
+ case 'i8':
68
+ n = v.getInt8(at);
69
+ break;
70
+ case 'u16':
71
+ n = v.getUint16(at, true);
72
+ break;
73
+ case 'i16':
74
+ n = v.getInt16(at, true);
75
+ break;
76
+ case 'u32':
77
+ n = v.getUint32(at, true);
78
+ break;
79
+ case 'f32':
80
+ n = v.getFloat32(at, true);
81
+ break;
82
+ case 'f64':
83
+ n = v.getFloat64(at, true);
84
+ break;
85
+ }
86
+ if (!Number.isFinite(n) || !Number.isFinite(n / f.scale))
87
+ return null;
88
+ out[f.key] = n / f.scale;
89
+ at += sizes[f.type];
90
+ }
91
+ return out;
92
+ },
93
+ };
94
+ }
95
+ //# sourceMappingURL=codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/netcode/codec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export * from './clock.js';
2
+ export * from './timing.js';
3
+ export * from './interpolation.js';
4
+ export * from './prediction.js';
5
+ export * from './spatial.js';
6
+ export * from './codec.js';
7
+ export * from './replication.js';
8
+ export * from './inputs.js';
9
+ export * from './snapshots.js';
@@ -0,0 +1,10 @@
1
+ export * from './clock.js';
2
+ export * from './timing.js';
3
+ export * from './interpolation.js';
4
+ export * from './prediction.js';
5
+ export * from './spatial.js';
6
+ export * from './codec.js';
7
+ export * from './replication.js';
8
+ export * from './inputs.js';
9
+ export * from './snapshots.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/netcode/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface BinaryInput {
2
+ seq: number;
3
+ data: Uint8Array;
4
+ }
5
+ /** Bundle recent inputs as redundancy without enabling retransmission of stale movement. */
6
+ export declare function encodeInputs(inputs: readonly BinaryInput[]): Uint8Array;
7
+ export declare function decodeInputs(b: Uint8Array): BinaryInput[] | null;