@lagless/net-wire 0.0.33

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.
@@ -0,0 +1,395 @@
1
+ import { BinarySchema, BinarySchemaPackPipeline, BinarySchemaUnpackPipeline, FieldType, LE } from '@lagless/binary';
2
+ // ─────────────────────────────────────────────────────────────
3
+ // Constants
4
+ // ─────────────────────────────────────────────────────────────
5
+ export const WIRE_VERSION = 1;
6
+ export var MsgType;
7
+ (function(MsgType) {
8
+ MsgType[MsgType["ServerHello"] = 0] = "ServerHello";
9
+ MsgType[MsgType["TickInput"] = 1] = "TickInput";
10
+ MsgType[MsgType["TickInputFanout"] = 2] = "TickInputFanout";
11
+ MsgType[MsgType["CancelInput"] = 3] = "CancelInput";
12
+ MsgType[MsgType["Ping"] = 4] = "Ping";
13
+ MsgType[MsgType["Pong"] = 5] = "Pong";
14
+ MsgType[MsgType["StateRequest"] = 6] = "StateRequest";
15
+ MsgType[MsgType["StateResponse"] = 7] = "StateResponse";
16
+ MsgType[MsgType["PlayerFinished"] = 8] = "PlayerFinished";
17
+ MsgType[MsgType["TickInputBatch"] = 9] = "TickInputBatch";
18
+ })(MsgType || (MsgType = {}));
19
+ export var TickInputKind;
20
+ (function(TickInputKind) {
21
+ TickInputKind[TickInputKind["Client"] = 0] = "Client";
22
+ TickInputKind[TickInputKind["Server"] = 1] = "Server";
23
+ })(TickInputKind || (TickInputKind = {}));
24
+ export var CancelReason;
25
+ (function(CancelReason) {
26
+ CancelReason[CancelReason["TooOld"] = 0] = "TooOld";
27
+ CancelReason[CancelReason["TooFarFuture"] = 1] = "TooFarFuture";
28
+ CancelReason[CancelReason["InvalidSlot"] = 2] = "InvalidSlot";
29
+ })(CancelReason || (CancelReason = {}));
30
+ // ─────────────────────────────────────────────────────────────
31
+ // Schemas
32
+ // ─────────────────────────────────────────────────────────────
33
+ export const HeaderSchema = new BinarySchema({
34
+ version: FieldType.Uint8,
35
+ type: FieldType.Uint8
36
+ });
37
+ export const ServerHelloSchema = new BinarySchema({
38
+ playerSlot: FieldType.Uint8,
39
+ serverTick: FieldType.Uint32,
40
+ maxPlayers: FieldType.Uint8,
41
+ playerCount: FieldType.Uint8
42
+ });
43
+ export const TickInputSchema = new BinarySchema({
44
+ tick: FieldType.Uint32,
45
+ playerSlot: FieldType.Uint8,
46
+ seq: FieldType.Uint32,
47
+ kind: FieldType.Uint8,
48
+ payloadLength: FieldType.Uint16
49
+ });
50
+ export const TickInputFanoutSchema = new BinarySchema({
51
+ serverTick: FieldType.Uint32,
52
+ inputCount: FieldType.Uint8
53
+ });
54
+ export const TickInputBatchSchema = new BinarySchema({
55
+ inputCount: FieldType.Uint8
56
+ });
57
+ export const CancelInputSchema = new BinarySchema({
58
+ tick: FieldType.Uint32,
59
+ playerSlot: FieldType.Uint8,
60
+ seq: FieldType.Uint32,
61
+ reason: FieldType.Uint8
62
+ });
63
+ export const PingSchema = new BinarySchema({
64
+ cSend: FieldType.Float64
65
+ });
66
+ export const PongSchema = new BinarySchema({
67
+ cSend: FieldType.Float64,
68
+ sRecv: FieldType.Float64,
69
+ sSend: FieldType.Float64,
70
+ sTick: FieldType.Uint32
71
+ });
72
+ export const StateRequestSchema = new BinarySchema({
73
+ requestId: FieldType.Uint32
74
+ });
75
+ export const StateResponseHeaderSchema = new BinarySchema({
76
+ requestId: FieldType.Uint32,
77
+ tick: FieldType.Uint32,
78
+ hash: FieldType.Uint32,
79
+ stateLength: FieldType.Uint32
80
+ });
81
+ export const PlayerFinishedSchema = new BinarySchema({
82
+ tick: FieldType.Uint32,
83
+ playerSlot: FieldType.Uint8,
84
+ payloadLength: FieldType.Uint16
85
+ });
86
+ // ─────────────────────────────────────────────────────────────
87
+ // Packing
88
+ // ─────────────────────────────────────────────────────────────
89
+ function packHeader(pipeline, type) {
90
+ pipeline.pack(HeaderSchema, {
91
+ version: WIRE_VERSION,
92
+ type
93
+ });
94
+ }
95
+ export function packServerHello(data) {
96
+ const pipeline = new BinarySchemaPackPipeline();
97
+ packHeader(pipeline, 0);
98
+ pipeline.appendView(data.seed); // 16-byte PRNG seed
99
+ pipeline.pack(ServerHelloSchema, {
100
+ playerSlot: data.playerSlot,
101
+ serverTick: data.serverTick,
102
+ maxPlayers: data.maxPlayers,
103
+ playerCount: data.players.length
104
+ });
105
+ // Pack players: for each player: playerId (16 bytes) + slot (u8) + isBot (u8) + metadataJsonLen (u16) + metadataJson
106
+ const playerChunks = [];
107
+ for (const player of data.players){
108
+ const metadataBytes = new TextEncoder().encode(player.metadataJson);
109
+ const chunk = new ArrayBuffer(16 + 1 + 1 + 2 + metadataBytes.length);
110
+ const view = new DataView(chunk);
111
+ const uint8 = new Uint8Array(chunk);
112
+ uint8.set(player.playerId, 0);
113
+ view.setUint8(16, player.slot);
114
+ view.setUint8(17, player.isBot ? 1 : 0);
115
+ view.setUint16(18, metadataBytes.length, LE);
116
+ uint8.set(metadataBytes, 20);
117
+ playerChunks.push(chunk);
118
+ }
119
+ for (const chunk of playerChunks){
120
+ pipeline.appendBuffer(chunk);
121
+ }
122
+ // Pack scope JSON
123
+ const scopeBytes = new TextEncoder().encode(data.scopeJson);
124
+ const scopeHeader = new ArrayBuffer(2);
125
+ new DataView(scopeHeader).setUint16(0, scopeBytes.length, LE);
126
+ pipeline.appendBuffer(scopeHeader);
127
+ pipeline.appendView(scopeBytes);
128
+ return pipeline.toUint8Array();
129
+ }
130
+ export function packTickInput(data) {
131
+ const pipeline = new BinarySchemaPackPipeline();
132
+ packHeader(pipeline, 1);
133
+ pipeline.pack(TickInputSchema, {
134
+ tick: data.tick,
135
+ playerSlot: data.playerSlot,
136
+ seq: data.seq,
137
+ kind: data.kind,
138
+ payloadLength: data.payload.byteLength
139
+ });
140
+ pipeline.appendView(data.payload);
141
+ return pipeline.toUint8Array();
142
+ }
143
+ export function packTickInputFanout(data) {
144
+ const pipeline = new BinarySchemaPackPipeline();
145
+ packHeader(pipeline, 2);
146
+ pipeline.pack(TickInputFanoutSchema, {
147
+ serverTick: data.serverTick,
148
+ inputCount: data.inputs.length
149
+ });
150
+ for (const input of data.inputs){
151
+ pipeline.pack(TickInputSchema, {
152
+ tick: input.tick,
153
+ playerSlot: input.playerSlot,
154
+ seq: input.seq,
155
+ kind: input.kind,
156
+ payloadLength: input.payload.byteLength
157
+ });
158
+ pipeline.appendView(input.payload);
159
+ }
160
+ return pipeline.toUint8Array();
161
+ }
162
+ export function packTickInputBatch(inputs) {
163
+ const pipeline = new BinarySchemaPackPipeline();
164
+ packHeader(pipeline, 9);
165
+ pipeline.pack(TickInputBatchSchema, {
166
+ inputCount: inputs.length
167
+ });
168
+ for (const input of inputs){
169
+ pipeline.pack(TickInputSchema, {
170
+ tick: input.tick,
171
+ playerSlot: input.playerSlot,
172
+ seq: input.seq,
173
+ kind: input.kind,
174
+ payloadLength: input.payload.byteLength
175
+ });
176
+ pipeline.appendView(input.payload);
177
+ }
178
+ return pipeline.toUint8Array();
179
+ }
180
+ export function packCancelInput(data) {
181
+ const pipeline = new BinarySchemaPackPipeline();
182
+ packHeader(pipeline, 3);
183
+ pipeline.pack(CancelInputSchema, {
184
+ tick: data.tick,
185
+ playerSlot: data.playerSlot,
186
+ seq: data.seq,
187
+ reason: data.reason
188
+ });
189
+ return pipeline.toUint8Array();
190
+ }
191
+ export function packPing(cSend) {
192
+ const pipeline = new BinarySchemaPackPipeline();
193
+ packHeader(pipeline, 4);
194
+ pipeline.pack(PingSchema, {
195
+ cSend
196
+ });
197
+ return pipeline.toUint8Array();
198
+ }
199
+ export function packPong(data) {
200
+ const pipeline = new BinarySchemaPackPipeline();
201
+ packHeader(pipeline, 5);
202
+ pipeline.pack(PongSchema, data);
203
+ return pipeline.toUint8Array();
204
+ }
205
+ export function packStateRequest(requestId) {
206
+ const pipeline = new BinarySchemaPackPipeline();
207
+ packHeader(pipeline, 6);
208
+ pipeline.pack(StateRequestSchema, {
209
+ requestId
210
+ });
211
+ return pipeline.toUint8Array();
212
+ }
213
+ export function packStateResponse(data) {
214
+ const pipeline = new BinarySchemaPackPipeline();
215
+ packHeader(pipeline, 7);
216
+ pipeline.pack(StateResponseHeaderSchema, {
217
+ requestId: data.requestId,
218
+ tick: data.tick,
219
+ hash: data.hash,
220
+ stateLength: data.state.byteLength
221
+ });
222
+ pipeline.appendBuffer(data.state);
223
+ return pipeline.toUint8Array();
224
+ }
225
+ export function packPlayerFinished(data) {
226
+ const pipeline = new BinarySchemaPackPipeline();
227
+ packHeader(pipeline, 8);
228
+ pipeline.pack(PlayerFinishedSchema, {
229
+ tick: data.tick,
230
+ playerSlot: data.playerSlot,
231
+ payloadLength: data.payload.byteLength
232
+ });
233
+ pipeline.appendView(data.payload);
234
+ return pipeline.toUint8Array();
235
+ }
236
+ // ─────────────────────────────────────────────────────────────
237
+ // Unpacking
238
+ // ─────────────────────────────────────────────────────────────
239
+ export function unpackHeader(data) {
240
+ const pipeline = new BinarySchemaUnpackPipeline(data);
241
+ const header = pipeline.unpack(HeaderSchema);
242
+ return {
243
+ version: header.version,
244
+ type: header.type
245
+ };
246
+ }
247
+ export function unpackServerHello(data) {
248
+ const uint8 = new Uint8Array(data);
249
+ const view = new DataView(data);
250
+ let offset = HeaderSchema.byteLength; // skip header (2B)
251
+ // Read 16-byte seed
252
+ const seed = uint8.slice(offset, offset + 16);
253
+ offset += 16;
254
+ // Read schema fields manually (matches ServerHelloSchema field order)
255
+ const playerSlot = view.getUint8(offset);
256
+ offset += 1;
257
+ const serverTick = view.getUint32(offset, LE);
258
+ offset += 4;
259
+ const maxPlayers = view.getUint8(offset);
260
+ offset += 1;
261
+ const playerCount = view.getUint8(offset);
262
+ offset += 1;
263
+ // Players
264
+ const players = [];
265
+ for(let i = 0; i < playerCount; i++){
266
+ const playerId = uint8.slice(offset, offset + 16);
267
+ offset += 16;
268
+ const slot = uint8[offset++];
269
+ const isBot = uint8[offset++] === 1;
270
+ const metadataLen = view.getUint16(offset, LE);
271
+ offset += 2;
272
+ const metadataJson = new TextDecoder().decode(uint8.slice(offset, offset + metadataLen));
273
+ offset += metadataLen;
274
+ players.push({
275
+ playerId,
276
+ slot,
277
+ isBot,
278
+ metadataJson
279
+ });
280
+ }
281
+ // Scope JSON
282
+ const scopeLen = view.getUint16(offset, LE);
283
+ offset += 2;
284
+ const scopeJson = new TextDecoder().decode(uint8.slice(offset, offset + scopeLen));
285
+ return {
286
+ seed,
287
+ playerSlot,
288
+ serverTick,
289
+ maxPlayers,
290
+ players,
291
+ scopeJson
292
+ };
293
+ }
294
+ export function unpackTickInput(data) {
295
+ const pipeline = new BinarySchemaUnpackPipeline(data);
296
+ pipeline.unpack(HeaderSchema); // skip header
297
+ const input = pipeline.unpack(TickInputSchema);
298
+ const payload = new Uint8Array(pipeline.sliceRemaining()).slice(0, input.payloadLength);
299
+ return {
300
+ tick: input.tick,
301
+ playerSlot: input.playerSlot,
302
+ seq: input.seq,
303
+ kind: input.kind,
304
+ payload
305
+ };
306
+ }
307
+ export function unpackCancelInput(data) {
308
+ const pipeline = new BinarySchemaUnpackPipeline(data);
309
+ pipeline.unpack(HeaderSchema);
310
+ const cancel = pipeline.unpack(CancelInputSchema);
311
+ return {
312
+ tick: cancel.tick,
313
+ playerSlot: cancel.playerSlot,
314
+ seq: cancel.seq,
315
+ reason: cancel.reason
316
+ };
317
+ }
318
+ export function unpackPing(data) {
319
+ const pipeline = new BinarySchemaUnpackPipeline(data);
320
+ pipeline.unpack(HeaderSchema);
321
+ const ping = pipeline.unpack(PingSchema);
322
+ return ping.cSend;
323
+ }
324
+ export function unpackPong(data) {
325
+ const pipeline = new BinarySchemaUnpackPipeline(data);
326
+ pipeline.unpack(HeaderSchema);
327
+ return pipeline.unpack(PongSchema);
328
+ }
329
+ export function unpackStateRequest(data) {
330
+ const pipeline = new BinarySchemaUnpackPipeline(data);
331
+ pipeline.unpack(HeaderSchema);
332
+ const req = pipeline.unpack(StateRequestSchema);
333
+ return req.requestId;
334
+ }
335
+ export function unpackStateResponse(data) {
336
+ const pipeline = new BinarySchemaUnpackPipeline(data);
337
+ pipeline.unpack(HeaderSchema);
338
+ const header = pipeline.unpack(StateResponseHeaderSchema);
339
+ const remaining = pipeline.sliceRemaining();
340
+ const state = remaining.slice(0, header.stateLength);
341
+ return {
342
+ requestId: header.requestId,
343
+ tick: header.tick,
344
+ hash: header.hash,
345
+ state
346
+ };
347
+ }
348
+ export function unpackPlayerFinished(data) {
349
+ const pipeline = new BinarySchemaUnpackPipeline(data);
350
+ pipeline.unpack(HeaderSchema);
351
+ const pf = pipeline.unpack(PlayerFinishedSchema);
352
+ const remaining = new Uint8Array(pipeline.sliceRemaining());
353
+ const payload = remaining.slice(0, pf.payloadLength);
354
+ return {
355
+ tick: pf.tick,
356
+ playerSlot: pf.playerSlot,
357
+ payload
358
+ };
359
+ }
360
+ export function unpackTickInputFanout(data) {
361
+ const view = new DataView(data);
362
+ let offset = HeaderSchema.byteLength; // skip header
363
+ const serverTick = view.getUint32(offset, LE);
364
+ offset += 4;
365
+ const inputCount = view.getUint8(offset);
366
+ offset += 1;
367
+ const inputs = [];
368
+ for(let i = 0; i < inputCount; i++){
369
+ const tick = view.getUint32(offset, LE);
370
+ offset += 4;
371
+ const playerSlot = view.getUint8(offset);
372
+ offset += 1;
373
+ const seq = view.getUint32(offset, LE);
374
+ offset += 4;
375
+ const kind = view.getUint8(offset);
376
+ offset += 1;
377
+ const payloadLength = view.getUint16(offset, LE);
378
+ offset += 2;
379
+ const payload = new Uint8Array(data.slice(offset, offset + payloadLength));
380
+ offset += payloadLength;
381
+ inputs.push({
382
+ tick,
383
+ playerSlot,
384
+ seq,
385
+ kind,
386
+ payload
387
+ });
388
+ }
389
+ return {
390
+ serverTick,
391
+ inputs
392
+ };
393
+ }
394
+
395
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/protocol.ts"],"sourcesContent":["import {\n BinarySchema,\n BinarySchemaPackPipeline,\n BinarySchemaUnpackPipeline,\n FieldType,\n LE,\n} from '@lagless/binary';\n\n// ─────────────────────────────────────────────────────────────\n// Constants\n// ─────────────────────────────────────────────────────────────\n\nexport const WIRE_VERSION = 1;\n\nexport const enum MsgType {\n ServerHello = 0,\n TickInput = 1,\n TickInputFanout = 2,\n CancelInput = 3,\n Ping = 4,\n Pong = 5,\n StateRequest = 6,\n StateResponse = 7,\n PlayerFinished = 8,\n TickInputBatch = 9,\n}\n\nexport const enum TickInputKind {\n Client = 0,\n Server = 1,\n}\n\nexport const enum CancelReason {\n TooOld = 0,\n TooFarFuture = 1,\n InvalidSlot = 2,\n}\n\n// ─────────────────────────────────────────────────────────────\n// Schemas\n// ─────────────────────────────────────────────────────────────\n\nexport const HeaderSchema = new BinarySchema({\n version: FieldType.Uint8,\n type: FieldType.Uint8,\n});\n\nexport const ServerHelloSchema = new BinarySchema({\n playerSlot: FieldType.Uint8,\n serverTick: FieldType.Uint32,\n maxPlayers: FieldType.Uint8,\n playerCount: FieldType.Uint8,\n});\n\nexport const TickInputSchema = new BinarySchema({\n tick: FieldType.Uint32,\n playerSlot: FieldType.Uint8,\n seq: FieldType.Uint32,\n kind: FieldType.Uint8,\n payloadLength: FieldType.Uint16,\n});\n\nexport const TickInputFanoutSchema = new BinarySchema({\n serverTick: FieldType.Uint32,\n inputCount: FieldType.Uint8,\n});\n\nexport const TickInputBatchSchema = new BinarySchema({\n inputCount: FieldType.Uint8,\n});\n\nexport const CancelInputSchema = new BinarySchema({\n tick: FieldType.Uint32,\n playerSlot: FieldType.Uint8,\n seq: FieldType.Uint32,\n reason: FieldType.Uint8,\n});\n\nexport const PingSchema = new BinarySchema({\n cSend: FieldType.Float64,\n});\n\nexport const PongSchema = new BinarySchema({\n cSend: FieldType.Float64,\n sRecv: FieldType.Float64,\n sSend: FieldType.Float64,\n sTick: FieldType.Uint32,\n});\n\nexport const StateRequestSchema = new BinarySchema({\n requestId: FieldType.Uint32,\n});\n\nexport const StateResponseHeaderSchema = new BinarySchema({\n requestId: FieldType.Uint32,\n tick: FieldType.Uint32,\n hash: FieldType.Uint32,\n stateLength: FieldType.Uint32,\n});\n\nexport const PlayerFinishedSchema = new BinarySchema({\n tick: FieldType.Uint32,\n playerSlot: FieldType.Uint8,\n payloadLength: FieldType.Uint16,\n});\n\n// ─────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────\n\nexport interface ServerHelloPlayer {\n readonly playerId: Uint8Array; // 16 bytes UUID\n readonly slot: number;\n readonly isBot: boolean;\n readonly metadataJson: string; // JSON-encoded metadata\n}\n\nexport interface ServerHelloData {\n readonly seed: Uint8Array; // 16-byte PRNG seed\n readonly playerSlot: number;\n readonly serverTick: number;\n readonly maxPlayers: number;\n readonly players: ReadonlyArray<ServerHelloPlayer>;\n readonly scopeJson: string;\n}\n\nexport interface TickInputData {\n readonly tick: number;\n readonly playerSlot: number;\n readonly seq: number;\n readonly kind: TickInputKind;\n readonly payload: Uint8Array;\n}\n\nexport interface FanoutData {\n readonly serverTick: number;\n readonly inputs: ReadonlyArray<TickInputData>;\n}\n\nexport interface CancelInputData {\n readonly tick: number;\n readonly playerSlot: number;\n readonly seq: number;\n readonly reason: CancelReason;\n}\n\nexport interface PongData {\n readonly cSend: number;\n readonly sRecv: number;\n readonly sSend: number;\n readonly sTick: number;\n}\n\nexport interface StateResponseData {\n readonly requestId: number;\n readonly tick: number;\n readonly hash: number;\n readonly state: ArrayBuffer;\n}\n\nexport interface PlayerFinishedData {\n readonly tick: number;\n readonly playerSlot: number;\n readonly payload: Uint8Array;\n}\n\n// ─────────────────────────────────────────────────────────────\n// Packing\n// ─────────────────────────────────────────────────────────────\n\nfunction packHeader(pipeline: BinarySchemaPackPipeline, type: MsgType): void {\n pipeline.pack(HeaderSchema, { version: WIRE_VERSION, type });\n}\n\nexport function packServerHello(data: ServerHelloData): Uint8Array {\n const pipeline = new BinarySchemaPackPipeline();\n\n packHeader(pipeline, MsgType.ServerHello);\n pipeline.appendView(data.seed); // 16-byte PRNG seed\n pipeline.pack(ServerHelloSchema, {\n playerSlot: data.playerSlot,\n serverTick: data.serverTick,\n maxPlayers: data.maxPlayers,\n playerCount: data.players.length,\n });\n\n // Pack players: for each player: playerId (16 bytes) + slot (u8) + isBot (u8) + metadataJsonLen (u16) + metadataJson\n const playerChunks: ArrayBuffer[] = [];\n for (const player of data.players) {\n const metadataBytes = new TextEncoder().encode(player.metadataJson);\n const chunk = new ArrayBuffer(16 + 1 + 1 + 2 + metadataBytes.length);\n const view = new DataView(chunk);\n const uint8 = new Uint8Array(chunk);\n uint8.set(player.playerId, 0);\n view.setUint8(16, player.slot);\n view.setUint8(17, player.isBot ? 1 : 0);\n view.setUint16(18, metadataBytes.length, LE);\n uint8.set(metadataBytes, 20);\n playerChunks.push(chunk);\n }\n for (const chunk of playerChunks) {\n pipeline.appendBuffer(chunk);\n }\n\n // Pack scope JSON\n const scopeBytes = new TextEncoder().encode(data.scopeJson);\n const scopeHeader = new ArrayBuffer(2);\n new DataView(scopeHeader).setUint16(0, scopeBytes.length, LE);\n pipeline.appendBuffer(scopeHeader);\n pipeline.appendView(scopeBytes);\n\n return pipeline.toUint8Array();\n}\n\nexport function packTickInput(data: TickInputData): Uint8Array {\n const pipeline = new BinarySchemaPackPipeline();\n packHeader(pipeline, MsgType.TickInput);\n pipeline.pack(TickInputSchema, {\n tick: data.tick,\n playerSlot: data.playerSlot,\n seq: data.seq,\n kind: data.kind,\n payloadLength: data.payload.byteLength,\n });\n pipeline.appendView(data.payload);\n return pipeline.toUint8Array();\n}\n\nexport function packTickInputFanout(data: FanoutData): Uint8Array {\n const pipeline = new BinarySchemaPackPipeline();\n packHeader(pipeline, MsgType.TickInputFanout);\n pipeline.pack(TickInputFanoutSchema, {\n serverTick: data.serverTick,\n inputCount: data.inputs.length,\n });\n\n for (const input of data.inputs) {\n pipeline.pack(TickInputSchema, {\n tick: input.tick,\n playerSlot: input.playerSlot,\n seq: input.seq,\n kind: input.kind,\n payloadLength: input.payload.byteLength,\n });\n pipeline.appendView(input.payload);\n }\n\n return pipeline.toUint8Array();\n}\n\nexport function packTickInputBatch(inputs: ReadonlyArray<TickInputData>): Uint8Array {\n const pipeline = new BinarySchemaPackPipeline();\n packHeader(pipeline, MsgType.TickInputBatch);\n pipeline.pack(TickInputBatchSchema, { inputCount: inputs.length });\n\n for (const input of inputs) {\n pipeline.pack(TickInputSchema, {\n tick: input.tick,\n playerSlot: input.playerSlot,\n seq: input.seq,\n kind: input.kind,\n payloadLength: input.payload.byteLength,\n });\n pipeline.appendView(input.payload);\n }\n\n return pipeline.toUint8Array();\n}\n\nexport function packCancelInput(data: CancelInputData): Uint8Array {\n const pipeline = new BinarySchemaPackPipeline();\n packHeader(pipeline, MsgType.CancelInput);\n pipeline.pack(CancelInputSchema, {\n tick: data.tick,\n playerSlot: data.playerSlot,\n seq: data.seq,\n reason: data.reason,\n });\n return pipeline.toUint8Array();\n}\n\nexport function packPing(cSend: number): Uint8Array {\n const pipeline = new BinarySchemaPackPipeline();\n packHeader(pipeline, MsgType.Ping);\n pipeline.pack(PingSchema, { cSend });\n return pipeline.toUint8Array();\n}\n\nexport function packPong(data: PongData): Uint8Array {\n const pipeline = new BinarySchemaPackPipeline();\n packHeader(pipeline, MsgType.Pong);\n pipeline.pack(PongSchema, data);\n return pipeline.toUint8Array();\n}\n\nexport function packStateRequest(requestId: number): Uint8Array {\n const pipeline = new BinarySchemaPackPipeline();\n packHeader(pipeline, MsgType.StateRequest);\n pipeline.pack(StateRequestSchema, { requestId });\n return pipeline.toUint8Array();\n}\n\nexport function packStateResponse(data: StateResponseData): Uint8Array {\n const pipeline = new BinarySchemaPackPipeline();\n packHeader(pipeline, MsgType.StateResponse);\n pipeline.pack(StateResponseHeaderSchema, {\n requestId: data.requestId,\n tick: data.tick,\n hash: data.hash,\n stateLength: data.state.byteLength,\n });\n pipeline.appendBuffer(data.state);\n return pipeline.toUint8Array();\n}\n\nexport function packPlayerFinished(data: PlayerFinishedData): Uint8Array {\n const pipeline = new BinarySchemaPackPipeline();\n packHeader(pipeline, MsgType.PlayerFinished);\n pipeline.pack(PlayerFinishedSchema, {\n tick: data.tick,\n playerSlot: data.playerSlot,\n payloadLength: data.payload.byteLength,\n });\n pipeline.appendView(data.payload);\n return pipeline.toUint8Array();\n}\n\n// ─────────────────────────────────────────────────────────────\n// Unpacking\n// ─────────────────────────────────────────────────────────────\n\nexport function unpackHeader(data: ArrayBuffer): { version: number; type: MsgType } {\n const pipeline = new BinarySchemaUnpackPipeline(data);\n const header = pipeline.unpack(HeaderSchema);\n return { version: header.version, type: header.type as MsgType };\n}\n\nexport function unpackServerHello(data: ArrayBuffer): ServerHelloData {\n const uint8 = new Uint8Array(data);\n const view = new DataView(data);\n let offset = HeaderSchema.byteLength; // skip header (2B)\n\n // Read 16-byte seed\n const seed = uint8.slice(offset, offset + 16);\n offset += 16;\n\n // Read schema fields manually (matches ServerHelloSchema field order)\n const playerSlot = view.getUint8(offset); offset += 1;\n const serverTick = view.getUint32(offset, LE); offset += 4;\n const maxPlayers = view.getUint8(offset); offset += 1;\n const playerCount = view.getUint8(offset); offset += 1;\n\n // Players\n const players: ServerHelloPlayer[] = [];\n for (let i = 0; i < playerCount; i++) {\n const playerId = uint8.slice(offset, offset + 16);\n offset += 16;\n const slot = uint8[offset++];\n const isBot = uint8[offset++] === 1;\n const metadataLen = view.getUint16(offset, LE);\n offset += 2;\n const metadataJson = new TextDecoder().decode(uint8.slice(offset, offset + metadataLen));\n offset += metadataLen;\n players.push({ playerId, slot, isBot, metadataJson });\n }\n\n // Scope JSON\n const scopeLen = view.getUint16(offset, LE);\n offset += 2;\n const scopeJson = new TextDecoder().decode(uint8.slice(offset, offset + scopeLen));\n\n return {\n seed,\n playerSlot,\n serverTick,\n maxPlayers,\n players,\n scopeJson,\n };\n}\n\nexport function unpackTickInput(data: ArrayBuffer): TickInputData {\n const pipeline = new BinarySchemaUnpackPipeline(data);\n pipeline.unpack(HeaderSchema); // skip header\n const input = pipeline.unpack(TickInputSchema);\n const payload = new Uint8Array(pipeline.sliceRemaining()).slice(0, input.payloadLength);\n return {\n tick: input.tick,\n playerSlot: input.playerSlot,\n seq: input.seq,\n kind: input.kind as TickInputKind,\n payload,\n };\n}\n\nexport function unpackCancelInput(data: ArrayBuffer): CancelInputData {\n const pipeline = new BinarySchemaUnpackPipeline(data);\n pipeline.unpack(HeaderSchema);\n const cancel = pipeline.unpack(CancelInputSchema);\n return {\n tick: cancel.tick,\n playerSlot: cancel.playerSlot,\n seq: cancel.seq,\n reason: cancel.reason as CancelReason,\n };\n}\n\nexport function unpackPing(data: ArrayBuffer): number {\n const pipeline = new BinarySchemaUnpackPipeline(data);\n pipeline.unpack(HeaderSchema);\n const ping = pipeline.unpack(PingSchema);\n return ping.cSend;\n}\n\nexport function unpackPong(data: ArrayBuffer): PongData {\n const pipeline = new BinarySchemaUnpackPipeline(data);\n pipeline.unpack(HeaderSchema);\n return pipeline.unpack(PongSchema);\n}\n\nexport function unpackStateRequest(data: ArrayBuffer): number {\n const pipeline = new BinarySchemaUnpackPipeline(data);\n pipeline.unpack(HeaderSchema);\n const req = pipeline.unpack(StateRequestSchema);\n return req.requestId;\n}\n\nexport function unpackStateResponse(data: ArrayBuffer): StateResponseData {\n const pipeline = new BinarySchemaUnpackPipeline(data);\n pipeline.unpack(HeaderSchema);\n const header = pipeline.unpack(StateResponseHeaderSchema);\n const remaining = pipeline.sliceRemaining();\n const state = remaining.slice(0, header.stateLength);\n return {\n requestId: header.requestId,\n tick: header.tick,\n hash: header.hash,\n state,\n };\n}\n\nexport function unpackPlayerFinished(data: ArrayBuffer): PlayerFinishedData {\n const pipeline = new BinarySchemaUnpackPipeline(data);\n pipeline.unpack(HeaderSchema);\n const pf = pipeline.unpack(PlayerFinishedSchema);\n const remaining = new Uint8Array(pipeline.sliceRemaining());\n const payload = remaining.slice(0, pf.payloadLength);\n return {\n tick: pf.tick,\n playerSlot: pf.playerSlot,\n payload,\n };\n}\n\nexport function unpackTickInputFanout(data: ArrayBuffer): FanoutData {\n const view = new DataView(data);\n let offset = HeaderSchema.byteLength; // skip header\n\n const serverTick = view.getUint32(offset, LE); offset += 4;\n const inputCount = view.getUint8(offset); offset += 1;\n\n const inputs: TickInputData[] = [];\n for (let i = 0; i < inputCount; i++) {\n const tick = view.getUint32(offset, LE); offset += 4;\n const playerSlot = view.getUint8(offset); offset += 1;\n const seq = view.getUint32(offset, LE); offset += 4;\n const kind = view.getUint8(offset) as TickInputKind; offset += 1;\n const payloadLength = view.getUint16(offset, LE); offset += 2;\n const payload = new Uint8Array(data.slice(offset, offset + payloadLength));\n offset += payloadLength;\n\n inputs.push({ tick, playerSlot, seq, kind, payload });\n }\n\n return { serverTick, inputs };\n}\n"],"names":["BinarySchema","BinarySchemaPackPipeline","BinarySchemaUnpackPipeline","FieldType","LE","WIRE_VERSION","MsgType","TickInputKind","CancelReason","HeaderSchema","version","Uint8","type","ServerHelloSchema","playerSlot","serverTick","Uint32","maxPlayers","playerCount","TickInputSchema","tick","seq","kind","payloadLength","Uint16","TickInputFanoutSchema","inputCount","TickInputBatchSchema","CancelInputSchema","reason","PingSchema","cSend","Float64","PongSchema","sRecv","sSend","sTick","StateRequestSchema","requestId","StateResponseHeaderSchema","hash","stateLength","PlayerFinishedSchema","packHeader","pipeline","pack","packServerHello","data","appendView","seed","players","length","playerChunks","player","metadataBytes","TextEncoder","encode","metadataJson","chunk","ArrayBuffer","view","DataView","uint8","Uint8Array","set","playerId","setUint8","slot","isBot","setUint16","push","appendBuffer","scopeBytes","scopeJson","scopeHeader","toUint8Array","packTickInput","payload","byteLength","packTickInputFanout","inputs","input","packTickInputBatch","packCancelInput","packPing","packPong","packStateRequest","packStateResponse","state","packPlayerFinished","unpackHeader","header","unpack","unpackServerHello","offset","slice","getUint8","getUint32","i","metadataLen","getUint16","TextDecoder","decode","scopeLen","unpackTickInput","sliceRemaining","unpackCancelInput","cancel","unpackPing","ping","unpackPong","unpackStateRequest","req","unpackStateResponse","remaining","unpackPlayerFinished","pf","unpackTickInputFanout"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Stores tick-indexed input data for late joiner synchronization.
3
+ * Automatically prunes old entries based on retention policy.
4
+ */
5
+ export declare class TickInputBuffer {
6
+ private readonly _maxRetentionTicks;
7
+ private readonly _buffer;
8
+ private _oldestStoredTick;
9
+ constructor(_maxRetentionTicks?: number);
10
+ get oldestTick(): number;
11
+ get size(): number;
12
+ /**
13
+ * Adds input data for a specific tick.
14
+ */
15
+ add(tick: number, data: Uint8Array): void;
16
+ /**
17
+ * Returns all inputs from the specified tick onwards (inclusive).
18
+ */
19
+ getFromTick(fromTick: number): ReadonlyMap<number, ReadonlyArray<Uint8Array>>;
20
+ /**
21
+ * Returns flattened array of all inputs from tick onwards.
22
+ */
23
+ getFlattenedFromTick(fromTick: number): Uint8Array[];
24
+ /**
25
+ * Prunes entries older than the retention window.
26
+ */
27
+ prune(currentTick: number): number;
28
+ clear(): void;
29
+ }
30
+ //# sourceMappingURL=tick-input-buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tick-input-buffer.d.ts","sourceRoot":"","sources":["../../src/lib/tick-input-buffer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,eAAe;IAKxB,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAJrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwC;IAChE,OAAO,CAAC,iBAAiB,CAAK;gBAGX,kBAAkB,SAAM;IAG3C,IAAW,UAAU,IAAI,MAAM,CAE9B;IAED,IAAW,IAAI,IAAI,MAAM,CAExB;IAED;;OAEG;IACI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI;IAahD;;OAEG;IACI,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAUpF;;OAEG;IACI,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE;IAa3D;;OAEG;IACI,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAqBlC,KAAK,IAAI,IAAI;CAIrB"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Stores tick-indexed input data for late joiner synchronization.
3
+ * Automatically prunes old entries based on retention policy.
4
+ */ export class TickInputBuffer {
5
+ get oldestTick() {
6
+ return this._oldestStoredTick;
7
+ }
8
+ get size() {
9
+ return this._buffer.size;
10
+ }
11
+ /**
12
+ * Adds input data for a specific tick.
13
+ */ add(tick, data) {
14
+ let bucket = this._buffer.get(tick);
15
+ if (!bucket) {
16
+ bucket = [];
17
+ this._buffer.set(tick, bucket);
18
+ }
19
+ bucket.push(data);
20
+ if (this._oldestStoredTick === 0 || tick < this._oldestStoredTick) {
21
+ this._oldestStoredTick = tick;
22
+ }
23
+ }
24
+ /**
25
+ * Returns all inputs from the specified tick onwards (inclusive).
26
+ */ getFromTick(fromTick) {
27
+ const result = new Map();
28
+ for (const [tick, inputs] of this._buffer){
29
+ if (tick >= fromTick) {
30
+ result.set(tick, [
31
+ ...inputs
32
+ ]);
33
+ }
34
+ }
35
+ return result;
36
+ }
37
+ /**
38
+ * Returns flattened array of all inputs from tick onwards.
39
+ */ getFlattenedFromTick(fromTick) {
40
+ const result = [];
41
+ const sortedTicks = [
42
+ ...this._buffer.keys()
43
+ ].filter((t)=>t >= fromTick).sort((a, b)=>a - b);
44
+ for (const tick of sortedTicks){
45
+ const bucket = this._buffer.get(tick);
46
+ if (bucket) {
47
+ result.push(...bucket);
48
+ }
49
+ }
50
+ return result;
51
+ }
52
+ /**
53
+ * Prunes entries older than the retention window.
54
+ */ prune(currentTick) {
55
+ const threshold = currentTick - this._maxRetentionTicks;
56
+ let pruned = 0;
57
+ for (const tick of this._buffer.keys()){
58
+ if (tick < threshold) {
59
+ this._buffer.delete(tick);
60
+ pruned++;
61
+ }
62
+ }
63
+ // Update oldest tick marker
64
+ if (this._buffer.size === 0) {
65
+ this._oldestStoredTick = 0;
66
+ } else {
67
+ this._oldestStoredTick = Math.min(...this._buffer.keys());
68
+ }
69
+ return pruned;
70
+ }
71
+ clear() {
72
+ this._buffer.clear();
73
+ this._oldestStoredTick = 0;
74
+ }
75
+ constructor(_maxRetentionTicks = 600 // ~10 seconds at 60fps
76
+ ){
77
+ this._maxRetentionTicks = _maxRetentionTicks;
78
+ this._buffer = new Map();
79
+ this._oldestStoredTick = 0;
80
+ }
81
+ }
82
+
83
+ //# sourceMappingURL=tick-input-buffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/tick-input-buffer.ts"],"sourcesContent":["/**\n * Stores tick-indexed input data for late joiner synchronization.\n * Automatically prunes old entries based on retention policy.\n */\nexport class TickInputBuffer {\n private readonly _buffer: Map<number, Uint8Array[]> = new Map();\n private _oldestStoredTick = 0;\n\n public constructor(\n private readonly _maxRetentionTicks = 600 // ~10 seconds at 60fps\n ) {}\n\n public get oldestTick(): number {\n return this._oldestStoredTick;\n }\n\n public get size(): number {\n return this._buffer.size;\n }\n\n /**\n * Adds input data for a specific tick.\n */\n public add(tick: number, data: Uint8Array): void {\n let bucket = this._buffer.get(tick);\n if (!bucket) {\n bucket = [];\n this._buffer.set(tick, bucket);\n }\n bucket.push(data);\n\n if (this._oldestStoredTick === 0 || tick < this._oldestStoredTick) {\n this._oldestStoredTick = tick;\n }\n }\n\n /**\n * Returns all inputs from the specified tick onwards (inclusive).\n */\n public getFromTick(fromTick: number): ReadonlyMap<number, ReadonlyArray<Uint8Array>> {\n const result = new Map<number, Uint8Array[]>();\n for (const [tick, inputs] of this._buffer) {\n if (tick >= fromTick) {\n result.set(tick, [...inputs]);\n }\n }\n return result;\n }\n\n /**\n * Returns flattened array of all inputs from tick onwards.\n */\n public getFlattenedFromTick(fromTick: number): Uint8Array[] {\n const result: Uint8Array[] = [];\n const sortedTicks = [...this._buffer.keys()].filter(t => t >= fromTick).sort((a, b) => a - b);\n\n for (const tick of sortedTicks) {\n const bucket = this._buffer.get(tick);\n if (bucket) {\n result.push(...bucket);\n }\n }\n return result;\n }\n\n /**\n * Prunes entries older than the retention window.\n */\n public prune(currentTick: number): number {\n const threshold = currentTick - this._maxRetentionTicks;\n let pruned = 0;\n\n for (const tick of this._buffer.keys()) {\n if (tick < threshold) {\n this._buffer.delete(tick);\n pruned++;\n }\n }\n\n // Update oldest tick marker\n if (this._buffer.size === 0) {\n this._oldestStoredTick = 0;\n } else {\n this._oldestStoredTick = Math.min(...this._buffer.keys());\n }\n\n return pruned;\n }\n\n public clear(): void {\n this._buffer.clear();\n this._oldestStoredTick = 0;\n }\n}\n"],"names":["TickInputBuffer","oldestTick","_oldestStoredTick","size","_buffer","add","tick","data","bucket","get","set","push","getFromTick","fromTick","result","Map","inputs","getFlattenedFromTick","sortedTicks","keys","filter","t","sort","a","b","prune","currentTick","threshold","_maxRetentionTicks","pruned","delete","Math","min","clear"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;CAGC,GACD,OAAO,MAAMA;IAQX,IAAWC,aAAqB;QAC9B,OAAO,IAAI,CAACC,iBAAiB;IAC/B;IAEA,IAAWC,OAAe;QACxB,OAAO,IAAI,CAACC,OAAO,CAACD,IAAI;IAC1B;IAEA;;GAEC,GACD,AAAOE,IAAIC,IAAY,EAAEC,IAAgB,EAAQ;QAC/C,IAAIC,SAAS,IAAI,CAACJ,OAAO,CAACK,GAAG,CAACH;QAC9B,IAAI,CAACE,QAAQ;YACXA,SAAS,EAAE;YACX,IAAI,CAACJ,OAAO,CAACM,GAAG,CAACJ,MAAME;QACzB;QACAA,OAAOG,IAAI,CAACJ;QAEZ,IAAI,IAAI,CAACL,iBAAiB,KAAK,KAAKI,OAAO,IAAI,CAACJ,iBAAiB,EAAE;YACjE,IAAI,CAACA,iBAAiB,GAAGI;QAC3B;IACF;IAEA;;GAEC,GACD,AAAOM,YAAYC,QAAgB,EAAkD;QACnF,MAAMC,SAAS,IAAIC;QACnB,KAAK,MAAM,CAACT,MAAMU,OAAO,IAAI,IAAI,CAACZ,OAAO,CAAE;YACzC,IAAIE,QAAQO,UAAU;gBACpBC,OAAOJ,GAAG,CAACJ,MAAM;uBAAIU;iBAAO;YAC9B;QACF;QACA,OAAOF;IACT;IAEA;;GAEC,GACD,AAAOG,qBAAqBJ,QAAgB,EAAgB;QAC1D,MAAMC,SAAuB,EAAE;QAC/B,MAAMI,cAAc;eAAI,IAAI,CAACd,OAAO,CAACe,IAAI;SAAG,CAACC,MAAM,CAACC,CAAAA,IAAKA,KAAKR,UAAUS,IAAI,CAAC,CAACC,GAAGC,IAAMD,IAAIC;QAE3F,KAAK,MAAMlB,QAAQY,YAAa;YAC9B,MAAMV,SAAS,IAAI,CAACJ,OAAO,CAACK,GAAG,CAACH;YAChC,IAAIE,QAAQ;gBACVM,OAAOH,IAAI,IAAIH;YACjB;QACF;QACA,OAAOM;IACT;IAEA;;GAEC,GACD,AAAOW,MAAMC,WAAmB,EAAU;QACxC,MAAMC,YAAYD,cAAc,IAAI,CAACE,kBAAkB;QACvD,IAAIC,SAAS;QAEb,KAAK,MAAMvB,QAAQ,IAAI,CAACF,OAAO,CAACe,IAAI,GAAI;YACtC,IAAIb,OAAOqB,WAAW;gBACpB,IAAI,CAACvB,OAAO,CAAC0B,MAAM,CAACxB;gBACpBuB;YACF;QACF;QAEA,4BAA4B;QAC5B,IAAI,IAAI,CAACzB,OAAO,CAACD,IAAI,KAAK,GAAG;YAC3B,IAAI,CAACD,iBAAiB,GAAG;QAC3B,OAAO;YACL,IAAI,CAACA,iBAAiB,GAAG6B,KAAKC,GAAG,IAAI,IAAI,CAAC5B,OAAO,CAACe,IAAI;QACxD;QAEA,OAAOU;IACT;IAEOI,QAAc;QACnB,IAAI,CAAC7B,OAAO,CAAC6B,KAAK;QAClB,IAAI,CAAC/B,iBAAiB,GAAG;IAC3B;IApFA,YACE,AAAiB0B,qBAAqB,IAAI,uBAAuB;IAAxB,CACzC;aADiBA,qBAAAA;aAJFxB,UAAqC,IAAIW;aAClDb,oBAAoB;IAIzB;AAmFL"}
@@ -0,0 +1 @@
1
+ {"version":"5.9.3"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@lagless/net-wire",
3
+ "version": "0.0.33",
4
+ "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/ppauel/lagless",
8
+ "directory": "libs/net-wire"
9
+ },
10
+ "type": "module",
11
+ "main": "./dist/index.js",
12
+ "module": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ "./package.json": "./package.json",
16
+ ".": {
17
+ "@lagless/source": "./src/index.ts",
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js",
20
+ "default": "./dist/index.js"
21
+ }
22
+ },
23
+ "nx": {
24
+ "sourceRoot": "libs/net-wire/src",
25
+ "targets": {
26
+ "build": {
27
+ "executor": "@nx/js:swc",
28
+ "outputs": [
29
+ "{options.outputPath}"
30
+ ],
31
+ "options": {
32
+ "outputPath": "libs/net-wire/dist",
33
+ "main": "libs/net-wire/src/index.ts",
34
+ "tsConfig": "libs/net-wire/tsconfig.lib.json",
35
+ "skipTypeCheck": true,
36
+ "stripLeadingPaths": true
37
+ }
38
+ }
39
+ }
40
+ },
41
+ "dependencies": {
42
+ "@swc/helpers": "~0.5.11",
43
+ "@lagless/binary": "0.0.33",
44
+ "@lagless/misc": "0.0.33"
45
+ },
46
+ "files": [
47
+ "dist",
48
+ "README.md"
49
+ ],
50
+ "publishConfig": {
51
+ "access": "public"
52
+ }
53
+ }