From ffb7a913d88e0e769a9385fbae41b6690245d78f Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Fri, 22 Dec 2023 17:13:08 -0300 Subject: [PATCH 01/38] add http test --- test/http_test.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 test/http_test.ts diff --git a/test/http_test.ts b/test/http_test.ts new file mode 100644 index 0000000..c09380b --- /dev/null +++ b/test/http_test.ts @@ -0,0 +1,23 @@ +import './util'; +import assert from "assert"; +import { Client, Room } from "../src"; + +describe("HTTP", function() { + let client: Client; + + before(() => { + client = new Client("ws://localhost:4545"); + }); + + describe("errors", () => { + it("should return 'offline' error when requesting offline service", async () => { + try { + await client.http.post("/anything"); + } catch (e) { + console.log({code: e.code, message: e.message}); + console.log(e); + } + }); + }); + +}); From 106a89961a384603d0f7e1c65a10c7c97765f0f9 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Fri, 22 Dec 2023 17:13:18 -0300 Subject: [PATCH 02/38] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e0dbb42..3f5b030 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.15-preview.22", + "version": "0.15.15", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", From 339610cb5918f1404363f6388fb47af7c4fa073e Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Sun, 14 Jan 2024 10:46:49 -0300 Subject: [PATCH 03/38] drafting WebTransport support --- src/transport/WebTransportTransport.ts | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/transport/WebTransportTransport.ts diff --git a/src/transport/WebTransportTransport.ts b/src/transport/WebTransportTransport.ts new file mode 100644 index 0000000..86bf75c --- /dev/null +++ b/src/transport/WebTransportTransport.ts @@ -0,0 +1,43 @@ +import { ITransport, ITransportEventMap } from "./ITransport"; + +export class WebTransportTransport implements ITransport { + wt: WebTransport; + isOpen: boolean = false; + + constructor(public events: ITransportEventMap) {} + + public send(data: ArrayBuffer | Array): void { + if (data instanceof ArrayBuffer) { + // this.ws.send(data); + + } else if (Array.isArray(data)) { + // this.ws.send((new Uint8Array(data)).buffer); + } + } + + public connect(url: string) { + this.wt = new WebTransport(url); + + this.wt.ready.then((e) => { + this.isOpen = true; + this.events.onopen(e); + }).catch((e: WebTransportCloseInfo) => { + this.events.onerror(e); + this.events.onclose({ code: e.closeCode, reason: e.reason }); + }); + + this.wt.closed.then((e: WebTransportCloseInfo) => { + this.events.onclose({ code: e.closeCode, reason: e.reason }); + }).catch((e: WebTransportCloseInfo) => { + this.events.onerror(e); + this.events.onclose({ code: e.closeCode, reason: e.reason }); + }); + + // this.wt.onmessage = this.events.onmessage; + } + + public close(code?: number, reason?: string) { + this.wt.close({ closeCode: code, reason: reason }); + } + +} From 3ebe124d0304f8579f78df87a1f5280f7b54949f Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Mon, 22 Jan 2024 22:35:01 -0300 Subject: [PATCH 04/38] rename WebTransportTransport to H3Transport --- src/Client.ts | 2 +- src/Connection.ts | 21 ++++++++++---- src/Room.ts | 5 ++-- ...ebTransportTransport.ts => H3Transport.ts} | 29 ++++++++++++------- src/transport/ITransport.ts | 1 + src/transport/WebSocketTransport.ts | 4 +++ 6 files changed, 44 insertions(+), 18 deletions(-) rename src/transport/{WebTransportTransport.ts => H3Transport.ts} (79%) diff --git a/src/Client.ts b/src/Client.ts index 9c8401b..8896d95 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -155,7 +155,7 @@ export class Client { }; setTimeout(retryReconnection, 2000); - }), targetRoom); + }), targetRoom, response.protocol); return new Promise((resolve, reject) => { const onError = (code, message) => reject(new ServerError(code, message)); diff --git a/src/Connection.ts b/src/Connection.ts index 9b321ef..f694f13 100644 --- a/src/Connection.ts +++ b/src/Connection.ts @@ -1,3 +1,4 @@ +import { H3TransportTransport } from "./transport/H3Transport"; import { ITransport, ITransportEventMap } from "./transport/ITransport"; import { WebSocketTransport } from "./transport/WebSocketTransport"; @@ -5,17 +6,27 @@ export class Connection implements ITransport { transport: ITransport; events: ITransportEventMap = {}; - constructor() { - this.transport = new WebSocketTransport(this.events); + constructor(protocol?: string) { + switch (protocol) { + case "h3": + this.transport = new H3TransportTransport(this.events); + + default: + this.transport = new WebSocketTransport(this.events); + break; + } + } + + connect(url: string): void { + this.transport.connect(url); } send(data: ArrayBuffer | Array): void { this.transport.send(data); } - - connect(url: string): void { - this.transport.connect(url); + sendUnreliable(data: ArrayBuffer | Array): void { + this.transport.sendUnreliable(data); } close(code?: number, reason?: string): void { diff --git a/src/Room.ts b/src/Room.ts index 2e49f92..3245812 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -65,9 +65,10 @@ export class Room { public connect( endpoint: string, devModeCloseCallback?: () => void, - room: Room = this // when reconnecting on devMode, re-use previous room intance for handling events. + room: Room = this, // when reconnecting on devMode, re-use previous room intance for handling events. + protocol?: string, ) { - const connection = new Connection(); + const connection = new Connection(protocol); room.connection = connection; connection.events.onmessage = Room.prototype.onMessageCallback.bind(room); diff --git a/src/transport/WebTransportTransport.ts b/src/transport/H3Transport.ts similarity index 79% rename from src/transport/WebTransportTransport.ts rename to src/transport/H3Transport.ts index 86bf75c..83ffbc5 100644 --- a/src/transport/WebTransportTransport.ts +++ b/src/transport/H3Transport.ts @@ -1,20 +1,11 @@ import { ITransport, ITransportEventMap } from "./ITransport"; -export class WebTransportTransport implements ITransport { +export class H3TransportTransport implements ITransport { wt: WebTransport; isOpen: boolean = false; constructor(public events: ITransportEventMap) {} - public send(data: ArrayBuffer | Array): void { - if (data instanceof ArrayBuffer) { - // this.ws.send(data); - - } else if (Array.isArray(data)) { - // this.ws.send((new Uint8Array(data)).buffer); - } - } - public connect(url: string) { this.wt = new WebTransport(url); @@ -36,6 +27,24 @@ export class WebTransportTransport implements ITransport { // this.wt.onmessage = this.events.onmessage; } + public send(data: ArrayBuffer | Array): void { + if (data instanceof ArrayBuffer) { + // this.ws.send(data); + + } else if (Array.isArray(data)) { + // this.ws.send((new Uint8Array(data)).buffer); + } + } + + public sendUnreliable(data: ArrayBuffer | Array): void { + if (data instanceof ArrayBuffer) { + // this.ws.send(data); + + } else if (Array.isArray(data)) { + // this.ws.send((new Uint8Array(data)).buffer); + } + } + public close(code?: number, reason?: string) { this.wt.close({ closeCode: code, reason: reason }); } diff --git a/src/transport/ITransport.ts b/src/transport/ITransport.ts index 5f2303e..7080901 100644 --- a/src/transport/ITransport.ts +++ b/src/transport/ITransport.ts @@ -12,6 +12,7 @@ export interface ITransportConstructor { export interface ITransport { isOpen: boolean; send(data: ArrayBuffer | Array): void; + sendUnreliable(data: ArrayBuffer | Array): void; connect(url: string): void; close(code?: number, reason?: string): void; } diff --git a/src/transport/WebSocketTransport.ts b/src/transport/WebSocketTransport.ts index 67113b8..274df79 100644 --- a/src/transport/WebSocketTransport.ts +++ b/src/transport/WebSocketTransport.ts @@ -18,6 +18,10 @@ export class WebSocketTransport implements ITransport { } } + public sendUnreliable(data: ArrayBuffer | Array): void { + throw new Error("WebSocket does not support unreliable messages"); + } + public connect(url: string) { this.ws = new WebSocket(url, this.protocols); this.ws.binaryType = 'arraybuffer'; From f6075704f15ef9f83eaf512370e8e960411ed252 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Thu, 25 Jan 2024 18:16:02 -0300 Subject: [PATCH 05/38] H3Transport: pass serverCertificateHashes if fingerprint has been provided --- src/transport/H3Transport.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/transport/H3Transport.ts b/src/transport/H3Transport.ts index 83ffbc5..483f8f3 100644 --- a/src/transport/H3Transport.ts +++ b/src/transport/H3Transport.ts @@ -6,8 +6,18 @@ export class H3TransportTransport implements ITransport { constructor(public events: ITransportEventMap) {} - public connect(url: string) { - this.wt = new WebTransport(url); + public connect(url: string, fingerprint?: number[]) { + const options = fingerprint && ({ + // requireUnreliable: true, + // congestionControl: "default", // "low-latency" || "throughput" + + serverCertificateHashes: [{ + algorithm: 'sha-256', + value: new Uint8Array(fingerprint).buffer + }] + }) || undefined; + + this.wt = new WebTransport(url, options); this.wt.ready.then((e) => { this.isOpen = true; From bede1518a92014554843bb24994ffb9832c10af9 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Mon, 5 Feb 2024 08:48:29 -0300 Subject: [PATCH 06/38] wip H3Transport --- dist/index.html | 2 +- package-lock.json | 14 ++++---- package.json | 2 +- src/Client.ts | 14 +++++--- src/Connection.ts | 5 +-- src/Room.ts | 15 ++++++-- src/transport/H3Transport.ts | 68 +++++++++++++++++++++++++----------- src/transport/ITransport.ts | 2 +- 8 files changed, 81 insertions(+), 41 deletions(-) diff --git a/dist/index.html b/dist/index.html index 4e58b91..55029df 100644 --- a/dist/index.html +++ b/dist/index.html @@ -11,7 +11,7 @@ Messages
- Endpoint:
+ Endpoint:
Room name:
Send data: diff --git a/package-lock.json b/package-lock.json index 5c41f7d..7c790c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "colyseus.js", - "version": "0.15.13", + "version": "0.15.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "colyseus.js", - "version": "0.15.13", + "version": "0.15.15", "license": "MIT", "dependencies": { "@colyseus/schema": "^2.0.4", @@ -35,7 +35,7 @@ "ts-loader": "^6.2.1", "ts-node": "^6.0.3", "tslint": "^5.9.1", - "typescript": "^4.3.5" + "typescript": "^5.3.3" }, "engines": { "node": ">= 12.x" @@ -6234,16 +6234,16 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/util-deprecate": { diff --git a/package.json b/package.json index 3f5b030..5121617 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,6 @@ "ts-loader": "^6.2.1", "ts-node": "^6.0.3", "tslint": "^5.9.1", - "typescript": "^4.3.5" + "typescript": "^5.3.3" } } diff --git a/src/Client.ts b/src/Client.ts index 8896d95..f9e7437 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -130,7 +130,7 @@ export class Client { } const targetRoom = reuseRoomInstance || room; - room.connect(this.buildEndpoint(response.room, options), response.devMode && (async () => { + room.connect(this.buildEndpoint(response.room, options, response.protocol), response.devMode && (async () => { console.info(`[Colyseus devMode]: ${String.fromCodePoint(0x1F504)} Re-establishing connection with room id '${room.roomId}'...`); // 🔄 let retryCount = 0; @@ -155,7 +155,7 @@ export class Client { }; setTimeout(retryReconnection, 2000); - }), targetRoom, response.protocol); + }), targetRoom, response); return new Promise((resolve, reject) => { const onError = (code, message) => reject(new ServerError(code, message)); @@ -202,7 +202,7 @@ export class Client { return new Room(roomName, rootSchema); } - protected buildEndpoint(room: any, options: any = {}) { + protected buildEndpoint(room: any, options: any = {}, protocol: string = "ws") { const params = []; // append provided options @@ -213,9 +213,13 @@ export class Client { params.push(`${name}=${options[name]}`); } + if (protocol === "h3") { + protocol = "http"; + } + let endpoint = (this.settings.secure) - ? "wss://" - : "ws://" + ? `${protocol}s://` + : `${protocol}://`; if (room.publicAddress) { endpoint += `${room.publicAddress}`; diff --git a/src/Connection.ts b/src/Connection.ts index f694f13..81f802a 100644 --- a/src/Connection.ts +++ b/src/Connection.ts @@ -10,6 +10,7 @@ export class Connection implements ITransport { switch (protocol) { case "h3": this.transport = new H3TransportTransport(this.events); + break; default: this.transport = new WebSocketTransport(this.events); @@ -17,8 +18,8 @@ export class Connection implements ITransport { } } - connect(url: string): void { - this.transport.connect(url); + connect(url: string, options?: any): void { + this.transport.connect.call(this.transport, url, options); } send(data: ArrayBuffer | Array): void { diff --git a/src/Room.ts b/src/Room.ts index 3245812..00e639c 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -66,9 +66,9 @@ export class Room { endpoint: string, devModeCloseCallback?: () => void, room: Room = this, // when reconnecting on devMode, re-use previous room intance for handling events. - protocol?: string, + options?: any, ) { - const connection = new Connection(protocol); + const connection = new Connection(options.protocol); room.connection = connection; connection.events.onmessage = Room.prototype.onMessageCallback.bind(room); @@ -89,7 +89,16 @@ export class Room { console.warn?.(`Room, onError (${e.code}): ${e.reason}`); room.onError.invoke(e.code, e.reason); }; - connection.connect(endpoint); + + // FIXME: refactor this. + if (options.protocol === "h3") { + const url = new URL(endpoint); + connection.connect(url.origin, options); + + } else { + connection.connect(endpoint); + } + } public leave(consented: boolean = true): Promise { diff --git a/src/transport/H3Transport.ts b/src/transport/H3Transport.ts index 483f8f3..31ada17 100644 --- a/src/transport/H3Transport.ts +++ b/src/transport/H3Transport.ts @@ -1,62 +1,88 @@ import { ITransport, ITransportEventMap } from "./ITransport"; +import { encode } from '@colyseus/schema'; export class H3TransportTransport implements ITransport { wt: WebTransport; isOpen: boolean = false; - constructor(public events: ITransportEventMap) {} + reader: ReadableStreamDefaultReader; + writer: WritableStreamDefaultWriter; - public connect(url: string, fingerprint?: number[]) { - const options = fingerprint && ({ + unreliableReader: ReadableStreamDefaultReader; + unreliableWriter: WritableStreamDefaultWriter; + + constructor(public events: ITransportEventMap) { } + + public connect(url: string, options: any = {}) { + const wtOpts = options.fingerprint && ({ // requireUnreliable: true, // congestionControl: "default", // "low-latency" || "throughput" serverCertificateHashes: [{ algorithm: 'sha-256', - value: new Uint8Array(fingerprint).buffer + value: new Uint8Array(options.fingerprint).buffer }] }) || undefined; - this.wt = new WebTransport(url, options); + this.wt = new WebTransport(url, wtOpts); this.wt.ready.then((e) => { + console.log("WebTransport ready!", e) this.isOpen = true; - this.events.onopen(e); + + this.unreliableReader = this.wt.datagrams.readable.getReader(); + this.unreliableWriter = this.wt.datagrams.writable.getWriter(); + + const incomingBidi = this.wt.incomingBidirectionalStreams.getReader(); + incomingBidi.read().then((stream) => { + this.reader = stream.value.readable.getReader(); + this.writer = stream.value.writable.getWriter(); + + // immediately write room/sessionId for establishing the room connection + this.sendSeatReservation(options.room.roomId, options.sessionId); + }).catch((e) => { + console.error("failed to read incoming stream", e); + console.error("TODO: close the connection"); + }); + + // this.events.onopen(e); }).catch((e: WebTransportCloseInfo) => { - this.events.onerror(e); - this.events.onclose({ code: e.closeCode, reason: e.reason }); + // this.events.onerror(e); + // this.events.onclose({ code: e.closeCode, reason: e.reason }); + console.log("WebTransport not ready!", e) }); this.wt.closed.then((e: WebTransportCloseInfo) => { + console.log("WebTransport closed w/ success", e) this.events.onclose({ code: e.closeCode, reason: e.reason }); + }).catch((e: WebTransportCloseInfo) => { + console.log("WebTransport closed w/ error", e) this.events.onerror(e); this.events.onclose({ code: e.closeCode, reason: e.reason }); }); - // this.wt.onmessage = this.events.onmessage; } public send(data: ArrayBuffer | Array): void { - if (data instanceof ArrayBuffer) { - // this.ws.send(data); - - } else if (Array.isArray(data)) { - // this.ws.send((new Uint8Array(data)).buffer); - } + this.writer.write(data); } public sendUnreliable(data: ArrayBuffer | Array): void { - if (data instanceof ArrayBuffer) { - // this.ws.send(data); - - } else if (Array.isArray(data)) { - // this.ws.send((new Uint8Array(data)).buffer); - } + this.unreliableWriter.write(data); } public close(code?: number, reason?: string) { this.wt.close({ closeCode: code, reason: reason }); } + protected sendSeatReservation (roomId: string, sessionId: string) { + const bytes: number[] = []; + + encode.string(bytes, roomId); + encode.string(bytes, sessionId); + + this.writer.write(new Uint8Array(bytes).buffer); + } + } diff --git a/src/transport/ITransport.ts b/src/transport/ITransport.ts index 7080901..1da3235 100644 --- a/src/transport/ITransport.ts +++ b/src/transport/ITransport.ts @@ -13,6 +13,6 @@ export interface ITransport { isOpen: boolean; send(data: ArrayBuffer | Array): void; sendUnreliable(data: ArrayBuffer | Array): void; - connect(url: string): void; + connect(url: string, options?: any): void; close(code?: number, reason?: string): void; } From cfd482b7784f98d969fd47896f02b76fd0185344 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Wed, 7 Feb 2024 23:28:09 -0300 Subject: [PATCH 07/38] sending and receiving messages --- src/transport/H3Transport.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/transport/H3Transport.ts b/src/transport/H3Transport.ts index 31ada17..6e558a7 100644 --- a/src/transport/H3Transport.ts +++ b/src/transport/H3Transport.ts @@ -40,6 +40,10 @@ export class H3TransportTransport implements ITransport { // immediately write room/sessionId for establishing the room connection this.sendSeatReservation(options.room.roomId, options.sessionId); + + // start reading incoming data + this.readIncomingData(); + }).catch((e) => { console.error("failed to read incoming stream", e); console.error("TODO: close the connection"); @@ -65,7 +69,12 @@ export class H3TransportTransport implements ITransport { } public send(data: ArrayBuffer | Array): void { - this.writer.write(data); + if (data instanceof ArrayBuffer) { + this.writer.write(data); + + } else if (Array.isArray(data)) { + this.writer.write(new Uint8Array(data)); + } } public sendUnreliable(data: ArrayBuffer | Array): void { @@ -76,6 +85,16 @@ export class H3TransportTransport implements ITransport { this.wt.close({ closeCode: code, reason: reason }); } + protected async readIncomingData() { + while (true) { + const { value, done } = await this.reader.read(); + if (done) { break; } + + // value is a Uint8Array. + this.events.onmessage({ data: value.buffer }); + } + } + protected sendSeatReservation (roomId: string, sessionId: string) { const bytes: number[] = []; From f4f9a0cae7359da062d457b3bf9e33f44cdc6194 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Mon, 26 Feb 2024 11:20:22 -0300 Subject: [PATCH 08/38] experimenting --- dist/index.html | 35 +++++++++++++++++++++++++++++++---- src/Room.ts | 26 ++++++++++++++++++++++++++ src/transport/H3Transport.ts | 10 ++++++++-- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/dist/index.html b/dist/index.html index 55029df..14365b7 100644 --- a/dist/index.html +++ b/dist/index.html @@ -42,7 +42,28 @@ // console.log("received message:", type, "=>", message); // }); - room.onMessage("onJoin", () => {}); + room.state.players.onAdd(function(player, sessionId) { + console.log("ADD PLAYER", player); + + var el = document.createElement("div"); + el.style.display = "block"; + el.style.position = "absolute"; + el.style.width = "10px"; + el.style.height = "10px"; + el.style.backgroundColor = "red"; + // el.style.left = player.x + "px"; + // el.style.top = player.y + "px"; + document.body.appendChild(el); + + player.onChange(function() { + el.style.left = player.x + "px"; + el.style.top = player.y + "px"; + }); + }); + + room.onMessage("*", (type, message) => { + console.log("onMessage:", { type, message }); + }); room.onLeave(function() { console.log("LEFT ROOM", arguments); @@ -52,9 +73,15 @@ console.log("on error:", {code, message}); }); - // room.onStateChange(function(state) { - // console.log("state change: ", state.toJSON()); - // }); + document.addEventListener("mousemove", function (event) { + console.log("move", { x: event.clientX, y: event.clientY }); + // room.sendUnreliable("move", { x: event.clientX, y: event.clientY }); + room.send("move", { x: event.clientX, y: event.clientY }); + }); + + room.onStateChange(function(state) { + console.log("state change: ", state.toJSON()); + }); } function join () { diff --git a/src/Room.ts b/src/Room.ts index 00e639c..d0d2a05 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -163,6 +163,31 @@ export class Room { this.connection.send(arr.buffer); } + public sendUnreliable(type: string | number, message?: any): void { + const initialBytes: number[] = [Protocol.ROOM_DATA]; + + if (typeof(type) === "string") { + encode.string(initialBytes, type); + + } else { + encode.number(initialBytes, type); + } + + let arr: Uint8Array; + + if (message !== undefined) { + const encoded = msgpack.encode(message); + arr = new Uint8Array(initialBytes.length + encoded.byteLength); + arr.set(new Uint8Array(initialBytes), 0); + arr.set(new Uint8Array(encoded), initialBytes.length); + + } else { + arr = new Uint8Array(initialBytes); + } + + this.connection.sendUnreliable(arr.buffer); + } + public sendBytes(type: string | number, bytes: number[] | ArrayBufferLike) { const initialBytes: number[] = [Protocol.ROOM_DATA_BYTES]; @@ -196,6 +221,7 @@ export class Room { protected onMessageCallback(event: MessageEvent) { const bytes = Array.from(new Uint8Array(event.data)) const code = bytes[0]; + console.log("onMessageCallback", bytes); if (code === Protocol.JOIN_ROOM) { let offset = 1; diff --git a/src/transport/H3Transport.ts b/src/transport/H3Transport.ts index 6e558a7..85b0ee3 100644 --- a/src/transport/H3Transport.ts +++ b/src/transport/H3Transport.ts @@ -54,6 +54,7 @@ export class H3TransportTransport implements ITransport { // this.events.onerror(e); // this.events.onclose({ code: e.closeCode, reason: e.reason }); console.log("WebTransport not ready!", e) + this._close(); }); this.wt.closed.then((e: WebTransportCloseInfo) => { @@ -64,8 +65,9 @@ export class H3TransportTransport implements ITransport { console.log("WebTransport closed w/ error", e) this.events.onerror(e); this.events.onclose({ code: e.closeCode, reason: e.reason }); + }).finally(() => { + this._close(); }); - } public send(data: ArrayBuffer | Array): void { @@ -86,7 +88,7 @@ export class H3TransportTransport implements ITransport { } protected async readIncomingData() { - while (true) { + while (this.isOpen) { const { value, done } = await this.reader.read(); if (done) { break; } @@ -104,4 +106,8 @@ export class H3TransportTransport implements ITransport { this.writer.write(new Uint8Array(bytes).buffer); } + protected _close() { + this.isOpen = false; + } + } From 64d110a8c01389ed96f40d0a4d5917f0a33c5f2d Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Mon, 4 Mar 2024 21:25:55 -0300 Subject: [PATCH 09/38] avoid errors when client leave the room --- dist/index.html | 23 +++++++++++++++++------ src/transport/H3Transport.ts | 9 ++++++++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/dist/index.html b/dist/index.html index 14365b7..5618ccd 100644 --- a/dist/index.html +++ b/dist/index.html @@ -42,10 +42,13 @@ // console.log("received message:", type, "=>", message); // }); + + // listen to player "add" events room.state.players.onAdd(function(player, sessionId) { console.log("ADD PLAYER", player); var el = document.createElement("div"); + el.id = "player-" + sessionId; el.style.display = "block"; el.style.position = "absolute"; el.style.width = "10px"; @@ -61,24 +64,32 @@ }); }); + // listen to player "remove" events + room.state.players.onRemove(function(player, sessionId) { + var el = document.getElementById("player-" + sessionId); + el.parentNode.removeChild(el); + }); + room.onMessage("*", (type, message) => { console.log("onMessage:", { type, message }); }); + var onmousemove = function (event) { + room.sendUnreliable("move", { x: event.clientX, y: event.clientY }); + // room.send("move", { x: event.clientX, y: event.clientY }); + }; + + document.addEventListener("mousemove", onmousemove); + room.onLeave(function() { console.log("LEFT ROOM", arguments); + document.removeEventListener("mousemove", onmousemove); }); room.onError(function(code, message) { console.log("on error:", {code, message}); }); - document.addEventListener("mousemove", function (event) { - console.log("move", { x: event.clientX, y: event.clientY }); - // room.sendUnreliable("move", { x: event.clientX, y: event.clientY }); - room.send("move", { x: event.clientX, y: event.clientY }); - }); - room.onStateChange(function(state) { console.log("state change: ", state.toJSON()); }); diff --git a/src/transport/H3Transport.ts b/src/transport/H3Transport.ts index 85b0ee3..3c8d802 100644 --- a/src/transport/H3Transport.ts +++ b/src/transport/H3Transport.ts @@ -71,6 +71,7 @@ export class H3TransportTransport implements ITransport { } public send(data: ArrayBuffer | Array): void { + console.log(".send()", data); if (data instanceof ArrayBuffer) { this.writer.write(data); @@ -80,11 +81,16 @@ export class H3TransportTransport implements ITransport { } public sendUnreliable(data: ArrayBuffer | Array): void { + console.log(".sendUnreliable()", data); this.unreliableWriter.write(data); } public close(code?: number, reason?: string) { - this.wt.close({ closeCode: code, reason: reason }); + try { + this.wt.close({ closeCode: code, reason: reason }); + } catch (e) { + console.error(e); + } } protected async readIncomingData() { @@ -107,6 +113,7 @@ export class H3TransportTransport implements ITransport { } protected _close() { + console.log("_close() !!"); this.isOpen = false; } From d903031e8a551be4a4f635e2ac98dd62b147c5a2 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Tue, 5 Mar 2024 21:30:49 -0300 Subject: [PATCH 10/38] allow to reconnect using H3Transport --- dist/index.html | 1 + src/transport/H3Transport.ts | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/dist/index.html b/dist/index.html index 5618ccd..6542935 100644 --- a/dist/index.html +++ b/dist/index.html @@ -49,6 +49,7 @@ var el = document.createElement("div"); el.id = "player-" + sessionId; + el.style.pointerEvents = "none"; el.style.display = "block"; el.style.position = "absolute"; el.style.width = "10px"; diff --git a/src/transport/H3Transport.ts b/src/transport/H3Transport.ts index 3c8d802..455de4f 100644 --- a/src/transport/H3Transport.ts +++ b/src/transport/H3Transport.ts @@ -39,7 +39,7 @@ export class H3TransportTransport implements ITransport { this.writer = stream.value.writable.getWriter(); // immediately write room/sessionId for establishing the room connection - this.sendSeatReservation(options.room.roomId, options.sessionId); + this.sendSeatReservation(options.room.roomId, options.sessionId, options.reconnectionToken); // start reading incoming data this.readIncomingData(); @@ -103,12 +103,16 @@ export class H3TransportTransport implements ITransport { } } - protected sendSeatReservation (roomId: string, sessionId: string) { + protected sendSeatReservation (roomId: string, sessionId: string, reconnectionToken?: string) { const bytes: number[] = []; encode.string(bytes, roomId); encode.string(bytes, sessionId); + if (reconnectionToken) { + encode.string(bytes, reconnectionToken); + } + this.writer.write(new Uint8Array(bytes).buffer); } From 4a5556a6f66ba7dade5c6f92df8278a319cd61fb Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Mon, 18 Mar 2024 14:30:01 -0300 Subject: [PATCH 11/38] wip: unreliable --- src/transport/H3Transport.ts | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/transport/H3Transport.ts b/src/transport/H3Transport.ts index 455de4f..c96e1db 100644 --- a/src/transport/H3Transport.ts +++ b/src/transport/H3Transport.ts @@ -43,6 +43,7 @@ export class H3TransportTransport implements ITransport { // start reading incoming data this.readIncomingData(); + this.readIncomingUnreliableData(); }).catch((e) => { console.error("failed to read incoming stream", e); @@ -94,12 +95,38 @@ export class H3TransportTransport implements ITransport { } protected async readIncomingData() { + let result: ReadableStreamReadResult; + + while (this.isOpen) { + try { + result = await this.reader.read(); + } catch (e) { + console.error("failed to read incoming data", e); + break; + } + + if (result.done) { break; } + + // value is a Uint8Array. + this.events.onmessage({ data: result.value.buffer }); + } + } + + protected async readIncomingUnreliableData() { + let result: ReadableStreamReadResult; + while (this.isOpen) { - const { value, done } = await this.reader.read(); - if (done) { break; } + try { + result = await this.unreliableReader.read(); + } catch (e) { + console.error("failed to read incoming data", e); + break; + } + + if (result.done) { break; } // value is a Uint8Array. - this.events.onmessage({ data: value.buffer }); + this.events.onmessage({ data: result.value.buffer }); } } From 81ba87f1c79247523ef26636d671d5a108a7d689 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Tue, 11 Jun 2024 19:52:22 -0300 Subject: [PATCH 12/38] use @colyseus/schema 3.0. use msgpackr package instead of hardcoded notepack.io --- package-lock.json | 300 +++++++++---- package.json | 5 +- src/Protocol.ts | 66 +-- src/Room.ts | 161 +++---- src/legacy.ts | 9 +- src/msgpack/index.ts | 668 ----------------------------- src/serializer/SchemaSerializer.ts | 22 +- src/serializer/Serializer.ts | 8 +- 8 files changed, 320 insertions(+), 919 deletions(-) delete mode 100644 src/msgpack/index.ts diff --git a/package-lock.json b/package-lock.json index ae1968b..a413a09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,17 @@ { "name": "colyseus.js", - "version": "0.15.19", + "version": "0.16.0-preview.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "colyseus.js", - "version": "0.15.19", + "version": "0.16.0-preview.0", "license": "MIT", "dependencies": { - "@colyseus/schema": "^2.0.4", + "@colyseus/schema": "^3.0.0-alpha.0", "httpie": "^2.0.0-next.13", + "msgpackr": "^1.10.2", "tslib": "^2.1.0", "ws": "^8.13.0" }, @@ -45,48 +46,122 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@colyseus/schema": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-2.0.9.tgz", - "integrity": "sha512-YuIs9oPuVAFAvjEtNFLDdZ4yiRi3d0DfGkeDDrMKFqaI8G4G/MnVb+zHIWN21QeSru+urzqZnZoVV+gHKHNK0w==", + "version": "3.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.3.tgz", + "integrity": "sha512-55U1Ye45Tq4fsDIHBW/OLwqt+M5Ap1cEoI7BuGKCXo5zamW1W8SG4lK9jv64vs0HGwwUZCclCjw9TrG98nWPww==", "bin": { "schema-codegen": "bin/schema-codegen" } }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", + "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", + "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", + "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", + "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", + "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", + "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/plugin-alias": { "version": "3.1.9", "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-3.1.9.tgz", @@ -208,10 +283,13 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.2.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz", - "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==", - "dev": true + "version": "20.14.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz", + "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/resolve": { "version": "1.17.1", @@ -315,12 +393,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -470,6 +548,15 @@ "node": ">=0.10.0" } }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -537,9 +624,9 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "engines": { "node": ">=6" @@ -574,9 +661,9 @@ "dev": true }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -592,9 +679,9 @@ "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -606,10 +693,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-caller-file": { "version": "2.0.5", @@ -624,6 +714,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -655,18 +746,6 @@ "node": ">=4.x" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -676,6 +755,18 @@ "node": ">=4" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", @@ -706,6 +797,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "dependencies": { "once": "^1.3.0", @@ -728,12 +820,12 @@ } }, "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -867,12 +959,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -940,6 +1032,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -971,12 +1064,55 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/msgpackr": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.10.2.tgz", + "integrity": "sha512-L60rsPynBvNE+8BWipKKZ9jHcSGbtyJYIwjRq0VrIvQ08cRjntGXJYW/tmciZ2IHWIY8WEW32Qa2xbh5+SKBZA==", + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", + "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" + } + }, "node_modules/nanoid": { "version": "2.1.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==", "dev": true }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, "node_modules/node-localstorage": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-localstorage/-/node-localstorage-1.3.1.tgz", @@ -5815,6 +5951,12 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -5870,12 +6012,12 @@ } }, "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -5950,9 +6092,9 @@ "dev": true }, "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -6139,9 +6281,9 @@ } }, "node_modules/tslib": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/tslint": { "version": "5.20.1", @@ -6192,9 +6334,9 @@ } }, "node_modules/tslint/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "bin": { "semver": "bin/semver" @@ -6246,6 +6388,12 @@ "node": ">=4.2.0" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -6320,9 +6468,9 @@ } }, "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", "engines": { "node": ">=10.0.0" }, diff --git a/package.json b/package.json index 9b505d5..2b430c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.22", + "version": "0.16.0-preview.0", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", @@ -58,8 +58,9 @@ "node": ">= 12.x" }, "dependencies": { - "@colyseus/schema": "^2.0.4", + "@colyseus/schema": "^3.0.0-alpha.0", "httpie": "^2.0.0-next.13", + "msgpackr": "^1.10.2", "tslib": "^2.1.0", "ws": "^8.13.0" }, diff --git a/src/Protocol.ts b/src/Protocol.ts index 49dd0c5..cb16268 100644 --- a/src/Protocol.ts +++ b/src/Protocol.ts @@ -1,5 +1,6 @@ -// Use codes between 0~127 for lesser throughput (1 byte) +import type { Iterator } from "@colyseus/schema"; +// Use codes between 0~127 for lesser throughput (1 byte) export enum Protocol { // Room-related (10~19) HANDSHAKE = 9, @@ -23,66 +24,3 @@ export enum ErrorCode { AUTH_FAILED = 4215, APPLICATION_ERROR = 4216, } - -export function utf8Read(view: number[], offset: number) { - const length = view[offset++]; - - var string = '', chr = 0; - for (var i = offset, end = offset + length; i < end; i++) { - var byte = view[i]; - if ((byte & 0x80) === 0x00) { - string += String.fromCharCode(byte); - continue; - } - if ((byte & 0xe0) === 0xc0) { - string += String.fromCharCode( - ((byte & 0x1f) << 6) | - (view[++i] & 0x3f) - ); - continue; - } - if ((byte & 0xf0) === 0xe0) { - string += String.fromCharCode( - ((byte & 0x0f) << 12) | - ((view[++i] & 0x3f) << 6) | - ((view[++i] & 0x3f) << 0) - ); - continue; - } - if ((byte & 0xf8) === 0xf0) { - chr = ((byte & 0x07) << 18) | - ((view[++i] & 0x3f) << 12) | - ((view[++i] & 0x3f) << 6) | - ((view[++i] & 0x3f) << 0); - if (chr >= 0x010000) { // surrogate pair - chr -= 0x010000; - string += String.fromCharCode((chr >>> 10) + 0xD800, (chr & 0x3FF) + 0xDC00); - } else { - string += String.fromCharCode(chr); - } - continue; - } - throw new Error('Invalid byte ' + byte.toString(16)); - } - return string; -} - -// Faster for short strings than Buffer.byteLength -export function utf8Length(str: string = '') { - let c = 0; - let length = 0; - for (let i = 0, l = str.length; i < l; i++) { - c = str.charCodeAt(i); - if (c < 0x80) { - length += 1; - } else if (c < 0x800) { - length += 2; - } else if (c < 0xd800 || c >= 0xe000) { - length += 3; - } else { - i++; - length += 4; - } - } - return length + 1; -} diff --git a/src/Room.ts b/src/Room.ts index 2e49f92..a04e857 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -1,18 +1,23 @@ -import * as msgpack from './msgpack'; - import { Connection } from './Connection'; -import { Protocol, utf8Length, utf8Read } from './Protocol'; -import { getSerializer, Serializer } from './serializer/Serializer'; +import { Protocol } from './Protocol'; +import { BufferLike, getSerializer, Serializer } from './serializer/Serializer'; // The unused imports here are important for better `.d.ts` file generation // (Later merged with `dts-bundle-generator`) import { createNanoEvents } from './core/nanoevents'; import { createSignal } from './core/signal'; -import { Context, decode, encode, Schema } from '@colyseus/schema'; +import { decode, encode, Iterator } from '@colyseus/schema'; import { SchemaConstructor, SchemaSerializer } from './serializer/SchemaSerializer'; import { CloseCode } from './errors/ServerError'; +import msgpackr from "msgpackr"; + +type ByteArrayAllocator = new (length: number) => Uint8Array | Buffer; +const ByteArrayAllocate: ByteArrayAllocator = (typeof Buffer !== 'undefined') + ? function (length: number) { return Buffer.allocUnsafeSlow(length) as any } as any + : Uint8Array; + export interface RoomAvailable { name: string; roomId: string; @@ -45,10 +50,17 @@ export class Room { protected onMessageHandlers = createNanoEvents(); + protected packr: msgpackr.Packr; + protected sendBuffer: Buffer | Uint8Array = new ByteArrayAllocate(8192); + constructor(name: string, rootSchema?: SchemaConstructor) { this.roomId = null; this.name = name; + this.packr = new msgpackr.Packr(); + // @ts-ignore + this.packr.useBuffer(this.sendBuffer); + if (rootSchema) { this.serializer = new (getSerializer("schema")); this.rootSchema = rootSchema; @@ -109,66 +121,44 @@ export class Room { }); } - public onMessage( - type: "*", - callback: (type: string | number | Schema, message: T) => void - ) - public onMessage any))>( - type: T, - callback: (message: InstanceType) => void - ) - public onMessage( - type: string | number, - callback: (message: T) => void - ) - public onMessage( - type: '*' | string | number | typeof Schema, - callback: (...args: any[]) => void - ) { + public onMessage(type: "*", callback: (type: string | number, message: T) => void) + public onMessage(type: string | number, callback: (message: T) => void) + public onMessage(type: '*' | string | number, callback: (...args: any[]) => void) { return this.onMessageHandlers.on(this.getMessageHandlerKey(type), callback); } public send(type: string | number, message?: any): void { - const initialBytes: number[] = [Protocol.ROOM_DATA]; + const it: Iterator = { offset: 0 }; + this.sendBuffer[it.offset++] = Protocol.ROOM_DATA; if (typeof(type) === "string") { - encode.string(initialBytes, type); + encode.string(this.sendBuffer, type, it); } else { - encode.number(initialBytes, type); + encode.number(this.sendBuffer, type, it); } - let arr: Uint8Array; + const data = (message !== undefined) + // @ts-ignore + ? this.packr.pack(message, 2048 + it.offset) // PR to fix TypeScript types https://github.com/kriszyp/msgpackr/pull/137 + // 2048 = RESERVE_START_SPACE + : this.sendBuffer.subarray(0, it.offset); - if (message !== undefined) { - const encoded = msgpack.encode(message); - arr = new Uint8Array(initialBytes.length + encoded.byteLength); - arr.set(new Uint8Array(initialBytes), 0); - arr.set(new Uint8Array(encoded), initialBytes.length); - - } else { - arr = new Uint8Array(initialBytes); - } - - this.connection.send(arr.buffer); + this.connection.send(data); } - public sendBytes(type: string | number, bytes: number[] | ArrayBufferLike) { - const initialBytes: number[] = [Protocol.ROOM_DATA_BYTES]; + public sendBytes(type: string | number, bytes: Uint8Array) { + const it: Iterator = { offset: 0 }; + this.sendBuffer[it.offset++] = Protocol.ROOM_DATA_BYTES; if (typeof(type) === "string") { - encode.string(initialBytes, type); + encode.string(this.sendBuffer, type, it); } else { - encode.number(initialBytes, type); + encode.number(this.sendBuffer, type, it); } - let arr: Uint8Array; - arr = new Uint8Array(initialBytes.length + ((bytes as ArrayBufferLike).byteLength || (bytes as number[]).length)); - arr.set(new Uint8Array(initialBytes), 0); - arr.set(new Uint8Array(bytes), initialBytes.length); - - this.connection.send(arr.buffer); + this.connection.send(Buffer.concat([this.sendBuffer.subarray(0, it.offset), bytes])); } public get state (): State { @@ -184,26 +174,23 @@ export class Room { } protected onMessageCallback(event: MessageEvent) { - const bytes = Array.from(new Uint8Array(event.data)) - const code = bytes[0]; - - if (code === Protocol.JOIN_ROOM) { - let offset = 1; + const buffer = new Uint8Array(event.data); + const code = buffer[0]; - const reconnectionToken = utf8Read(bytes, offset); - offset += utf8Length(reconnectionToken); + const it: Iterator = { offset: 1 }; - this.serializerId = utf8Read(bytes, offset); - offset += utf8Length(this.serializerId); + if (code === Protocol.JOIN_ROOM) { + const reconnectionToken = decode.utf8Read(buffer, it, buffer[it.offset++]); + this.serializerId = decode.utf8Read(buffer, it, buffer[it.offset++]); // Instantiate serializer if not locally available. if (!this.serializer) { - const serializer = getSerializer(this.serializerId) + const serializer = getSerializer(this.serializerId); this.serializer = new serializer(); } - if (bytes.length > offset && this.serializer.handshake) { - this.serializer.handshake(bytes, { offset }); + if (buffer.length > it.offset && this.serializer.handshake) { + this.serializer.handshake(buffer, it); } this.reconnectionToken = `${this.roomId}:${reconnectionToken}`; @@ -212,47 +199,32 @@ export class Room { this.onJoin.invoke(); // acknowledge successfull JOIN_ROOM - this.connection.send([Protocol.JOIN_ROOM]); + this.sendBuffer[0] = Protocol.JOIN_ROOM; + this.connection.send(this.sendBuffer.subarray(0, 1)); } else if (code === Protocol.ERROR) { - const it: decode.Iterator = { offset: 1 }; - - const code = decode.number(bytes, it); - const message = decode.string(bytes, it); + const code = decode.number(buffer, it); + const message = decode.string(buffer, it); this.onError.invoke(code, message); } else if (code === Protocol.LEAVE_ROOM) { this.leave(); - } else if (code === Protocol.ROOM_DATA_SCHEMA) { - const it = { offset: 1 }; - - const context: Context = (this.serializer.getState() as any).constructor._context; - const type = context.get(decode.number(bytes, it)); - - const message: Schema = new (type as any)(); - message.decode(bytes, it); - - this.dispatchMessage(type, message); - } else if (code === Protocol.ROOM_STATE) { - bytes.shift(); // drop `code` byte - this.setState(bytes); + this.setState(buffer.subarray(it.offset)); } else if (code === Protocol.ROOM_STATE_PATCH) { - bytes.shift(); // drop `code` byte - this.patch(bytes); + this.patch(buffer.subarray(it.offset)); } else if (code === Protocol.ROOM_DATA) { - const it: decode.Iterator = { offset: 1 }; - - const type = (decode.stringCheck(bytes, it)) - ? decode.string(bytes, it) - : decode.number(bytes, it); + const type = (decode.stringCheck(buffer, it)) + ? decode.string(buffer, it) + : decode.number(buffer, it); - const message = (bytes.length > it.offset) - ? msgpack.decode(event.data, it.offset) + const message = (buffer.length > it.offset) + // @ts-ignore + ? msgpackr.unpack(buffer, it.offset) : undefined; this.dispatchMessage(type, message); @@ -260,25 +232,25 @@ export class Room { } else if (code === Protocol.ROOM_DATA_BYTES) { const it: decode.Iterator = { offset: 1 }; - const type = (decode.stringCheck(bytes, it)) - ? decode.string(bytes, it) - : decode.number(bytes, it); + const type = (decode.stringCheck(buffer, it)) + ? decode.string(buffer, it) + : decode.number(buffer, it); - this.dispatchMessage(type, new Uint8Array(bytes.slice(it.offset))); + this.dispatchMessage(type, buffer.slice(it.offset)); } } - protected setState(encodedState: number[]): void { + protected setState(encodedState: BufferLike): void { this.serializer.setState(encodedState); this.onStateChange.invoke(this.serializer.getState()); } - protected patch(binaryPatch: number[]) { + protected patch(binaryPatch: BufferLike) { this.serializer.patch(binaryPatch); this.onStateChange.invoke(this.serializer.getState()); } - private dispatchMessage(type: string | number | typeof Schema, message: any) { + private dispatchMessage(type: string | number, message: any) { const messageType = this.getMessageHandlerKey(type); if (this.onMessageHandlers.events[messageType]) { @@ -298,11 +270,8 @@ export class Room { } } - private getMessageHandlerKey(type: string | number | typeof Schema): string { + private getMessageHandlerKey(type: string | number): string { switch (typeof(type)) { - // typeof Schema - case "function": return `$${(type as typeof Schema)._typeid}`; - // string case "string": return type; diff --git a/src/legacy.ts b/src/legacy.ts index 182b0c6..06a746f 100644 --- a/src/legacy.ts +++ b/src/legacy.ts @@ -11,6 +11,13 @@ if (!ArrayBuffer.isView) { }; } +// Cocos Creator does not provide "FormData" +// Define a dummy implementation so it doesn't crash +if (typeof(FormData) === "undefined") { + // @ts-ignore + global['FormData'] = class {}; +} + // Define globalThis if not available. // https://github.com/colyseus/colyseus.js/issues/86 if ( @@ -19,4 +26,4 @@ if ( ) { // @ts-ignore window['globalThis'] = window; -} \ No newline at end of file +} diff --git a/src/msgpack/index.ts b/src/msgpack/index.ts deleted file mode 100644 index 1d6f892..0000000 --- a/src/msgpack/index.ts +++ /dev/null @@ -1,668 +0,0 @@ -/** - * Copyright (c) 2014 Ion Drive Software Ltd. - * https://github.com/darrachequesne/notepack/ - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * Patch for Colyseus: - * ------------------- - * notepack.io@3.0.1 - * - * added `offset` on Decoder constructor, for messages arriving with a code - * before actual msgpack data - */ - -// -// DECODER -// - -function Decoder(buffer, offset) { - this._offset = offset; - if (buffer instanceof ArrayBuffer) { - this._buffer = buffer; - this._view = new DataView(this._buffer); - } else if (ArrayBuffer.isView(buffer)) { - this._buffer = buffer.buffer; - this._view = new DataView(this._buffer, buffer.byteOffset, buffer.byteLength); - } else { - throw new Error('Invalid argument'); - } -} - -function utf8Read(view, offset, length) { - var string = '', chr = 0; - for (var i = offset, end = offset + length; i < end; i++) { - var byte = view.getUint8(i); - if ((byte & 0x80) === 0x00) { - string += String.fromCharCode(byte); - continue; - } - if ((byte & 0xe0) === 0xc0) { - string += String.fromCharCode( - ((byte & 0x1f) << 6) | - (view.getUint8(++i) & 0x3f) - ); - continue; - } - if ((byte & 0xf0) === 0xe0) { - string += String.fromCharCode( - ((byte & 0x0f) << 12) | - ((view.getUint8(++i) & 0x3f) << 6) | - ((view.getUint8(++i) & 0x3f) << 0) - ); - continue; - } - if ((byte & 0xf8) === 0xf0) { - chr = ((byte & 0x07) << 18) | - ((view.getUint8(++i) & 0x3f) << 12) | - ((view.getUint8(++i) & 0x3f) << 6) | - ((view.getUint8(++i) & 0x3f) << 0); - if (chr >= 0x010000) { // surrogate pair - chr -= 0x010000; - string += String.fromCharCode((chr >>> 10) + 0xD800, (chr & 0x3FF) + 0xDC00); - } else { - string += String.fromCharCode(chr); - } - continue; - } - throw new Error('Invalid byte ' + byte.toString(16)); - } - return string; -} - -Decoder.prototype._array = function (length) { - var value = new Array(length); - for (var i = 0; i < length; i++) { - value[i] = this._parse(); - } - return value; -}; - -Decoder.prototype._map = function (length) { - var key = '', value = {}; - for (var i = 0; i < length; i++) { - key = this._parse(); - value[key] = this._parse(); - } - return value; -}; - -Decoder.prototype._str = function (length) { - var value = utf8Read(this._view, this._offset, length); - this._offset += length; - return value; -}; - -Decoder.prototype._bin = function (length) { - var value = this._buffer.slice(this._offset, this._offset + length); - this._offset += length; - return value; -}; - -Decoder.prototype._parse = function () { - var prefix = this._view.getUint8(this._offset++); - var value, length = 0, type = 0, hi = 0, lo = 0; - - if (prefix < 0xc0) { - // positive fixint - if (prefix < 0x80) { - return prefix; - } - // fixmap - if (prefix < 0x90) { - return this._map(prefix & 0x0f); - } - // fixarray - if (prefix < 0xa0) { - return this._array(prefix & 0x0f); - } - // fixstr - return this._str(prefix & 0x1f); - } - - // negative fixint - if (prefix > 0xdf) { - return (0xff - prefix + 1) * -1; - } - - switch (prefix) { - // nil - case 0xc0: - return null; - // false - case 0xc2: - return false; - // true - case 0xc3: - return true; - - // bin - case 0xc4: - length = this._view.getUint8(this._offset); - this._offset += 1; - return this._bin(length); - case 0xc5: - length = this._view.getUint16(this._offset); - this._offset += 2; - return this._bin(length); - case 0xc6: - length = this._view.getUint32(this._offset); - this._offset += 4; - return this._bin(length); - - // ext - case 0xc7: - length = this._view.getUint8(this._offset); - type = this._view.getInt8(this._offset + 1); - this._offset += 2; - if (type === -1) { - // timestamp 96 - var ns = this._view.getUint32(this._offset); - hi = this._view.getInt32(this._offset + 4); - lo = this._view.getUint32(this._offset + 8); - this._offset += 12; - return new Date((hi * 0x100000000 + lo) * 1e3 + ns / 1e6); - } - return [type, this._bin(length)]; - case 0xc8: - length = this._view.getUint16(this._offset); - type = this._view.getInt8(this._offset + 2); - this._offset += 3; - return [type, this._bin(length)]; - case 0xc9: - length = this._view.getUint32(this._offset); - type = this._view.getInt8(this._offset + 4); - this._offset += 5; - return [type, this._bin(length)]; - - // float - case 0xca: - value = this._view.getFloat32(this._offset); - this._offset += 4; - return value; - case 0xcb: - value = this._view.getFloat64(this._offset); - this._offset += 8; - return value; - - // uint - case 0xcc: - value = this._view.getUint8(this._offset); - this._offset += 1; - return value; - case 0xcd: - value = this._view.getUint16(this._offset); - this._offset += 2; - return value; - case 0xce: - value = this._view.getUint32(this._offset); - this._offset += 4; - return value; - case 0xcf: - hi = this._view.getUint32(this._offset) * Math.pow(2, 32); - lo = this._view.getUint32(this._offset + 4); - this._offset += 8; - return hi + lo; - - // int - case 0xd0: - value = this._view.getInt8(this._offset); - this._offset += 1; - return value; - case 0xd1: - value = this._view.getInt16(this._offset); - this._offset += 2; - return value; - case 0xd2: - value = this._view.getInt32(this._offset); - this._offset += 4; - return value; - case 0xd3: - hi = this._view.getInt32(this._offset) * Math.pow(2, 32); - lo = this._view.getUint32(this._offset + 4); - this._offset += 8; - return hi + lo; - - // fixext - case 0xd4: - type = this._view.getInt8(this._offset); - this._offset += 1; - if (type === 0x00) { - // custom encoding for 'undefined' (kept for backward-compatibility) - this._offset += 1; - return void 0; - } - return [type, this._bin(1)]; - case 0xd5: - type = this._view.getInt8(this._offset); - this._offset += 1; - return [type, this._bin(2)]; - case 0xd6: - type = this._view.getInt8(this._offset); - this._offset += 1; - if (type === -1) { - // timestamp 32 - value = this._view.getUint32(this._offset); - this._offset += 4; - return new Date(value * 1e3); - } - return [type, this._bin(4)]; - case 0xd7: - type = this._view.getInt8(this._offset); - this._offset += 1; - if (type === 0x00) { - // custom date encoding (kept for backward-compatibility) - hi = this._view.getInt32(this._offset) * Math.pow(2, 32); - lo = this._view.getUint32(this._offset + 4); - this._offset += 8; - return new Date(hi + lo); - } - if (type === -1) { - // timestamp 64 - hi = this._view.getUint32(this._offset); - lo = this._view.getUint32(this._offset + 4); - this._offset += 8; - var s = (hi & 0x3) * 0x100000000 + lo; - return new Date(s * 1e3 + (hi >>> 2) / 1e6); - } - return [type, this._bin(8)]; - case 0xd8: - type = this._view.getInt8(this._offset); - this._offset += 1; - return [type, this._bin(16)]; - - // str - case 0xd9: - length = this._view.getUint8(this._offset); - this._offset += 1; - return this._str(length); - case 0xda: - length = this._view.getUint16(this._offset); - this._offset += 2; - return this._str(length); - case 0xdb: - length = this._view.getUint32(this._offset); - this._offset += 4; - return this._str(length); - - // array - case 0xdc: - length = this._view.getUint16(this._offset); - this._offset += 2; - return this._array(length); - case 0xdd: - length = this._view.getUint32(this._offset); - this._offset += 4; - return this._array(length); - - // map - case 0xde: - length = this._view.getUint16(this._offset); - this._offset += 2; - return this._map(length); - case 0xdf: - length = this._view.getUint32(this._offset); - this._offset += 4; - return this._map(length); - } - - throw new Error('Could not parse'); -}; - -function decode(buffer, offset = 0) { - var decoder = new Decoder(buffer, offset); - var value = decoder._parse(); - if (decoder._offset !== buffer.byteLength) { - throw new Error((buffer.byteLength - decoder._offset) + ' trailing bytes'); - } - return value; -} - -// -// ENCODER -// - -var TIMESTAMP32_MAX_SEC = 0x100000000 - 1; // 32-bit unsigned int -var TIMESTAMP64_MAX_SEC = 0x400000000 - 1; // 34-bit unsigned int - -function utf8Write(view, offset, str) { - var c = 0; - for (var i = 0, l = str.length; i < l; i++) { - c = str.charCodeAt(i); - if (c < 0x80) { - view.setUint8(offset++, c); - } - else if (c < 0x800) { - view.setUint8(offset++, 0xc0 | (c >> 6)); - view.setUint8(offset++, 0x80 | (c & 0x3f)); - } - else if (c < 0xd800 || c >= 0xe000) { - view.setUint8(offset++, 0xe0 | (c >> 12)); - view.setUint8(offset++, 0x80 | (c >> 6) & 0x3f); - view.setUint8(offset++, 0x80 | (c & 0x3f)); - } - else { - i++; - c = 0x10000 + (((c & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff)); - view.setUint8(offset++, 0xf0 | (c >> 18)); - view.setUint8(offset++, 0x80 | (c >> 12) & 0x3f); - view.setUint8(offset++, 0x80 | (c >> 6) & 0x3f); - view.setUint8(offset++, 0x80 | (c & 0x3f)); - } - } -} - -function utf8Length(str) { - var c = 0, length = 0; - for (var i = 0, l = str.length; i < l; i++) { - c = str.charCodeAt(i); - if (c < 0x80) { - length += 1; - } - else if (c < 0x800) { - length += 2; - } - else if (c < 0xd800 || c >= 0xe000) { - length += 3; - } - else { - i++; - length += 4; - } - } - return length; -} - -function _encode(bytes, defers, value) { - var type = typeof value, i = 0, l = 0, hi = 0, lo = 0, length = 0, size = 0; - - if (type === 'string') { - length = utf8Length(value); - - // fixstr - if (length < 0x20) { - bytes.push(length | 0xa0); - size = 1; - } - // str 8 - else if (length < 0x100) { - bytes.push(0xd9, length); - size = 2; - } - // str 16 - else if (length < 0x10000) { - bytes.push(0xda, length >> 8, length); - size = 3; - } - // str 32 - else if (length < 0x100000000) { - bytes.push(0xdb, length >> 24, length >> 16, length >> 8, length); - size = 5; - } else { - throw new Error('String too long'); - } - defers.push({ _str: value, _length: length, _offset: bytes.length }); - return size + length; - } - if (type === 'number') { - // TODO: encode to float 32? - - // float 64 - if (Math.floor(value) !== value || !isFinite(value)) { - bytes.push(0xcb); - defers.push({ _float: value, _length: 8, _offset: bytes.length }); - return 9; - } - - if (value >= 0) { - // positive fixnum - if (value < 0x80) { - bytes.push(value); - return 1; - } - // uint 8 - if (value < 0x100) { - bytes.push(0xcc, value); - return 2; - } - // uint 16 - if (value < 0x10000) { - bytes.push(0xcd, value >> 8, value); - return 3; - } - // uint 32 - if (value < 0x100000000) { - bytes.push(0xce, value >> 24, value >> 16, value >> 8, value); - return 5; - } - // uint 64 - hi = (value / Math.pow(2, 32)) >> 0; - lo = value >>> 0; - bytes.push(0xcf, hi >> 24, hi >> 16, hi >> 8, hi, lo >> 24, lo >> 16, lo >> 8, lo); - return 9; - } else { - // negative fixnum - if (value >= -0x20) { - bytes.push(value); - return 1; - } - // int 8 - if (value >= -0x80) { - bytes.push(0xd0, value); - return 2; - } - // int 16 - if (value >= -0x8000) { - bytes.push(0xd1, value >> 8, value); - return 3; - } - // int 32 - if (value >= -0x80000000) { - bytes.push(0xd2, value >> 24, value >> 16, value >> 8, value); - return 5; - } - // int 64 - hi = Math.floor(value / Math.pow(2, 32)); - lo = value >>> 0; - bytes.push(0xd3, hi >> 24, hi >> 16, hi >> 8, hi, lo >> 24, lo >> 16, lo >> 8, lo); - return 9; - } - } - if (type === 'object') { - // nil - if (value === null) { - bytes.push(0xc0); - return 1; - } - - if (Array.isArray(value)) { - length = value.length; - - // fixarray - if (length < 0x10) { - bytes.push(length | 0x90); - size = 1; - } - // array 16 - else if (length < 0x10000) { - bytes.push(0xdc, length >> 8, length); - size = 3; - } - // array 32 - else if (length < 0x100000000) { - bytes.push(0xdd, length >> 24, length >> 16, length >> 8, length); - size = 5; - } else { - throw new Error('Array too large'); - } - for (i = 0; i < length; i++) { - size += _encode(bytes, defers, value[i]); - } - return size; - } - - if (value instanceof Date) { - var ms = value.getTime(); - var s = Math.floor(ms / 1e3); - var ns = (ms - s * 1e3) * 1e6; - - if (s >= 0 && ns >= 0 && s <= TIMESTAMP64_MAX_SEC) { - if (ns === 0 && s <= TIMESTAMP32_MAX_SEC) { - // timestamp 32 - bytes.push(0xd6, 0xff, s >> 24, s >> 16, s >> 8, s); - return 6; - } else { - // timestamp 64 - hi = s / 0x100000000; - lo = s & 0xffffffff; - bytes.push(0xd7, 0xff, ns >> 22, ns >> 14, ns >> 6, hi, lo >> 24, lo >> 16, lo >> 8, lo); - return 10; - } - } else { - // timestamp 96 - hi = Math.floor(s / 0x100000000); - lo = s >>> 0; - bytes.push(0xc7, 0x0c, 0xff, ns >> 24, ns >> 16, ns >> 8, ns, hi >> 24, hi >> 16, hi >> 8, hi, lo >> 24, lo >> 16, lo >> 8, lo); - return 15; - } - } - - if (value instanceof ArrayBuffer) { - length = value.byteLength; - - // bin 8 - if (length < 0x100) { - bytes.push(0xc4, length); - size = 2; - } else - // bin 16 - if (length < 0x10000) { - bytes.push(0xc5, length >> 8, length); - size = 3; - } else - // bin 32 - if (length < 0x100000000) { - bytes.push(0xc6, length >> 24, length >> 16, length >> 8, length); - size = 5; - } else { - throw new Error('Buffer too large'); - } - defers.push({ _bin: value, _length: length, _offset: bytes.length }); - return size + length; - } - - if (typeof value.toJSON === 'function') { - return _encode(bytes, defers, value.toJSON()); - } - - var keys = [], key = ''; - - var allKeys = Object.keys(value); - for (i = 0, l = allKeys.length; i < l; i++) { - key = allKeys[i]; - if (value[key] !== undefined && typeof value[key] !== 'function') { - keys.push(key); - } - } - length = keys.length; - - // fixmap - if (length < 0x10) { - bytes.push(length | 0x80); - size = 1; - } - // map 16 - else if (length < 0x10000) { - bytes.push(0xde, length >> 8, length); - size = 3; - } - // map 32 - else if (length < 0x100000000) { - bytes.push(0xdf, length >> 24, length >> 16, length >> 8, length); - size = 5; - } else { - throw new Error('Object too large'); - } - - for (i = 0; i < length; i++) { - key = keys[i]; - size += _encode(bytes, defers, key); - size += _encode(bytes, defers, value[key]); - } - return size; - } - // false/true - if (type === 'boolean') { - bytes.push(value ? 0xc3 : 0xc2); - return 1; - } - if (type === 'undefined') { - bytes.push(0xc0); - return 1; - } - // custom types like BigInt (typeof value === 'bigint') - if (typeof value.toJSON === 'function') { - return _encode(bytes, defers, value.toJSON()); - } - throw new Error('Could not encode'); -} - -function encode(value) { - var bytes = []; - var defers = []; - var size = _encode(bytes, defers, value); - var buf = new ArrayBuffer(size); - var view = new DataView(buf); - - var deferIndex = 0; - var deferWritten = 0; - var nextOffset = -1; - if (defers.length > 0) { - nextOffset = defers[0]._offset; - } - - var defer, deferLength = 0, offset = 0; - for (var i = 0, l = bytes.length; i < l; i++) { - view.setUint8(deferWritten + i, bytes[i]); - if (i + 1 !== nextOffset) { continue; } - defer = defers[deferIndex]; - deferLength = defer._length; - offset = deferWritten + nextOffset; - if (defer._bin) { - var bin = new Uint8Array(defer._bin); - for (var j = 0; j < deferLength; j++) { - view.setUint8(offset + j, bin[j]); - } - } else if (defer._str) { - utf8Write(view, offset, defer._str); - } else if (defer._float !== undefined) { - view.setFloat64(offset, defer._float); - } - deferIndex++; - deferWritten += deferLength; - if (defers[deferIndex]) { - nextOffset = defers[deferIndex]._offset; - } - } - return buf; -} - -export { encode, decode }; diff --git a/src/serializer/SchemaSerializer.ts b/src/serializer/SchemaSerializer.ts index 8631c95..620eaf8 100644 --- a/src/serializer/SchemaSerializer.ts +++ b/src/serializer/SchemaSerializer.ts @@ -1,13 +1,15 @@ import { Serializer } from "./Serializer"; -import { Schema, Reflection, Iterator } from "@colyseus/schema"; +import { Schema, Decoder, Reflection, Iterator } from "@colyseus/schema"; export type SchemaConstructor = new (...args: any[]) => T; export class SchemaSerializer implements Serializer { state: T; + decoder: Decoder; - setState(rawState: any) { - return this.state.decode(rawState); + setState(encodedState: any, it?: Iterator) { + this.decoder = new Decoder(this.state); + this.decoder.decode(encodedState, it); } getState() { @@ -15,18 +17,20 @@ export class SchemaSerializer implements Serializer { } patch(patches) { - return this.state.decode(patches); + return this.decoder.decode(patches); } teardown() { - this.state?.['$changes']?.root.clearRefs(); + this.decoder.$root.clearRefs(); } - handshake(bytes: number[], it?: Iterator) { + handshake(bytes: Buffer, it?: Iterator) { if (this.state) { - // TODO: validate client/server definitinos - const reflection = new Reflection(); - reflection.decode(bytes, it); + // + // TODO: + // validate definitions against concreate this.state instance + // + Reflection.decode(bytes, it); } else { // initialize reflected state from server diff --git a/src/serializer/Serializer.ts b/src/serializer/Serializer.ts index 000d195..6484473 100644 --- a/src/serializer/Serializer.ts +++ b/src/serializer/Serializer.ts @@ -1,11 +1,13 @@ +export type BufferLike = number[] | Uint8Array | Buffer; + export interface Serializer { - setState(data: any): void; + setState(data: BufferLike): void; getState(): State; - patch(data: any): void; + patch(data: BufferLike): void; teardown(): void; - handshake?(bytes: number[], it?: any): void; + handshake?(bytes: BufferLike, it?: any): void; } const serializers: { [id: string]: any } = {}; From 593c6a68f5d1d881467619bcc36821c52c708e6d Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Tue, 11 Jun 2024 19:53:34 -0300 Subject: [PATCH 13/38] fixes msgpackr usage --- src/Room.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Room.ts b/src/Room.ts index a04e857..0d90a67 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -11,7 +11,7 @@ import { decode, encode, Iterator } from '@colyseus/schema'; import { SchemaConstructor, SchemaSerializer } from './serializer/SchemaSerializer'; import { CloseCode } from './errors/ServerError'; -import msgpackr from "msgpackr"; +import { Packr, unpack } from "msgpackr"; type ByteArrayAllocator = new (length: number) => Uint8Array | Buffer; const ByteArrayAllocate: ByteArrayAllocator = (typeof Buffer !== 'undefined') @@ -50,14 +50,14 @@ export class Room { protected onMessageHandlers = createNanoEvents(); - protected packr: msgpackr.Packr; + protected packr: Packr; protected sendBuffer: Buffer | Uint8Array = new ByteArrayAllocate(8192); constructor(name: string, rootSchema?: SchemaConstructor) { this.roomId = null; this.name = name; - this.packr = new msgpackr.Packr(); + this.packr = new Packr(); // @ts-ignore this.packr.useBuffer(this.sendBuffer); @@ -224,7 +224,7 @@ export class Room { const message = (buffer.length > it.offset) // @ts-ignore - ? msgpackr.unpack(buffer, it.offset) + ? unpack(buffer, it.offset) : undefined; this.dispatchMessage(type, message); From 5b1e803f4663a4bd72b57bb50e4a62759e4fb231 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Tue, 11 Jun 2024 20:03:55 -0300 Subject: [PATCH 14/38] fix tsc build --- tsconfig.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 62955a8..901283a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,7 @@ "noImplicitAny": false, "esModuleInterop": true, "experimentalDecorators": true, - "inlineSources": true + "inlineSources": true, + "skipLibCheck": true } -} \ No newline at end of file +} From baa033f78453106b3f4eef384f7efa65b2233e82 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Thu, 13 Jun 2024 20:35:03 -0300 Subject: [PATCH 15/38] refactoring --- package-lock.json | 10 ++++----- package.json | 2 +- src/Connection.ts | 3 +-- src/Room.ts | 35 ++++++++++++----------------- src/serializer/SchemaSerializer.ts | 7 +++--- src/serializer/Serializer.ts | 6 +++-- src/transport/ITransport.ts | 2 +- src/transport/WebSocketTransport.ts | 9 ++------ 8 files changed, 32 insertions(+), 42 deletions(-) diff --git a/package-lock.json b/package-lock.json index a413a09..3cb6afe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.0", + "version": "0.16.0-preview.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "colyseus.js", - "version": "0.16.0-preview.0", + "version": "0.16.0-preview.1", "license": "MIT", "dependencies": { "@colyseus/schema": "^3.0.0-alpha.0", @@ -83,9 +83,9 @@ } }, "node_modules/@colyseus/schema": { - "version": "3.0.0-alpha.3", - "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.3.tgz", - "integrity": "sha512-55U1Ye45Tq4fsDIHBW/OLwqt+M5Ap1cEoI7BuGKCXo5zamW1W8SG4lK9jv64vs0HGwwUZCclCjw9TrG98nWPww==", + "version": "3.0.0-alpha.4", + "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.4.tgz", + "integrity": "sha512-Uf+eKiUXvAFOOZMN/UCAxhRvX7nRZQfQJhu5dK6zbwozZtg2pu+QDjibViVMp92n3OceeHKZe/+fvxc3CUHkmw==", "bin": { "schema-codegen": "bin/schema-codegen" } diff --git a/package.json b/package.json index 2b430c6..7d20520 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.0", + "version": "0.16.0-preview.3", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Connection.ts b/src/Connection.ts index 9b321ef..4f725dd 100644 --- a/src/Connection.ts +++ b/src/Connection.ts @@ -9,11 +9,10 @@ export class Connection implements ITransport { this.transport = new WebSocketTransport(this.events); } - send(data: ArrayBuffer | Array): void { + send(data: Buffer | Uint8Array): void { this.transport.send(data); } - connect(url: string): void { this.transport.connect(url); } diff --git a/src/Room.ts b/src/Room.ts index 0d90a67..cdcd05b 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -109,7 +109,8 @@ export class Room { if (this.connection) { if (consented) { - this.connection.send([Protocol.LEAVE_ROOM]); + this.sendBuffer[0] = Protocol.LEAVE_ROOM; + this.connection.send(this.sendBuffer.subarray(0, 1)); } else { this.connection.close(); @@ -128,8 +129,8 @@ export class Room { } public send(type: string | number, message?: any): void { - const it: Iterator = { offset: 0 }; - this.sendBuffer[it.offset++] = Protocol.ROOM_DATA; + const it: Iterator = { offset: 1 }; + this.sendBuffer[0] = Protocol.ROOM_DATA; if (typeof(type) === "string") { encode.string(this.sendBuffer, type, it); @@ -148,8 +149,8 @@ export class Room { } public sendBytes(type: string | number, bytes: Uint8Array) { - const it: Iterator = { offset: 0 }; - this.sendBuffer[it.offset++] = Protocol.ROOM_DATA_BYTES; + const it: Iterator = { offset: 1 }; + this.sendBuffer[0] = Protocol.ROOM_DATA_BYTES; if (typeof(type) === "string") { encode.string(this.sendBuffer, type, it); @@ -175,9 +176,9 @@ export class Room { protected onMessageCallback(event: MessageEvent) { const buffer = new Uint8Array(event.data); - const code = buffer[0]; const it: Iterator = { offset: 1 }; + const code = buffer[0]; if (code === Protocol.JOIN_ROOM) { const reconnectionToken = decode.utf8Read(buffer, it, buffer[it.offset++]); @@ -189,7 +190,7 @@ export class Room { this.serializer = new serializer(); } - if (buffer.length > it.offset && this.serializer.handshake) { + if (buffer.byteLength > it.offset && this.serializer.handshake) { this.serializer.handshake(buffer, it); } @@ -212,17 +213,19 @@ export class Room { this.leave(); } else if (code === Protocol.ROOM_STATE) { - this.setState(buffer.subarray(it.offset)); + this.serializer.setState(buffer, it); + this.onStateChange.invoke(this.serializer.getState()); } else if (code === Protocol.ROOM_STATE_PATCH) { - this.patch(buffer.subarray(it.offset)); + this.serializer.patch(buffer, it); + this.onStateChange.invoke(this.serializer.getState()); } else if (code === Protocol.ROOM_DATA) { const type = (decode.stringCheck(buffer, it)) ? decode.string(buffer, it) : decode.number(buffer, it); - const message = (buffer.length > it.offset) + const message = (buffer.byteLength > it.offset) // @ts-ignore ? unpack(buffer, it.offset) : undefined; @@ -236,20 +239,10 @@ export class Room { ? decode.string(buffer, it) : decode.number(buffer, it); - this.dispatchMessage(type, buffer.slice(it.offset)); + this.dispatchMessage(type, buffer.subarray(it.offset)); } } - protected setState(encodedState: BufferLike): void { - this.serializer.setState(encodedState); - this.onStateChange.invoke(this.serializer.getState()); - } - - protected patch(binaryPatch: BufferLike) { - this.serializer.patch(binaryPatch); - this.onStateChange.invoke(this.serializer.getState()); - } - private dispatchMessage(type: string | number, message: any) { const messageType = this.getMessageHandlerKey(type); diff --git a/src/serializer/SchemaSerializer.ts b/src/serializer/SchemaSerializer.ts index 620eaf8..e5b427e 100644 --- a/src/serializer/SchemaSerializer.ts +++ b/src/serializer/SchemaSerializer.ts @@ -7,8 +7,7 @@ export class SchemaSerializer implements Serializer { state: T; decoder: Decoder; - setState(encodedState: any, it?: Iterator) { - this.decoder = new Decoder(this.state); + setState(encodedState: Buffer, it?: Iterator) { this.decoder.decode(encodedState, it); } @@ -16,7 +15,7 @@ export class SchemaSerializer implements Serializer { return this.state; } - patch(patches) { + patch(patches: Buffer, it?: Iterator) { return this.decoder.decode(patches); } @@ -36,5 +35,7 @@ export class SchemaSerializer implements Serializer { // initialize reflected state from server this.state = Reflection.decode(bytes, it) as any; } + + this.decoder = new Decoder(this.state); } } diff --git a/src/serializer/Serializer.ts b/src/serializer/Serializer.ts index 6484473..d244459 100644 --- a/src/serializer/Serializer.ts +++ b/src/serializer/Serializer.ts @@ -1,10 +1,12 @@ +import type { Iterator } from "@colyseus/schema"; + export type BufferLike = number[] | Uint8Array | Buffer; export interface Serializer { - setState(data: BufferLike): void; + setState(data: BufferLike, it?: Iterator): void; getState(): State; - patch(data: BufferLike): void; + patch(data: BufferLike, it?: Iterator): void; teardown(): void; handshake?(bytes: BufferLike, it?: any): void; diff --git a/src/transport/ITransport.ts b/src/transport/ITransport.ts index 5f2303e..743b98a 100644 --- a/src/transport/ITransport.ts +++ b/src/transport/ITransport.ts @@ -11,7 +11,7 @@ export interface ITransportConstructor { export interface ITransport { isOpen: boolean; - send(data: ArrayBuffer | Array): void; + send(data: Buffer | Uint8Array): void; connect(url: string): void; close(code?: number, reason?: string): void; } diff --git a/src/transport/WebSocketTransport.ts b/src/transport/WebSocketTransport.ts index 67113b8..93c5557 100644 --- a/src/transport/WebSocketTransport.ts +++ b/src/transport/WebSocketTransport.ts @@ -9,13 +9,8 @@ export class WebSocketTransport implements ITransport { constructor(public events: ITransportEventMap) {} - public send(data: ArrayBuffer | Array): void { - if (data instanceof ArrayBuffer) { - this.ws.send(data); - - } else if (Array.isArray(data)) { - this.ws.send((new Uint8Array(data)).buffer); - } + public send(data: Buffer | Uint8Array): void { + this.ws.send(data); } public connect(url: string) { From 4908f289f0ee1392a5c9e9012e55a3e93b0c57c4 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Fri, 14 Jun 2024 00:09:34 -0300 Subject: [PATCH 16/38] fix decoding message --- dist/index.html | 7 ++++--- package-lock.json | 10 +++++----- src/Room.ts | 6 +++--- src/serializer/SchemaSerializer.ts | 4 ++-- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/dist/index.html b/dist/index.html index 4e58b91..9701bbe 100644 --- a/dist/index.html +++ b/dist/index.html @@ -38,9 +38,10 @@ function addListeners (room) { console.log('joined!'); - // room.onMessage("*", (type, message) => { - // console.log("received message:", type, "=>", message); - // }); + + room.onMessage("*", (type, message) => { + console.log("received message:", type, "=>", message); + }); room.onMessage("onJoin", () => {}); diff --git a/package-lock.json b/package-lock.json index 3cb6afe..1265aa8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.1", + "version": "0.16.0-preview.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "colyseus.js", - "version": "0.16.0-preview.1", + "version": "0.16.0-preview.3", "license": "MIT", "dependencies": { "@colyseus/schema": "^3.0.0-alpha.0", @@ -83,9 +83,9 @@ } }, "node_modules/@colyseus/schema": { - "version": "3.0.0-alpha.4", - "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.4.tgz", - "integrity": "sha512-Uf+eKiUXvAFOOZMN/UCAxhRvX7nRZQfQJhu5dK6zbwozZtg2pu+QDjibViVMp92n3OceeHKZe/+fvxc3CUHkmw==", + "version": "3.0.0-alpha.8", + "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.8.tgz", + "integrity": "sha512-Bnqy6mPj6mZJyvxhidn3T9UmV0Em1IGuYdNgxSbTsu0n7RHazJK74i81cwJrSJVZAF2TTszlR8ZnO9g94B0gXA==", "bin": { "schema-codegen": "bin/schema-codegen" } diff --git a/src/Room.ts b/src/Room.ts index cdcd05b..9eb8f98 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -180,6 +180,8 @@ export class Room { const it: Iterator = { offset: 1 }; const code = buffer[0]; + console.log("onMessage ->", code, Protocol[code], `(len: ${buffer.byteLength})`) + if (code === Protocol.JOIN_ROOM) { const reconnectionToken = decode.utf8Read(buffer, it, buffer[it.offset++]); this.serializerId = decode.utf8Read(buffer, it, buffer[it.offset++]); @@ -227,14 +229,12 @@ export class Room { const message = (buffer.byteLength > it.offset) // @ts-ignore - ? unpack(buffer, it.offset) + ? unpack(buffer, { start: it.offset }) : undefined; this.dispatchMessage(type, message); } else if (code === Protocol.ROOM_DATA_BYTES) { - const it: decode.Iterator = { offset: 1 }; - const type = (decode.stringCheck(buffer, it)) ? decode.string(buffer, it) : decode.number(buffer, it); diff --git a/src/serializer/SchemaSerializer.ts b/src/serializer/SchemaSerializer.ts index e5b427e..3695988 100644 --- a/src/serializer/SchemaSerializer.ts +++ b/src/serializer/SchemaSerializer.ts @@ -16,11 +16,11 @@ export class SchemaSerializer implements Serializer { } patch(patches: Buffer, it?: Iterator) { - return this.decoder.decode(patches); + return this.decoder.decode(patches, it); } teardown() { - this.decoder.$root.clearRefs(); + this.decoder.root.clearRefs(); } handshake(bytes: Buffer, it?: Iterator) { From e4ffcaf6f6c9439b2a5d059fdf9390eabc8819db Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Fri, 14 Jun 2024 15:49:15 -0300 Subject: [PATCH 17/38] use forked @colyseus/msgpackr version --- dist/index.html | 10 ++++++++++ package-lock.json | 18 +++++++++--------- package.json | 4 ++-- src/Room.ts | 14 +++++++------- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/dist/index.html b/dist/index.html index 9701bbe..b842508 100644 --- a/dist/index.html +++ b/dist/index.html @@ -26,6 +26,7 @@ + @@ -88,6 +89,15 @@ }); } + function sendRandomBytes() { + const bytes = new Uint8Array(32); + for (let i=0; i < bytes.length; i++) { + bytes[i] = Math.floor(Math.random() * 256); + } + console.log("sending bytes", Array.from(bytes)); + room.sendBytes("bytes", bytes); + } + function getAvailableRooms() { getClient().getAvailableRooms(document.getElementById('room_name').value).then((rooms) => { console.log(rooms); diff --git a/package-lock.json b/package-lock.json index 1265aa8..35502f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,9 @@ "version": "0.16.0-preview.3", "license": "MIT", "dependencies": { + "@colyseus/msgpackr": "^1.10.3", "@colyseus/schema": "^3.0.0-alpha.0", "httpie": "^2.0.0-next.13", - "msgpackr": "^1.10.2", "tslib": "^2.1.0", "ws": "^8.13.0" }, @@ -82,6 +82,14 @@ "node": ">=6.9.0" } }, + "node_modules/@colyseus/msgpackr": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/@colyseus/msgpackr/-/msgpackr-1.10.3.tgz", + "integrity": "sha512-xG46HkMobd2jV7bV91xXOm30L7TXo251GriFHfcTsG6vFfZY109LiN+9pwCkOa3U5LCELBhP8EOmRw1I65zf6g==", + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, "node_modules/@colyseus/schema": { "version": "3.0.0-alpha.8", "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.8.tgz", @@ -1064,14 +1072,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/msgpackr": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.10.2.tgz", - "integrity": "sha512-L60rsPynBvNE+8BWipKKZ9jHcSGbtyJYIwjRq0VrIvQ08cRjntGXJYW/tmciZ2IHWIY8WEW32Qa2xbh5+SKBZA==", - "optionalDependencies": { - "msgpackr-extract": "^3.0.2" - } - }, "node_modules/msgpackr-extract": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", diff --git a/package.json b/package.json index 7d20520..a24fc11 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.3", + "version": "0.16.0-preview.4", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", @@ -59,8 +59,8 @@ }, "dependencies": { "@colyseus/schema": "^3.0.0-alpha.0", + "@colyseus/msgpackr": "^1.10.3", "httpie": "^2.0.0-next.13", - "msgpackr": "^1.10.2", "tslib": "^2.1.0", "ws": "^8.13.0" }, diff --git a/src/Room.ts b/src/Room.ts index 9eb8f98..2a47fc5 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -11,7 +11,7 @@ import { decode, encode, Iterator } from '@colyseus/schema'; import { SchemaConstructor, SchemaSerializer } from './serializer/SchemaSerializer'; import { CloseCode } from './errors/ServerError'; -import { Packr, unpack } from "msgpackr"; +import { Packr, unpack } from '@colyseus/msgpackr'; type ByteArrayAllocator = new (length: number) => Uint8Array | Buffer; const ByteArrayAllocate: ByteArrayAllocator = (typeof Buffer !== 'undefined') @@ -58,7 +58,6 @@ export class Room { this.name = name; this.packr = new Packr(); - // @ts-ignore this.packr.useBuffer(this.sendBuffer); if (rootSchema) { @@ -139,10 +138,11 @@ export class Room { encode.number(this.sendBuffer, type, it); } + // force packr to use beginning of the buffer + this.packr.position = 0; + const data = (message !== undefined) - // @ts-ignore - ? this.packr.pack(message, 2048 + it.offset) // PR to fix TypeScript types https://github.com/kriszyp/msgpackr/pull/137 - // 2048 = RESERVE_START_SPACE + ? this.packr.pack(message, 2048 + it.offset) // 2048 = RESERVE_START_SPACE : this.sendBuffer.subarray(0, it.offset); this.connection.send(data); @@ -159,7 +159,8 @@ export class Room { encode.number(this.sendBuffer, type, it); } - this.connection.send(Buffer.concat([this.sendBuffer.subarray(0, it.offset), bytes])); + this.sendBuffer.set(bytes, it.offset); + this.connection.send(this.sendBuffer.subarray(0, it.offset + bytes.byteLength)); } public get state (): State { @@ -228,7 +229,6 @@ export class Room { : decode.number(buffer, it); const message = (buffer.byteLength > it.offset) - // @ts-ignore ? unpack(buffer, { start: it.offset }) : undefined; From 9ddc41ecb188b15ff1949b5d0c20d42bc0c140fe Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Wed, 19 Jun 2024 15:41:19 -0300 Subject: [PATCH 18/38] add room.$ for state callbacks. --- package-lock.json | 28 ++++++++++++++-------------- package.json | 2 +- src/Room.ts | 13 +++++++++++-- test/room_test.ts | 13 ------------- test/storage_test.ts | 19 +++++++++++++++++++ 5 files changed, 45 insertions(+), 30 deletions(-) create mode 100644 test/storage_test.ts diff --git a/package-lock.json b/package-lock.json index 35502f3..5fb43ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.3", + "version": "0.16.0-preview.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "colyseus.js", - "version": "0.16.0-preview.3", + "version": "0.16.0-preview.5", "license": "MIT", "dependencies": { "@colyseus/msgpackr": "^1.10.3", @@ -83,17 +83,17 @@ } }, "node_modules/@colyseus/msgpackr": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/@colyseus/msgpackr/-/msgpackr-1.10.3.tgz", - "integrity": "sha512-xG46HkMobd2jV7bV91xXOm30L7TXo251GriFHfcTsG6vFfZY109LiN+9pwCkOa3U5LCELBhP8EOmRw1I65zf6g==", + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@colyseus/msgpackr/-/msgpackr-1.10.4.tgz", + "integrity": "sha512-fqnZ6R91U8BnmXq7OuXNmtFe6JE/iYG3GskiPZjWw7uiE8IJJjLcIfm9h9JkVonHrwMoYCNDYYno/W3MTIz0mg==", "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "node_modules/@colyseus/schema": { - "version": "3.0.0-alpha.8", - "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.8.tgz", - "integrity": "sha512-Bnqy6mPj6mZJyvxhidn3T9UmV0Em1IGuYdNgxSbTsu0n7RHazJK74i81cwJrSJVZAF2TTszlR8ZnO9g94B0gXA==", + "version": "3.0.0-alpha.13", + "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.13.tgz", + "integrity": "sha512-ANAGktd3LKtM6qJVjBP/HbvRVVO06d2VF9UGMNNSuZMEZf8KYIKmpomwx6cNq/2AR8XCVHNR50k79RkqIak18g==", "bin": { "schema-codegen": "bin/schema-codegen" } @@ -291,9 +291,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.14.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz", - "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==", + "version": "20.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.6.tgz", + "integrity": "sha512-JbA0XIJPL1IiNnU7PFxDXyfAwcwVVrOoqyzzyQTyMeVhBzkJVMSkC1LlVsRQ2lpqiY4n6Bb9oCS6lzDKVQxbZw==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -6468,9 +6468,9 @@ } }, "node_modules/ws": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", - "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "engines": { "node": ">=10.0.0" }, diff --git a/package.json b/package.json index a24fc11..178365f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.4", + "version": "0.16.0-preview.5", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Room.ts b/src/Room.ts index 2a47fc5..aa20ec7 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -1,13 +1,13 @@ import { Connection } from './Connection'; import { Protocol } from './Protocol'; -import { BufferLike, getSerializer, Serializer } from './serializer/Serializer'; +import { getSerializer, Serializer } from './serializer/Serializer'; // The unused imports here are important for better `.d.ts` file generation // (Later merged with `dts-bundle-generator`) import { createNanoEvents } from './core/nanoevents'; import { createSignal } from './core/signal'; -import { decode, encode, Iterator } from '@colyseus/schema'; +import { decode, encode, Iterator, getStateCallbacks, CallbackProxy, Schema } from '@colyseus/schema'; import { SchemaConstructor, SchemaSerializer } from './serializer/SchemaSerializer'; import { CloseCode } from './errors/ServerError'; @@ -34,6 +34,11 @@ export class Room { public name: string; public connection: Connection; + /** + * API to attach callbacks to state changes + */ + public $: CallbackProxy; + // Public signals public onStateChange = createSignal<(state: State) => void>(); public onError = createSignal<(code: number, message?: string) => void>(); @@ -219,6 +224,10 @@ export class Room { this.serializer.setState(buffer, it); this.onStateChange.invoke(this.serializer.getState()); + // TODO: refactor me on 1.0 + // @ts-ignore + this.$ = getStateCallbacks((this.serializer as SchemaSerializer).decoder); + } else if (code === Protocol.ROOM_STATE_PATCH) { this.serializer.patch(buffer, it); this.onStateChange.invoke(this.serializer.getState()); diff --git a/test/room_test.ts b/test/room_test.ts index eb4aba0..be581d0 100644 --- a/test/room_test.ts +++ b/test/room_test.ts @@ -5,7 +5,6 @@ import { Room } from "../src"; import { Schema, type } from "@colyseus/schema"; // import * as fossilDelta from "fossil-delta"; -import * as msgpack from "../src/msgpack"; // import { FossilDeltaSerializer } from '../src/serializer/FossilDeltaSerializer'; describe("Room", function() { @@ -54,18 +53,6 @@ describe("Room", function() { room['dispatchMessage'](0, 5); }); - it("should handle schema message types", (done) => { - class MyMessage extends Schema { - @type("string") str: string = "hello"; - } - - room = new Room("chat"); - room.onMessage(MyMessage, (message) => { - assert.equal("hello", message.str); - done(); - }); - room['dispatchMessage'](MyMessage, new MyMessage()); - }); }); /* diff --git a/test/storage_test.ts b/test/storage_test.ts new file mode 100644 index 0000000..9ff365e --- /dev/null +++ b/test/storage_test.ts @@ -0,0 +1,19 @@ +import './util'; +import assert from "assert"; +import { setItem, getItem } from "../src/Storage"; + +describe("Storage", function() { + + it("get and set", () => { + setItem("test", "test"); + + let getCalled = false; + getItem("test", (data) => { + getCalled = true; + assert.strictEqual(data, "test"); + }) + + assert.ok(getCalled); + }); + +}); From 1b7ab8388d5d7281d744226537eb4f0ee8574d09 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Wed, 19 Jun 2024 20:50:11 -0300 Subject: [PATCH 19/38] expose getStateCallbacks from '@colyseus/schema' --- package-lock.json | 6 +++--- package.json | 2 +- src/index.ts | 5 +++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5fb43ca..06be4c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -91,9 +91,9 @@ } }, "node_modules/@colyseus/schema": { - "version": "3.0.0-alpha.13", - "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.13.tgz", - "integrity": "sha512-ANAGktd3LKtM6qJVjBP/HbvRVVO06d2VF9UGMNNSuZMEZf8KYIKmpomwx6cNq/2AR8XCVHNR50k79RkqIak18g==", + "version": "3.0.0-alpha.14", + "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.14.tgz", + "integrity": "sha512-ImU2PBpZl5mEMbUI3L5N/xm0Om4qcwrgewsIsB5r26X4JXeSF57jncYBzdKoLEBOLPcAqD/uOUjAuIE1jPps+A==", "bin": { "schema-codegen": "bin/schema-codegen" } diff --git a/package.json b/package.json index 178365f..6e57779 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.5", + "version": "0.16.0-preview.6", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/index.ts b/src/index.ts index 531f88b..46a32f0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,11 @@ export { Protocol, ErrorCode } from './Protocol'; export { Room, RoomAvailable } from './Room'; export { Auth, type AuthSettings, type PopupSettings } from "./Auth"; +/** + * @colyseus/schema + */ +export { getStateCallbacks } from "@colyseus/schema"; + /* * Serializers */ From cb927eae09a13f10fb18a59f017b2ab6be08f7b6 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Wed, 19 Jun 2024 20:59:36 -0300 Subject: [PATCH 20/38] don't initialize room.$. bump version --- package.json | 2 +- src/Room.ts | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/package.json b/package.json index 6e57779..2fc9483 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.6", + "version": "0.16.0-preview.7", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Room.ts b/src/Room.ts index aa20ec7..bf1f119 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -34,11 +34,6 @@ export class Room { public name: string; public connection: Connection; - /** - * API to attach callbacks to state changes - */ - public $: CallbackProxy; - // Public signals public onStateChange = createSignal<(state: State) => void>(); public onError = createSignal<(code: number, message?: string) => void>(); @@ -224,10 +219,6 @@ export class Room { this.serializer.setState(buffer, it); this.onStateChange.invoke(this.serializer.getState()); - // TODO: refactor me on 1.0 - // @ts-ignore - this.$ = getStateCallbacks((this.serializer as SchemaSerializer).decoder); - } else if (code === Protocol.ROOM_STATE_PATCH) { this.serializer.patch(buffer, it); this.onStateChange.invoke(this.serializer.getState()); From d60fb0366d77bb55e6d9de82e7d126ebc822b554 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Wed, 19 Jun 2024 21:10:37 -0300 Subject: [PATCH 21/38] fix exposing getStateCallbacks() accepting Room as argument. --- package.json | 2 +- src/index.ts | 10 ++-------- src/serializer/SchemaSerializer.ts | 7 ++++++- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 2fc9483..0589786 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.7", + "version": "0.16.0-preview.8", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/index.ts b/src/index.ts index 46a32f0..cc09d29 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,19 +5,13 @@ export { Protocol, ErrorCode } from './Protocol'; export { Room, RoomAvailable } from './Room'; export { Auth, type AuthSettings, type PopupSettings } from "./Auth"; -/** - * @colyseus/schema - */ -export { getStateCallbacks } from "@colyseus/schema"; - /* * Serializers */ - -import { SchemaSerializer } from "./serializer/SchemaSerializer"; +import { SchemaSerializer, getStateCallbacks } from "./serializer/SchemaSerializer"; import { NoneSerializer } from "./serializer/NoneSerializer"; import { registerSerializer } from './serializer/Serializer'; -export { registerSerializer, SchemaSerializer }; +export { registerSerializer, SchemaSerializer, getStateCallbacks }; registerSerializer('schema', SchemaSerializer); registerSerializer('none', NoneSerializer); diff --git a/src/serializer/SchemaSerializer.ts b/src/serializer/SchemaSerializer.ts index 3695988..dde3499 100644 --- a/src/serializer/SchemaSerializer.ts +++ b/src/serializer/SchemaSerializer.ts @@ -1,8 +1,13 @@ import { Serializer } from "./Serializer"; -import { Schema, Decoder, Reflection, Iterator } from "@colyseus/schema"; +import { Schema, Decoder, Reflection, Iterator, getStateCallbacks as originalGetStateCallbacks } from "@colyseus/schema"; +import type { Room } from "../Room"; export type SchemaConstructor = new (...args: any[]) => T; +export function getStateCallbacks(room: Room) { + return originalGetStateCallbacks((room['serializer'] as unknown as SchemaSerializer).decoder); +} + export class SchemaSerializer implements Serializer { state: T; decoder: Decoder; From 8ef4f8c9ce25f8ef8592d481c02f79539d8237c5 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Wed, 19 Jun 2024 21:14:20 -0300 Subject: [PATCH 22/38] fix return type for getStateCallbacks() --- package.json | 2 +- src/serializer/SchemaSerializer.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 0589786..49acfbd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.8", + "version": "0.16.0-preview.9", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/serializer/SchemaSerializer.ts b/src/serializer/SchemaSerializer.ts index dde3499..a16e0a2 100644 --- a/src/serializer/SchemaSerializer.ts +++ b/src/serializer/SchemaSerializer.ts @@ -4,7 +4,7 @@ import type { Room } from "../Room"; export type SchemaConstructor = new (...args: any[]) => T; -export function getStateCallbacks(room: Room) { +export function getStateCallbacks(room: Room) { return originalGetStateCallbacks((room['serializer'] as unknown as SchemaSerializer).decoder); } From 26a0a473f6fd60f991f0b29936ab77e2efa4a2d2 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Wed, 19 Jun 2024 21:43:07 -0300 Subject: [PATCH 23/38] bump versions --- package-lock.json | 10 +++++----- package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 06be4c3..c50b65b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.5", + "version": "0.16.0-preview.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "colyseus.js", - "version": "0.16.0-preview.5", + "version": "0.16.0-preview.10", "license": "MIT", "dependencies": { "@colyseus/msgpackr": "^1.10.3", @@ -91,9 +91,9 @@ } }, "node_modules/@colyseus/schema": { - "version": "3.0.0-alpha.14", - "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.14.tgz", - "integrity": "sha512-ImU2PBpZl5mEMbUI3L5N/xm0Om4qcwrgewsIsB5r26X4JXeSF57jncYBzdKoLEBOLPcAqD/uOUjAuIE1jPps+A==", + "version": "3.0.0-alpha.15", + "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.15.tgz", + "integrity": "sha512-qU0ICBodRPYBiLjrK1y6AxfzoO/cTqSqLMbpHczPv0DSRfOIv49kQufLuA4aNHquCs5wFoisnQ4Uth5QaQwtRQ==", "bin": { "schema-codegen": "bin/schema-codegen" } diff --git a/package.json b/package.json index 49acfbd..a46ef18 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.9", + "version": "0.16.0-preview.10", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", From 71f85ecf9d142138b60247fd074244244f3ede05 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Tue, 25 Jun 2024 23:40:34 -0300 Subject: [PATCH 24/38] remove log during onMessage. bump version --- package.json | 2 +- src/Room.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/package.json b/package.json index a46ef18..7c1b6d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.10", + "version": "0.16.0-preview.11", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Room.ts b/src/Room.ts index ee8705c..1dd0cbf 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -181,8 +181,6 @@ export class Room { const it: Iterator = { offset: 1 }; const code = buffer[0]; - console.log("onMessage ->", code, Protocol[code], `(len: ${buffer.byteLength})`) - if (code === Protocol.JOIN_ROOM) { const reconnectionToken = decode.utf8Read(buffer, it, buffer[it.offset++]); this.serializerId = decode.utf8Read(buffer, it, buffer[it.offset++]); From ec9797b261f3d479093ab0e932af8204f31a1be3 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Wed, 3 Jul 2024 19:35:57 -0300 Subject: [PATCH 25/38] expose 'SeatReservation' type --- package.json | 2 +- src/Client.ts | 10 +++++----- src/Protocol.ts | 8 +++++++- src/Room.ts | 3 --- src/index.ts | 2 +- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 7c1b6d8..72dd94d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.11", + "version": "0.16.0-preview.12", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Client.ts b/src/Client.ts index e280d3e..4dceaff 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -3,6 +3,7 @@ import { Room, RoomAvailable } from './Room'; import { SchemaConstructor } from './serializer/SchemaSerializer'; import { HTTP } from "./HTTP"; import { Auth } from './Auth'; +import { SeatReservation } from './Protocol'; export type JoinOptions = any; @@ -121,7 +122,7 @@ export class Client { } public async consumeSeatReservation( - response: any, + response: SeatReservation, rootSchema?: SchemaConstructor, reuseRoomInstance?: Room // used in devMode ): Promise> { @@ -183,7 +184,7 @@ export class Client { reuseRoomInstance?: Room, ) { const response = ( - await this.http.post(`matchmake/${method}/${roomName}`, { + await this.http.post(`matchmake/${method}/${roomName}`, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' @@ -193,9 +194,8 @@ export class Client { ).data; // FIXME: HTTP class is already handling this as ServerError. - if (response.error) { - throw new MatchMakeError(response.error, response.code); - } + // @ts-ignore + if (response.error) { throw new MatchMakeError(response.error, response.code); } // forward reconnection token during "reconnect" methods. if (method === "reconnect") { diff --git a/src/Protocol.ts b/src/Protocol.ts index cb16268..7decc7b 100644 --- a/src/Protocol.ts +++ b/src/Protocol.ts @@ -1,4 +1,10 @@ -import type { Iterator } from "@colyseus/schema"; +import { RoomAvailable } from "./Room"; + +export interface SeatReservation { + room: RoomAvailable; + sessionId: string; + reconnectionToken?: string; +} // Use codes between 0~127 for lesser throughput (1 byte) export enum Protocol { diff --git a/src/Room.ts b/src/Room.ts index 1dd0cbf..854b4e3 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -70,9 +70,6 @@ export class Room { this.onLeave(() => this.removeAllListeners()); } - // TODO: deprecate me on version 1.0 - get id() { return this.roomId; } - public connect( endpoint: string, devModeCloseCallback?: () => void, diff --git a/src/index.ts b/src/index.ts index cc09d29..b44abdc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ import './legacy'; export { Client, JoinOptions } from './Client'; -export { Protocol, ErrorCode } from './Protocol'; +export { Protocol, ErrorCode, SeatReservation } from './Protocol'; export { Room, RoomAvailable } from './Room'; export { Auth, type AuthSettings, type PopupSettings } from "./Auth"; From feab9375b50d8a076b43a772c94c2562b68fac5d Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Wed, 10 Jul 2024 16:42:22 -0300 Subject: [PATCH 26/38] fixes msgpackr buffer usage --- package-lock.json | 12 ++++++------ package.json | 4 ++-- src/Protocol.ts | 1 + src/Room.ts | 31 ++++++++++++++++--------------- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index c50b65b..ccefb86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.10", + "version": "0.16.0-preview.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "colyseus.js", - "version": "0.16.0-preview.10", + "version": "0.16.0-preview.12", "license": "MIT", "dependencies": { - "@colyseus/msgpackr": "^1.10.3", + "@colyseus/msgpackr": "^1.10.5", "@colyseus/schema": "^3.0.0-alpha.0", "httpie": "^2.0.0-next.13", "tslib": "^2.1.0", @@ -83,9 +83,9 @@ } }, "node_modules/@colyseus/msgpackr": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@colyseus/msgpackr/-/msgpackr-1.10.4.tgz", - "integrity": "sha512-fqnZ6R91U8BnmXq7OuXNmtFe6JE/iYG3GskiPZjWw7uiE8IJJjLcIfm9h9JkVonHrwMoYCNDYYno/W3MTIz0mg==", + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/@colyseus/msgpackr/-/msgpackr-1.10.5.tgz", + "integrity": "sha512-ZSWPpEEnSe/oMzifiLKkNdE5UR0B8STagWR1JcKV5qw6ISM/z8d7ArZgGstqBrrZAXAOIZDpvOyrTloiR9zRlg==", "optionalDependencies": { "msgpackr-extract": "^3.0.2" } diff --git a/package.json b/package.json index 72dd94d..c0dda23 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.12", + "version": "0.16.0-preview.13", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", @@ -58,8 +58,8 @@ "node": ">= 12.x" }, "dependencies": { + "@colyseus/msgpackr": "^1.10.5", "@colyseus/schema": "^3.0.0-alpha.0", - "@colyseus/msgpackr": "^1.10.3", "httpie": "^2.0.0-next.13", "tslib": "^2.1.0", "ws": "^8.13.0" diff --git a/src/Protocol.ts b/src/Protocol.ts index 7decc7b..4a5e93f 100644 --- a/src/Protocol.ts +++ b/src/Protocol.ts @@ -4,6 +4,7 @@ export interface SeatReservation { room: RoomAvailable; sessionId: string; reconnectionToken?: string; + devMode?: boolean; } // Use codes between 0~127 for lesser throughput (1 byte) diff --git a/src/Room.ts b/src/Room.ts index 854b4e3..ac655f1 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -51,14 +51,15 @@ export class Room { protected onMessageHandlers = createNanoEvents(); protected packr: Packr; - protected sendBuffer: Buffer | Uint8Array = new ByteArrayAllocate(8192); constructor(name: string, rootSchema?: SchemaConstructor) { this.roomId = null; this.name = name; this.packr = new Packr(); - this.packr.useBuffer(this.sendBuffer); + + // msgpackr workaround: force buffer to be created. + this.packr.encode(undefined); if (rootSchema) { this.serializer = new (getSerializer("schema")); @@ -105,8 +106,8 @@ export class Room { if (this.connection) { if (consented) { - this.sendBuffer[0] = Protocol.LEAVE_ROOM; - this.connection.send(this.sendBuffer.subarray(0, 1)); + this.packr.buffer[0] = Protocol.LEAVE_ROOM; + this.connection.send(this.packr.buffer.subarray(0, 1)); } else { this.connection.close(); @@ -126,13 +127,13 @@ export class Room { public send(type: string | number, message?: T): void { const it: Iterator = { offset: 1 }; - this.sendBuffer[0] = Protocol.ROOM_DATA; + this.packr.buffer[0] = Protocol.ROOM_DATA; if (typeof(type) === "string") { - encode.string(this.sendBuffer, type, it); + encode.string(this.packr.buffer, type, it); } else { - encode.number(this.sendBuffer, type, it); + encode.number(this.packr.buffer, type, it); } // force packr to use beginning of the buffer @@ -140,24 +141,24 @@ export class Room { const data = (message !== undefined) ? this.packr.pack(message, 2048 + it.offset) // 2048 = RESERVE_START_SPACE - : this.sendBuffer.subarray(0, it.offset); + : this.packr.buffer.subarray(0, it.offset); this.connection.send(data); } public sendBytes(type: string | number, bytes: Uint8Array) { const it: Iterator = { offset: 1 }; - this.sendBuffer[0] = Protocol.ROOM_DATA_BYTES; + this.packr.buffer[0] = Protocol.ROOM_DATA_BYTES; if (typeof(type) === "string") { - encode.string(this.sendBuffer, type, it); + encode.string(this.packr.buffer, type, it); } else { - encode.number(this.sendBuffer, type, it); + encode.number(this.packr.buffer, type, it); } - this.sendBuffer.set(bytes, it.offset); - this.connection.send(this.sendBuffer.subarray(0, it.offset + bytes.byteLength)); + this.packr.buffer.set(bytes, it.offset); + this.connection.send(this.packr.buffer.subarray(0, it.offset + bytes.byteLength)); } public get state (): State { @@ -198,8 +199,8 @@ export class Room { this.onJoin.invoke(); // acknowledge successfull JOIN_ROOM - this.sendBuffer[0] = Protocol.JOIN_ROOM; - this.connection.send(this.sendBuffer.subarray(0, 1)); + this.packr.buffer[0] = Protocol.JOIN_ROOM; + this.connection.send(this.packr.buffer.subarray(0, 1)); } else if (code === Protocol.ERROR) { const code = decode.number(buffer, it); From ead56ab9165ad731cc413d146ca5172538fe5bfc Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Tue, 16 Jul 2024 10:51:28 -0300 Subject: [PATCH 27/38] remove schema callbacks on room.removeAllListeners(). colyseus/colyseus#749 --- src/Room.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Room.ts b/src/Room.ts index ac655f1..0ea62bd 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -171,6 +171,11 @@ export class Room { this.onError.clear(); this.onLeave.clear(); this.onMessageHandlers.events = {}; + + if (this.serializer instanceof SchemaSerializer) { + // Remove callback references + this.serializer.decoder.root.callbacks = {}; + } } protected onMessageCallback(event: MessageEvent) { From 2b295e7f096138fb9783397dea7231beff420c53 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Tue, 16 Jul 2024 11:47:16 -0300 Subject: [PATCH 28/38] use getDecoderStateCallbacks --- package-lock.json | 12 ++++++------ package.json | 4 ++-- src/Room.ts | 2 +- src/serializer/SchemaSerializer.ts | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index ccefb86..36ba7fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,16 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.12", + "version": "0.16.0-preview.13", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "colyseus.js", - "version": "0.16.0-preview.12", + "version": "0.16.0-preview.13", "license": "MIT", "dependencies": { "@colyseus/msgpackr": "^1.10.5", - "@colyseus/schema": "^3.0.0-alpha.0", + "@colyseus/schema": "^3.0.0-alpha.19", "httpie": "^2.0.0-next.13", "tslib": "^2.1.0", "ws": "^8.13.0" @@ -91,9 +91,9 @@ } }, "node_modules/@colyseus/schema": { - "version": "3.0.0-alpha.15", - "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.15.tgz", - "integrity": "sha512-qU0ICBodRPYBiLjrK1y6AxfzoO/cTqSqLMbpHczPv0DSRfOIv49kQufLuA4aNHquCs5wFoisnQ4Uth5QaQwtRQ==", + "version": "3.0.0-alpha.19", + "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.19.tgz", + "integrity": "sha512-bs99kqqm6rmHJKqBKQAyM+fRweCCIph2w+3WUG4zVOPbbHlHupqdqgkoGNSVR8B4KrlSsk8RmAbrn0rexmakWw==", "bin": { "schema-codegen": "bin/schema-codegen" } diff --git a/package.json b/package.json index c0dda23..3be5fd5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.13", + "version": "0.16.0-preview.14", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", @@ -59,7 +59,7 @@ }, "dependencies": { "@colyseus/msgpackr": "^1.10.5", - "@colyseus/schema": "^3.0.0-alpha.0", + "@colyseus/schema": "^3.0.0-alpha.19", "httpie": "^2.0.0-next.13", "tslib": "^2.1.0", "ws": "^8.13.0" diff --git a/src/Room.ts b/src/Room.ts index 0ea62bd..e9d1901 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -7,7 +7,7 @@ import { getSerializer, Serializer } from './serializer/Serializer'; import { createNanoEvents } from './core/nanoevents'; import { createSignal } from './core/signal'; -import { decode, encode, Iterator, getStateCallbacks, CallbackProxy, Schema } from '@colyseus/schema'; +import { decode, encode, Iterator } from '@colyseus/schema'; import { SchemaConstructor, SchemaSerializer } from './serializer/SchemaSerializer'; import { CloseCode } from './errors/ServerError'; diff --git a/src/serializer/SchemaSerializer.ts b/src/serializer/SchemaSerializer.ts index a16e0a2..e769cd1 100644 --- a/src/serializer/SchemaSerializer.ts +++ b/src/serializer/SchemaSerializer.ts @@ -1,11 +1,11 @@ import { Serializer } from "./Serializer"; -import { Schema, Decoder, Reflection, Iterator, getStateCallbacks as originalGetStateCallbacks } from "@colyseus/schema"; +import { Schema, Decoder, Reflection, Iterator, getDecoderStateCallbacks } from "@colyseus/schema"; import type { Room } from "../Room"; export type SchemaConstructor = new (...args: any[]) => T; export function getStateCallbacks(room: Room) { - return originalGetStateCallbacks((room['serializer'] as unknown as SchemaSerializer).decoder); + return getDecoderStateCallbacks((room['serializer'] as unknown as SchemaSerializer).decoder); } export class SchemaSerializer implements Serializer { From 19a6355e27012adc13eb9d6fcfb9dee9428af0d2 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Thu, 18 Jul 2024 23:31:29 -0300 Subject: [PATCH 29/38] raw example: fix state callbacks --- dist/index.html | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dist/index.html b/dist/index.html index 8f9c97b..8eb520d 100644 --- a/dist/index.html +++ b/dist/index.html @@ -38,15 +38,16 @@ } function addListeners (room) { + const $ = Colyseus.getStateCallbacks(room); + console.log('joined!'); room.onMessage("*", (type, message) => { console.log("received message:", type, "=>", message); }); - // listen to player "add" events - room.state.players.onAdd(function(player, sessionId) { + $(room.state).players.onAdd(function(player, sessionId) { console.log("ADD PLAYER", player); var el = document.createElement("div"); @@ -61,14 +62,14 @@ // el.style.top = player.y + "px"; document.body.appendChild(el); - player.onChange(function() { + $(player).onChange(function() { el.style.left = player.x + "px"; el.style.top = player.y + "px"; }); }); // listen to player "remove" events - room.state.players.onRemove(function(player, sessionId) { + $(room.state).players.onRemove(function(player, sessionId) { var el = document.getElementById("player-" + sessionId); el.parentNode.removeChild(el); }); @@ -94,7 +95,7 @@ }); room.onStateChange(function(state) { - console.log("state change: ", state.toJSON()); + // console.log("state change: ", state.toJSON()); }); } From 15c6314fb50cfc484342d9a1ce010c8d692fb5aa Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Thu, 18 Jul 2024 23:32:27 -0300 Subject: [PATCH 30/38] fix h3 / webtransport --- package-lock.json | 12 ++---------- package.json | 2 +- src/Connection.ts | 2 +- src/Protocol.ts | 1 + src/Room.ts | 2 +- src/transport/H3Transport.ts | 23 ++++++++--------------- src/transport/WebSocketTransport.ts | 2 +- 7 files changed, 15 insertions(+), 29 deletions(-) diff --git a/package-lock.json b/package-lock.json index d308a21..a76e5ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,12 @@ { "name": "colyseus.js", -<<<<<<< HEAD - "version": "0.16.0-preview.14", -======= - "version": "0.15.15", ->>>>>>> webtransport + "version": "0.16.0-preview.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "colyseus.js", -<<<<<<< HEAD - "version": "0.16.0-preview.14", -======= - "version": "0.15.15", ->>>>>>> webtransport + "version": "0.16.0-preview.15", "license": "MIT", "dependencies": { "@colyseus/msgpackr": "^1.10.5", diff --git a/package.json b/package.json index 2c6ca68..fa9303d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.15", + "version": "0.16.0-preview.16", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Connection.ts b/src/Connection.ts index 179d802..50c9a23 100644 --- a/src/Connection.ts +++ b/src/Connection.ts @@ -26,7 +26,7 @@ export class Connection implements ITransport { this.transport.send(data); } - sendUnreliable(data: ArrayBuffer | Array): void { + sendUnreliable(data: Buffer | Uint8Array): void { this.transport.sendUnreliable(data); } diff --git a/src/Protocol.ts b/src/Protocol.ts index 4a5e93f..b28a3e4 100644 --- a/src/Protocol.ts +++ b/src/Protocol.ts @@ -5,6 +5,7 @@ export interface SeatReservation { sessionId: string; reconnectionToken?: string; devMode?: boolean; + protocol?: string; } // Use codes between 0~127 for lesser throughput (1 byte) diff --git a/src/Room.ts b/src/Room.ts index dfde0a7..8485db8 100644 --- a/src/Room.ts +++ b/src/Room.ts @@ -151,7 +151,7 @@ export class Room { this.connection.send(data); } - public sendUnreliable(type: string | number, message?: Uint8Array): void { + public sendUnreliable(type: string | number, message?: T): void { const it: Iterator = { offset: 1 }; this.packr.buffer[0] = Protocol.ROOM_DATA; diff --git a/src/transport/H3Transport.ts b/src/transport/H3Transport.ts index c96e1db..8958561 100644 --- a/src/transport/H3Transport.ts +++ b/src/transport/H3Transport.ts @@ -1,5 +1,5 @@ import { ITransport, ITransportEventMap } from "./ITransport"; -import { encode } from '@colyseus/schema'; +import { encode, Iterator } from '@colyseus/schema'; export class H3TransportTransport implements ITransport { wt: WebTransport; @@ -71,18 +71,11 @@ export class H3TransportTransport implements ITransport { }); } - public send(data: ArrayBuffer | Array): void { - console.log(".send()", data); - if (data instanceof ArrayBuffer) { - this.writer.write(data); - - } else if (Array.isArray(data)) { - this.writer.write(new Uint8Array(data)); - } + public send(data: Buffer | Uint8Array): void { + this.writer.write(data); } - public sendUnreliable(data: ArrayBuffer | Array): void { - console.log(".sendUnreliable()", data); + public sendUnreliable(data: Buffer | Uint8Array): void { this.unreliableWriter.write(data); } @@ -131,20 +124,20 @@ export class H3TransportTransport implements ITransport { } protected sendSeatReservation (roomId: string, sessionId: string, reconnectionToken?: string) { + const it: Iterator = { offset: 0 }; const bytes: number[] = []; - encode.string(bytes, roomId); - encode.string(bytes, sessionId); + encode.string(bytes, roomId, it); + encode.string(bytes, sessionId, it); if (reconnectionToken) { - encode.string(bytes, reconnectionToken); + encode.string(bytes, reconnectionToken, it); } this.writer.write(new Uint8Array(bytes).buffer); } protected _close() { - console.log("_close() !!"); this.isOpen = false; } diff --git a/src/transport/WebSocketTransport.ts b/src/transport/WebSocketTransport.ts index 4d9cce5..7d7f6c7 100644 --- a/src/transport/WebSocketTransport.ts +++ b/src/transport/WebSocketTransport.ts @@ -14,7 +14,7 @@ export class WebSocketTransport implements ITransport { } public sendUnreliable(data: ArrayBuffer | Array): void { - throw new Error("WebSocket does not support unreliable messages"); + console.warn("colyseus.js: The WebSocket transport does not support unreliable messages"); } public connect(url: string) { From 8185228abc10f00e32c05aa59252a009041c9385 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Fri, 19 Jul 2024 11:39:40 -0300 Subject: [PATCH 31/38] h3-transport: read multiple length-prefixed messages at once --- package.json | 2 +- src/transport/H3Transport.ts | 47 ++++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index fa9303d..f902d70 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.16", + "version": "0.16.0-preview.17", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/transport/H3Transport.ts b/src/transport/H3Transport.ts index 8958561..853e423 100644 --- a/src/transport/H3Transport.ts +++ b/src/transport/H3Transport.ts @@ -8,8 +8,8 @@ export class H3TransportTransport implements ITransport { reader: ReadableStreamDefaultReader; writer: WritableStreamDefaultWriter; - unreliableReader: ReadableStreamDefaultReader; - unreliableWriter: WritableStreamDefaultWriter; + unreliableReader: ReadableStreamDefaultReader; + unreliableWriter: WritableStreamDefaultWriter; constructor(public events: ITransportEventMap) { } @@ -88,29 +88,62 @@ export class H3TransportTransport implements ITransport { } protected async readIncomingData() { - let result: ReadableStreamReadResult; + let result: ReadableStreamReadResult; while (this.isOpen) { try { result = await this.reader.read(); + + // + // a single read may contain multiple messages + // each message is prefixed with its length + // + + const messages = result.value; + const it: Iterator = { offset: 0 }; + do { + // + // QUESTION: should we buffer the message in case it's not fully read? + // + + const length = messages[it.offset++]; + this.events.onmessage({ data: messages.subarray(it.offset, it.offset + length) }); + it.offset += length; + } while (it.offset < messages.length); + } catch (e) { console.error("failed to read incoming data", e); break; } if (result.done) { break; } - - // value is a Uint8Array. - this.events.onmessage({ data: result.value.buffer }); } } protected async readIncomingUnreliableData() { - let result: ReadableStreamReadResult; + let result: ReadableStreamReadResult; while (this.isOpen) { try { result = await this.unreliableReader.read(); + + // + // a single read may contain multiple messages + // each message is prefixed with its length + // + + const messages = result.value; + const it: Iterator = { offset: 0 }; + do { + // + // QUESTION: should we buffer the message in case it's not fully read? + // + + const length = messages[it.offset++]; + this.events.onmessage({ data: messages.subarray(it.offset, it.offset + length) }); + it.offset += length; + } while (it.offset < messages.length); + } catch (e) { console.error("failed to read incoming data", e); break; From 5d31274b3d8fffa1a03469131ef65fe1e1330fdd Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Fri, 19 Jul 2024 12:04:44 -0300 Subject: [PATCH 32/38] h3-transport: send length-prefixed messages --- package.json | 2 +- src/transport/H3Transport.ts | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index f902d70..c10ca22 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.17", + "version": "0.16.0-preview.18", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/transport/H3Transport.ts b/src/transport/H3Transport.ts index 853e423..97fed83 100644 --- a/src/transport/H3Transport.ts +++ b/src/transport/H3Transport.ts @@ -72,11 +72,17 @@ export class H3TransportTransport implements ITransport { } public send(data: Buffer | Uint8Array): void { - this.writer.write(data); + const lengthPrefixed = new Uint8Array(data.byteLength + 1); + lengthPrefixed[0] = data.byteLength; + lengthPrefixed.set(new Uint8Array(data), 1); + this.writer.write(lengthPrefixed); } public sendUnreliable(data: Buffer | Uint8Array): void { - this.unreliableWriter.write(data); + const lengthPrefixed = new Uint8Array(data.byteLength + 1); + lengthPrefixed[0] = data.byteLength; + lengthPrefixed.set(new Uint8Array(data), 1); + this.unreliableWriter.write(lengthPrefixed); } public close(code?: number, reason?: string) { From c19ecf495779f0e9a3884cbf68eabd13b72139b2 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Wed, 24 Jul 2024 14:31:27 -0300 Subject: [PATCH 33/38] h3-transport: fixes sending and receiving 'varint' length prefixed messages --- package.json | 2 +- src/transport/H3Transport.ts | 45 +++++++++++++++++++++--------------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index c10ca22..5d31e73 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.18", + "version": "0.16.0-preview.20", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/transport/H3Transport.ts b/src/transport/H3Transport.ts index 97fed83..6be6455 100644 --- a/src/transport/H3Transport.ts +++ b/src/transport/H3Transport.ts @@ -1,5 +1,5 @@ import { ITransport, ITransportEventMap } from "./ITransport"; -import { encode, Iterator } from '@colyseus/schema'; +import { encode, decode, Iterator } from '@colyseus/schema'; export class H3TransportTransport implements ITransport { wt: WebTransport; @@ -11,6 +11,8 @@ export class H3TransportTransport implements ITransport { unreliableReader: ReadableStreamDefaultReader; unreliableWriter: WritableStreamDefaultWriter; + private lengthPrefixBuffer = new Uint8Array(9); // 9 bytes is the maximum length of a length prefix + constructor(public events: ITransportEventMap) { } public connect(url: string, options: any = {}) { @@ -72,17 +74,19 @@ export class H3TransportTransport implements ITransport { } public send(data: Buffer | Uint8Array): void { - const lengthPrefixed = new Uint8Array(data.byteLength + 1); - lengthPrefixed[0] = data.byteLength; - lengthPrefixed.set(new Uint8Array(data), 1); - this.writer.write(lengthPrefixed); + const prefixLength = encode.number(this.lengthPrefixBuffer, data.length, { offset: 0 }); + const dataWithPrefixedLength = new Uint8Array(prefixLength + data.length); + dataWithPrefixedLength.set(this.lengthPrefixBuffer.subarray(0, prefixLength), 0); + dataWithPrefixedLength.set(data, prefixLength); + this.writer.write(dataWithPrefixedLength); } public sendUnreliable(data: Buffer | Uint8Array): void { - const lengthPrefixed = new Uint8Array(data.byteLength + 1); - lengthPrefixed[0] = data.byteLength; - lengthPrefixed.set(new Uint8Array(data), 1); - this.unreliableWriter.write(lengthPrefixed); + const prefixLength = encode.number(this.lengthPrefixBuffer, data.length, { offset: 0 }); + const dataWithPrefixedLength = new Uint8Array(prefixLength + data.length); + dataWithPrefixedLength.set(this.lengthPrefixBuffer.subarray(0, prefixLength), 0); + dataWithPrefixedLength.set(data, prefixLength); + this.unreliableWriter.write(dataWithPrefixedLength); } public close(code?: number, reason?: string) { @@ -112,17 +116,21 @@ export class H3TransportTransport implements ITransport { // QUESTION: should we buffer the message in case it's not fully read? // - const length = messages[it.offset++]; + const length = decode.number(messages, it); this.events.onmessage({ data: messages.subarray(it.offset, it.offset + length) }); it.offset += length; } while (it.offset < messages.length); } catch (e) { - console.error("failed to read incoming data", e); + if (e.message.indexOf("session is closed") === -1) { + console.error("H3Transport: failed to read incoming data", e); + } break; } - if (result.done) { break; } + if (result.done) { + break; + } } } @@ -145,20 +153,21 @@ export class H3TransportTransport implements ITransport { // QUESTION: should we buffer the message in case it's not fully read? // - const length = messages[it.offset++]; + const length = decode.number(messages, it); this.events.onmessage({ data: messages.subarray(it.offset, it.offset + length) }); it.offset += length; } while (it.offset < messages.length); } catch (e) { - console.error("failed to read incoming data", e); + if (e.message.indexOf("session is closed") === -1) { + console.error("H3Transport: failed to read incoming data", e); + } break; } - if (result.done) { break; } - - // value is a Uint8Array. - this.events.onmessage({ data: result.value.buffer }); + if (result.done) { + break; + } } } From d504d6d272e572c871c8d7174bfe8c618cea2400 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Wed, 20 Nov 2024 13:44:19 -0300 Subject: [PATCH 34/38] use vitest --- package-lock.json | 1285 ++++++++++++++++++++- package.json | 9 +- test/{auth_test.ts => auth.test.ts} | 9 +- test/{client_test.ts => client.test.ts} | 29 +- test/{http_test.ts => http.test.ts} | 10 +- test/{room_test.ts => room.test.ts} | 23 +- test/{storage_test.ts => storage.test.ts} | 3 +- 7 files changed, 1311 insertions(+), 57 deletions(-) rename test/{auth_test.ts => auth.test.ts} (84%) rename test/{client_test.ts => client.test.ts} (83%) rename test/{http_test.ts => http.test.ts} (56%) rename test/{room_test.ts => room.test.ts} (84%) rename test/{storage_test.ts => storage.test.ts} (83%) diff --git a/package-lock.json b/package-lock.json index a76e5ab..7ffce2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,16 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.15", + "version": "0.16.0-preview.21", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "colyseus.js", - "version": "0.16.0-preview.15", + "version": "0.16.0-preview.21", "license": "MIT", "dependencies": { "@colyseus/msgpackr": "^1.10.5", - "@colyseus/schema": "^3.0.0-alpha.19", + "@colyseus/schema": "^3.0.0-alpha.36", "httpie": "^2.0.0-next.13", "tslib": "^2.1.0", "ws": "^8.13.0" @@ -36,7 +36,8 @@ "ts-loader": "^6.2.1", "ts-node": "^6.0.3", "tslint": "^5.9.1", - "typescript": "^5.3.3" + "typescript": "^5.3.3", + "vitest": "^2.1.1" }, "engines": { "node": ">= 12.x" @@ -91,13 +92,388 @@ } }, "node_modules/@colyseus/schema": { - "version": "3.0.0-alpha.19", - "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.19.tgz", - "integrity": "sha512-bs99kqqm6rmHJKqBKQAyM+fRweCCIph2w+3WUG4zVOPbbHlHupqdqgkoGNSVR8B4KrlSsk8RmAbrn0rexmakWw==", + "version": "3.0.0-alpha.36", + "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.0-alpha.36.tgz", + "integrity": "sha512-5hiuNYNy3RwNsDtwnzEVb6QKSCBBMDLxqOxy9WMK/yUiAL2uoljd8iQdLetM1SjmD9HVu3qvsJ3y9Z4kLtRcZA==", "bin": { - "schema-codegen": "bin/schema-codegen" + "schema-codegen": "bin/schema-codegen", + "schema-debug": "bin/schema-debug" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", @@ -212,6 +588,214 @@ "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", "dev": true }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.3.tgz", + "integrity": "sha512-MmKSfaB9GX+zXl6E8z4koOr/xU63AMVleLEa64v7R0QF/ZloMs5vcD1sHgM64GXXS1csaJutG+ddtzcueI/BLg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.3.tgz", + "integrity": "sha512-zrt8ecH07PE3sB4jPOggweBjJMzI1JG5xI2DIsUbkA+7K+Gkjys6eV7i9pOenNSDJH3eOr/jLb/PzqtmdwDq5g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.3.tgz", + "integrity": "sha512-P0UxIOrKNBFTQaXTxOH4RxuEBVCgEA5UTNV6Yz7z9QHnUJ7eLX9reOd/NYMO3+XZO2cco19mXTxDMXxit4R/eQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.3.tgz", + "integrity": "sha512-L1M0vKGO5ASKntqtsFEjTq/fD91vAqnzeaF6sfNAy55aD+Hi2pBI5DKwCO+UNDQHWsDViJLqshxOahXyLSh3EA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.3.tgz", + "integrity": "sha512-btVgIsCjuYFKUjopPoWiDqmoUXQDiW2A4C3Mtmp5vACm7/GnyuprqIDPNczeyR5W8rTXEbkmrJux7cJmD99D2g==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.3.tgz", + "integrity": "sha512-zmjbSphplZlau6ZTkxd3+NMtE4UKVy7U4aVFMmHcgO5CUbw17ZP6QCgyxhzGaU/wFFdTfiojjbLG3/0p9HhAqA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.3.tgz", + "integrity": "sha512-nSZfcZtAnQPRZmUkUQwZq2OjQciR6tEoJaZVFvLHsj0MF6QhNMg0fQ6mUOsiCUpTqxTx0/O6gX0V/nYc7LrgPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.3.tgz", + "integrity": "sha512-MnvSPGO8KJXIMGlQDYfvYS3IosFN2rKsvxRpPO2l2cum+Z3exiExLwVU+GExL96pn8IP+GdH8Tz70EpBhO0sIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.3.tgz", + "integrity": "sha512-+W+p/9QNDr2vE2AXU0qIy0qQE75E8RTwTwgqS2G5CRQ11vzq0tbnfBd6brWhS9bCRjAjepJe2fvvkvS3dno+iw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.3.tgz", + "integrity": "sha512-yXH6K6KfqGXaxHrtr+Uoy+JpNlUlI46BKVyonGiaD74ravdnF9BUNC+vV+SIuB96hUMGShhKV693rF9QDfO6nQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.3.tgz", + "integrity": "sha512-R8cwY9wcnApN/KDYWTH4gV/ypvy9yZUHlbJvfaiXSB48JO3KpwSpjOGqO4jnGkLDSk1hgjYkTbTt6Q7uvPf8eg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.3.tgz", + "integrity": "sha512-kZPbX/NOPh0vhS5sI+dR8L1bU2cSO9FgxwM8r7wHzGydzfSjLRCFAT87GR5U9scj2rhzN3JPYVC7NoBbl4FZ0g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.3.tgz", + "integrity": "sha512-S0Yq+xA1VEH66uiMNhijsWAafffydd2X5b77eLHfRmfLsRSpbiAWiRHV6DEpz6aOToPsgid7TI9rGd6zB1rhbg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.3.tgz", + "integrity": "sha512-9isNzeL34yquCPyerog+IMCNxKR8XYmGd0tHSV+OVx0TmE0aJOo9uw4fZfUuk2qxobP5sug6vNdZR6u7Mw7Q+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.3.tgz", + "integrity": "sha512-nMIdKnfZfzn1Vsk+RuOvl43ONTZXoAPUUxgcU0tXooqg4YrAqzfKzVenqqk2g5efWh46/D28cKFrOzDSW28gTA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.3.tgz", + "integrity": "sha512-fOvu7PCQjAj4eWDEuD8Xz5gpzFqXzGlxHZozHP4b9Jxv9APtdxL6STqztDzMLuRXEc4UpXGGhx029Xgm91QBeA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@types/chai": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-3.5.2.tgz", @@ -254,7 +838,181 @@ "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", "dev": true, "dependencies": { - "@types/node": "*" + "@types/node": "*" + } + }, + "node_modules/@vitest/expect": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.1.tgz", + "integrity": "sha512-YeueunS0HiHiQxk+KEOnq/QMzlUuOzbU1Go+PgAsHvvv3tUkJPm9xWt+6ITNTlzsMXUjmgm5T+U7KBPK2qQV6w==", + "dev": true, + "dependencies": { + "@vitest/spy": "2.1.1", + "@vitest/utils": "2.1.1", + "chai": "^5.1.1", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/expect/node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@vitest/expect/node_modules/chai": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", + "integrity": "sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==", + "dev": true, + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@vitest/expect/node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@vitest/mocker": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.1.tgz", + "integrity": "sha512-LNN5VwOEdJqCmJ/2XJBywB11DLlkbY0ooDJW3uRX5cZyYCrc4PI/ePX0iQhE3BiEGiQmK4GE7Q/PqCkkaiPnrA==", + "dev": true, + "dependencies": { + "@vitest/spy": "^2.1.0-beta.1", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.11" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/spy": "2.1.1", + "msw": "^2.3.5", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/mocker/node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/@vitest/mocker/node_modules/magic-string": { + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.1.tgz", + "integrity": "sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ==", + "dev": true, + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.1.tgz", + "integrity": "sha512-uTPuY6PWOYitIkLPidaY5L3t0JJITdGTSwBtwMjKzo5O6RCOEncz9PUN+0pDidX8kTHYjO0EwUIvhlGpnGpxmA==", + "dev": true, + "dependencies": { + "@vitest/utils": "2.1.1", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.1.tgz", + "integrity": "sha512-BnSku1WFy7r4mm96ha2FzN99AZJgpZOWrAhtQfoxjUU5YMRpq1zmHRq7a5K9/NjqonebO7iVDla+VvZS8BOWMw==", + "dev": true, + "dependencies": { + "@vitest/pretty-format": "2.1.1", + "magic-string": "^0.30.11", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot/node_modules/magic-string": { + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/@vitest/spy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.1.tgz", + "integrity": "sha512-ZM39BnZ9t/xZ/nF4UwRH5il0Sw93QnZXd9NAZGRpIgj0yvVwPpLd702s/Cx955rGaMlyBQkZJ2Ir7qyY48VZ+g==", + "dev": true, + "dependencies": { + "tinyspy": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.1.tgz", + "integrity": "sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==", + "dev": true, + "dependencies": { + "@vitest/pretty-format": "2.1.1", + "loupe": "^3.1.1", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, "node_modules/ansi-regex": { @@ -376,6 +1134,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/chai": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", @@ -404,6 +1171,15 @@ "node": ">=4" } }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "engines": { + "node": ">= 16" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -571,6 +1347,44 @@ "errno": "cli.js" } }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, "node_modules/escalade": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", @@ -658,6 +1472,15 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -878,6 +1701,15 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/loupe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz", + "integrity": "sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, "node_modules/magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -3589,7 +4421,7 @@ }, "node_modules/npm/node_modules/lodash._baseindexof": { "version": "3.1.0", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT" }, @@ -3605,19 +4437,19 @@ }, "node_modules/npm/node_modules/lodash._bindcallback": { "version": "3.0.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/lodash._cacheindexof": { "version": "3.0.2", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/lodash._createcache": { "version": "3.1.2", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -3632,7 +4464,7 @@ }, "node_modules/npm/node_modules/lodash._getnative": { "version": "3.9.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT" }, @@ -3650,7 +4482,7 @@ }, "node_modules/npm/node_modules/lodash.restparam": { "version": "3.6.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT" }, @@ -5891,10 +6723,25 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/pathval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "dev": true, + "engines": { + "node": ">= 14.16" + } + }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", "dev": true }, "node_modules/picomatch": { @@ -5915,6 +6762,52 @@ "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", "dev": true }, + "node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -6040,6 +6933,12 @@ "semver": "bin/semver.js" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -6067,6 +6966,15 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -6090,6 +6998,18 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, + "node_modules/std-env": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", + "dev": true + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -6158,6 +7078,45 @@ "node": ">=6" } }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true + }, + "node_modules/tinyexec": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.0.tgz", + "integrity": "sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==", + "dev": true + }, + "node_modules/tinypool": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.1.tgz", + "integrity": "sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA==", + "dev": true, + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -6340,6 +7299,296 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/vite": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.6.tgz", + "integrity": "sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==", + "dev": true, + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.1.tgz", + "integrity": "sha512-N/mGckI1suG/5wQI35XeR9rsMsPqKXzq1CdUndzVstBj/HvyxxGctwnK6WX43NGt5L3Z5tcRf83g4TITKJhPrA==", + "dev": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.6", + "pathe": "^1.1.2", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite-node/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/vite-node/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/vite/node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/vite/node_modules/rollup": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.3.tgz", + "integrity": "sha512-7sqRtBNnEbcBtMeRVc6VRsJMmpI+JU1z9VTvW8D4gXIYQFz0aLcsE6rRkyghZkLfEgUZgVvOG7A5CVz/VW5GIA==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.21.3", + "@rollup/rollup-android-arm64": "4.21.3", + "@rollup/rollup-darwin-arm64": "4.21.3", + "@rollup/rollup-darwin-x64": "4.21.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.21.3", + "@rollup/rollup-linux-arm-musleabihf": "4.21.3", + "@rollup/rollup-linux-arm64-gnu": "4.21.3", + "@rollup/rollup-linux-arm64-musl": "4.21.3", + "@rollup/rollup-linux-powerpc64le-gnu": "4.21.3", + "@rollup/rollup-linux-riscv64-gnu": "4.21.3", + "@rollup/rollup-linux-s390x-gnu": "4.21.3", + "@rollup/rollup-linux-x64-gnu": "4.21.3", + "@rollup/rollup-linux-x64-musl": "4.21.3", + "@rollup/rollup-win32-arm64-msvc": "4.21.3", + "@rollup/rollup-win32-ia32-msvc": "4.21.3", + "@rollup/rollup-win32-x64-msvc": "4.21.3", + "fsevents": "~2.3.2" + } + }, + "node_modules/vitest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.1.tgz", + "integrity": "sha512-97We7/VC0e9X5zBVkvt7SGQMGrRtn3KtySFQG5fpaMlS+l62eeXRQO633AYhSTC3z7IMebnPPNjGXVGNRFlxBA==", + "dev": true, + "dependencies": { + "@vitest/expect": "2.1.1", + "@vitest/mocker": "2.1.1", + "@vitest/pretty-format": "^2.1.1", + "@vitest/runner": "2.1.1", + "@vitest/snapshot": "2.1.1", + "@vitest/spy": "2.1.1", + "@vitest/utils": "2.1.1", + "chai": "^5.1.1", + "debug": "^4.3.6", + "magic-string": "^0.30.11", + "pathe": "^1.1.2", + "std-env": "^3.7.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.0", + "tinypool": "^1.0.0", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.1", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.1", + "@vitest/ui": "2.1.1", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/chai": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", + "integrity": "sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==", + "dev": true, + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/vitest/node_modules/magic-string": { + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/vitest/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index cf967db..d289b3f 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.21", + "version": "0.16.0-preview.22", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", "scripts": { - "test": "mocha test/*.ts --require ts-node/register", + "test": "vitest --dir test", "build": "rollup -c rollup.config.js", "build-dist-dts": "dts-bundle-generator --config dts-generator.json", "build-ci": "tsc && npm run build && npm run build-dist-dts && npm run build-zip-dist", @@ -59,7 +59,7 @@ }, "dependencies": { "@colyseus/msgpackr": "^1.10.5", - "@colyseus/schema": "^3.0.0-alpha.19", + "@colyseus/schema": "^3.0.0-alpha.36", "httpie": "^2.0.0-next.13", "tslib": "^2.1.0", "ws": "^8.13.0" @@ -85,6 +85,7 @@ "ts-loader": "^6.2.1", "ts-node": "^6.0.3", "tslint": "^5.9.1", - "typescript": "^5.3.3" + "typescript": "^5.3.3", + "vitest": "^2.1.1" } } diff --git a/test/auth_test.ts b/test/auth.test.ts similarity index 84% rename from test/auth_test.ts rename to test/auth.test.ts index 44d5675..11af25d 100644 --- a/test/auth_test.ts +++ b/test/auth.test.ts @@ -1,4 +1,5 @@ import './util'; +import { describe, beforeAll, test } from "vitest"; import assert from "assert"; import { Client, Room } from "../src"; import { AuthData } from '../src/Auth'; @@ -6,18 +7,18 @@ import { AuthData } from '../src/Auth'; describe("Auth", function() { let client: Client; - before(() => { + beforeAll(() => { client = new Client("ws://localhost:2546"); }); describe("store token", () => { - it("should store token on localStorage", () => { + test("should store token on localStorage", () => { client.auth['emitChange']({ user: {}, token: "123" }); assert.strictEqual("123", client.auth.token); assert.strictEqual("123", window.localStorage.getItem(client.auth.settings.key)); }); - it("should reject if no token is stored", async () => { + test("should reject if no token is stored", async () => { // @ts-ignore client.auth.token = undefined; @@ -29,7 +30,7 @@ describe("Auth", function() { }); describe("onChange", () => { - it("should trigger onChange when token is set", () => { + test("should trigger onChange when token is set", () => { let onChangePayload: AuthData | undefined = undefined; client.auth.onChange((data) => onChangePayload = data); client.auth['emitChange']({ user: { dummy: true }, token: "123" }); diff --git a/test/client_test.ts b/test/client.test.ts similarity index 83% rename from test/client_test.ts rename to test/client.test.ts index 1f4122b..4815952 100644 --- a/test/client_test.ts +++ b/test/client.test.ts @@ -1,4 +1,5 @@ import './util'; +import { describe, beforeAll, test } from "vitest"; import { assert } from "chai"; import { Client } from "../src"; import { Schema, type } from '@colyseus/schema'; @@ -7,12 +8,12 @@ import { discordURLBuilder } from '../src/3rd_party/discord'; describe("Client", function () { let client: Client; - before(() => { + beforeAll(() => { client = new Client("ws://localhost:2546"); }) describe("constructor settings", () => { - it("url string", () => { + test("url string", () => { const room = { roomId: "roomId", processId: "processId", sessionId: "sessionId", }; const roomWithPublicAddress = { publicAddress: "node-1.colyseus.cloud", roomId: "roomId", processId: "processId", sessionId: "sessionId", }; @@ -70,25 +71,25 @@ describe("Client", function () { } }); - it("discord url builder", () => { + test("discord url builder", () => { const room = { roomId: "roomId", processId: "processId", sessionId: "sessionId", }; const roomWithPublicAddress = { publicAddress: "node-1.colyseus.cloud", roomId: "roomId", processId: "processId", sessionId: "sessionId", }; const settingsByUrl = { 'ws://example.com': { - httpEndpoint: "http://localhost/colyseus/", - wsEndpoint: "ws://localhost/colyseus/processId/roomId", - wsEndpointPublicAddress: "ws://localhost/colyseus/node-1/processId/roomId" + httpEndpoint: "http://localhost/.proxy/colyseus/", + wsEndpoint: "ws://localhost/.proxy/colyseus/processId/roomId", + wsEndpointPublicAddress: "ws://localhost/.proxy/colyseus/node-1/processId/roomId" }, 'ws://subdomain.colyseus.cloud': { - httpEndpoint: "http://localhost/colyseus/subdomain/", - wsEndpoint: "ws://localhost/colyseus/subdomain/processId/roomId", - wsEndpointPublicAddress: "ws://localhost/colyseus/node-1/processId/roomId" + httpEndpoint: "http://localhost/.proxy/colyseus/subdomain/", + wsEndpoint: "ws://localhost/.proxy/colyseus/subdomain/processId/roomId", + wsEndpointPublicAddress: "ws://localhost/.proxy/colyseus/node-1/processId/roomId" }, 'https://subdomain.colyseus.cloud/custom/path': { - httpEndpoint: "https://localhost/colyseus/subdomain/custom/path/", - wsEndpoint: "wss://localhost/colyseus/subdomain/custom/path/processId/roomId", - wsEndpointPublicAddress: "wss://localhost/colyseus/node-1/processId/roomId" + httpEndpoint: "https://localhost/.proxy/colyseus/subdomain/custom/path/", + wsEndpoint: "wss://localhost/.proxy/colyseus/subdomain/custom/path/processId/roomId", + wsEndpointPublicAddress: "wss://localhost/.proxy/colyseus/node-1/processId/roomId" }, // '/api': { // httpEndpoint: "http://127.0.0.1:2567/api/", @@ -107,13 +108,13 @@ describe("Client", function () { }); }); - xit("join", function () { + test.skip("join", function () { const room = client.join("chat"); // assert.equal(room.name, "chat") // assert.deepEqual(room.state, {}) }); - xit("should allow to pass a Schema constructor as third argument", async () => { + test.skip("should allow to pass a Schema constructor as third argument", async () => { class State extends Schema { @type("string") str: string; } diff --git a/test/http_test.ts b/test/http.test.ts similarity index 56% rename from test/http_test.ts rename to test/http.test.ts index c09380b..10dfaa5 100644 --- a/test/http_test.ts +++ b/test/http.test.ts @@ -1,21 +1,21 @@ import './util'; +import { describe, beforeAll, test } from "vitest"; import assert from "assert"; -import { Client, Room } from "../src"; +import { Client } from "../src"; describe("HTTP", function() { let client: Client; - before(() => { + beforeAll(() => { client = new Client("ws://localhost:4545"); }); describe("errors", () => { - it("should return 'offline' error when requesting offline service", async () => { + test("should return 'offline' error when requesting offline service", async () => { try { await client.http.post("/anything"); } catch (e) { - console.log({code: e.code, message: e.message}); - console.log(e); + assert.strictEqual(e.code, 'ECONNREFUSED') } }); }); diff --git a/test/room_test.ts b/test/room.test.ts similarity index 84% rename from test/room_test.ts rename to test/room.test.ts index be581d0..458b871 100644 --- a/test/room_test.ts +++ b/test/room.test.ts @@ -1,4 +1,5 @@ import './util'; +import { describe, beforeEach, test } from "vitest"; import { assert } from "chai"; import { Room } from "../src"; @@ -11,7 +12,7 @@ describe("Room", function() { let room: Room = null; describe("onMessage / dispatchMessage", () => { - it("* should handle if message is not registered", (done) => { + test("* should handle if message is not registered", () => new Promise((done) => { room = new Room("chat"); room.onMessage("*", (type, message) => { @@ -24,34 +25,34 @@ describe("Room", function() { room['dispatchMessage']("type", 5); room['dispatchMessage']("something", 1); - }); + })); - it("should handle string message types", (done) => { + test("should handle string message types", () => new Promise((done) => { room = new Room("chat"); room.onMessage("type", (message) => { assert.equal(5, message); done(); }); room['dispatchMessage']("type", 5); - }); + })); - it("should handle number message types", (done) => { + test("should handle number message types", () => new Promise((done) => { room = new Room("chat"); room.onMessage(0, (message) => { assert.equal(5, message); done(); }); room['dispatchMessage'](0, 5); - }); + })); - it("should handle number message types", (done) => { + test("should handle number message types", () => new Promise((done) => { room = new Room("chat"); room.onMessage(0, (message) => { assert.equal(5, message); done(); }); room['dispatchMessage'](0, 5); - }); + })); }); @@ -64,12 +65,12 @@ describe("Room", function() { (room as any).serializer = new FossilDeltaSerializer(); }); - it("should initialize room with empty state", function() { + test("should initialize room with empty state", function() { assert.equal(room.name, "chat") assert.deepEqual(room.state, {}) }); - it("should emit state change", function(done) { + test("should emit state change", function(done) { room.onStateChange((data) => { assert.deepEqual(data.messages, []); done(); @@ -78,7 +79,7 @@ describe("Room", function() { (room).setState(msgpack.encode({ messages: [] }), 0, 0); }) - it("should patch room state", function(done) { + test("should patch room state", function(done) { let state = { players: { 'one': { hp: 100, lvl: 1, position: {x: 0, y: 0} }, diff --git a/test/storage_test.ts b/test/storage.test.ts similarity index 83% rename from test/storage_test.ts rename to test/storage.test.ts index 9ff365e..1be5d1f 100644 --- a/test/storage_test.ts +++ b/test/storage.test.ts @@ -1,10 +1,11 @@ import './util'; +import { describe, test } from "vitest"; import assert from "assert"; import { setItem, getItem } from "../src/Storage"; describe("Storage", function() { - it("get and set", () => { + test("get and set", () => { setItem("test", "test"); let getCalled = false; From 3817a0d28018f5cc81a80b3a88946b5672cb70b6 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Wed, 20 Nov 2024 13:45:15 -0300 Subject: [PATCH 35/38] upgrade @colyseus/schema --- src/serializer/SchemaSerializer.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/serializer/SchemaSerializer.ts b/src/serializer/SchemaSerializer.ts index e769cd1..b8b122b 100644 --- a/src/serializer/SchemaSerializer.ts +++ b/src/serializer/SchemaSerializer.ts @@ -31,16 +31,16 @@ export class SchemaSerializer implements Serializer { handshake(bytes: Buffer, it?: Iterator) { if (this.state) { // - // TODO: - // validate definitions against concreate this.state instance + // TODO: validate definitions against concreate this.state instance // - Reflection.decode(bytes, it); + Reflection.decode(bytes, it); // no-op + + this.decoder = new Decoder(this.state); } else { // initialize reflected state from server - this.state = Reflection.decode(bytes, it) as any; + this.decoder = Reflection.decode(bytes, it); + this.state = this.decoder.state; } - - this.decoder = new Decoder(this.state); } } From 2e9c8c94768d5e7e6c13449f0d5697d5cadde29e Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Wed, 20 Nov 2024 14:24:11 -0300 Subject: [PATCH 36/38] inject package version on Client.VERSION --- package-lock.json | 95 +++++++++++++++++++++++++++++++++++++++-------- package.json | 3 +- rollup.config.js | 13 ++++++- src/Client.ts | 2 + 4 files changed, 95 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7ffce2a..e419b7c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.21", + "version": "0.16.0-preview.22", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "colyseus.js", - "version": "0.16.0-preview.21", + "version": "0.16.0-preview.22", "license": "MIT", "dependencies": { "@colyseus/msgpackr": "^1.10.5", @@ -19,13 +19,14 @@ "@rollup/plugin-alias": "^3.1.2", "@rollup/plugin-commonjs": "^17.1.0", "@rollup/plugin-node-resolve": "^11.2.0", + "@rollup/plugin-replace": "^6.0.1", "@rollup/plugin-typescript": "^8.2.5", "@types/chai": "^3.4.34", "@types/mocha": "^2.2.44", "@types/ws": "^7.4.0", "benchmark": "^2.1.4", "chai": "^3.5.0", - "dts-bundle-generator": "^6.9.0", + "dts-bundle-generator": "^9.5.1", "install": "^0.12.2", "mocha": "^5.1.1", "nanoid": "^2.0.1", @@ -542,6 +543,76 @@ "rollup": "^1.20.0||^2.0.0" } }, + "node_modules/@rollup/plugin-replace": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.1.tgz", + "integrity": "sha512-2sPh9b73dj5IxuMmDAsQWVFT7mR+yoHweBaXG2W/R8vQ+IWZlnaI7BR7J6EguVQUp1hd8Z7XuozpDjEKQAAC2Q==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace/node_modules/@rollup/pluginutils": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", + "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace/node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, + "node_modules/@rollup/plugin-replace/node_modules/magic-string": { + "version": "0.30.13", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.13.tgz", + "integrity": "sha512-8rYBO+MsWkgjDSOvLomYnzhdwEG51olQ4zL5KXnNJWV5MNmrb4rTZdrtkhxjnD/QyZUqR/Z/XDsUs/4ej2nx0g==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/@rollup/plugin-replace/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@rollup/plugin-typescript": { "version": "8.5.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.5.0.tgz", @@ -1291,19 +1362,19 @@ } }, "node_modules/dts-bundle-generator": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/dts-bundle-generator/-/dts-bundle-generator-6.13.0.tgz", - "integrity": "sha512-v4mXZ08dnKO4RKUW2x4DNrb1cJyvtmxAzreV/zF1CZIXMKfe8GrQg6JDmTcikrK05/LMkdMuUrDe8N6w+6krsw==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/dts-bundle-generator/-/dts-bundle-generator-9.5.1.tgz", + "integrity": "sha512-DxpJOb2FNnEyOzMkG11sxO2dmxPjthoVWxfKqWYJ/bI/rT1rvTMktF5EKjAYrRZu6Z6t3NhOUZ0sZ5ZXevOfbA==", "dev": true, "dependencies": { - "typescript": ">=3.0.1", - "yargs": "^17.2.1" + "typescript": ">=5.0.2", + "yargs": "^17.6.0" }, "bin": { "dts-bundle-generator": "dist/bin/dts-bundle-generator.js" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/emoji-regex": { @@ -4421,7 +4492,6 @@ }, "node_modules/npm/node_modules/lodash._baseindexof": { "version": "3.1.0", - "extraneous": true, "inBundle": true, "license": "MIT" }, @@ -4437,19 +4507,16 @@ }, "node_modules/npm/node_modules/lodash._bindcallback": { "version": "3.0.1", - "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/lodash._cacheindexof": { "version": "3.0.2", - "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/lodash._createcache": { "version": "3.1.2", - "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -4464,7 +4531,6 @@ }, "node_modules/npm/node_modules/lodash._getnative": { "version": "3.9.1", - "extraneous": true, "inBundle": true, "license": "MIT" }, @@ -4482,7 +4548,6 @@ }, "node_modules/npm/node_modules/lodash.restparam": { "version": "3.6.1", - "extraneous": true, "inBundle": true, "license": "MIT" }, diff --git a/package.json b/package.json index d289b3f..7d383da 100644 --- a/package.json +++ b/package.json @@ -68,13 +68,14 @@ "@rollup/plugin-alias": "^3.1.2", "@rollup/plugin-commonjs": "^17.1.0", "@rollup/plugin-node-resolve": "^11.2.0", + "@rollup/plugin-replace": "^6.0.1", "@rollup/plugin-typescript": "^8.2.5", "@types/chai": "^3.4.34", "@types/mocha": "^2.2.44", "@types/ws": "^7.4.0", "benchmark": "^2.1.4", "chai": "^3.5.0", - "dts-bundle-generator": "^6.9.0", + "dts-bundle-generator": "^9.5.1", "install": "^0.12.2", "mocha": "^5.1.1", "nanoid": "^2.0.1", diff --git a/rollup.config.js b/rollup.config.js index abf69ea..39f6fab 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -2,6 +2,7 @@ import typescript from '@rollup/plugin-typescript'; import commonjs from '@rollup/plugin-commonjs'; import { nodeResolve } from '@rollup/plugin-node-resolve'; import alias from '@rollup/plugin-alias'; +import replace from '@rollup/plugin-replace'; import pkg from "./package.json"; import schemapkg from "./node_modules/@colyseus/schema/package.json"; @@ -11,6 +12,10 @@ const external = Object.keys(pkg.dependencies); const banner = `// colyseus.js@${pkg.version}`; const bannerStatic = `// colyseus.js@${pkg.version} (@colyseus/schema ${schemapkg.version})`; +const replacePlugin = replace({ + 'process.env.VERSION': JSON.stringify(pkg.version), +}); + export default [ // https://github.com/microsoft/TypeScript/issues/18442#issuecomment-749896695 @@ -20,7 +25,8 @@ export default [ output: [{ banner, dir: 'build/esm', format: 'esm', entryFileNames: '[name].mjs', sourcemap: true },], external, plugins: [ - typescript({ tsconfig: './tsconfig/tsconfig.esm.json' }) + replacePlugin, + typescript({ tsconfig: './tsconfig/tsconfig.esm.json' }), ], }, @@ -30,7 +36,8 @@ export default [ output: [{ banner, dir: 'build/cjs', format: 'cjs', entryFileNames: '[name].js', sourcemap: true },], external, plugins: [ - typescript({ tsconfig: './tsconfig/tsconfig.cjs.json' }) + replacePlugin, + typescript({ tsconfig: './tsconfig/tsconfig.cjs.json' }), ], }, @@ -50,6 +57,7 @@ export default [ }, ], plugins: [ + replacePlugin, typescript({ tsconfig: './tsconfig/tsconfig.cjs.json' }), alias({ entries: [ @@ -84,6 +92,7 @@ export default [ }, ], plugins: [ + replacePlugin, typescript({ tsconfig: './tsconfig/tsconfig.cjs.json' }), alias({ entries: [ diff --git a/src/Client.ts b/src/Client.ts index 94a8713..b44e440 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -31,6 +31,8 @@ export interface EndpointSettings { } export class Client { + static VERSION = process.env.VERSION; + public http: HTTP; public auth: Auth; From fde8a42ad0c7495c69d6d842fb69ac6c440421c5 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Wed, 20 Nov 2024 14:25:46 -0300 Subject: [PATCH 37/38] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7d383da..ad8957d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.22", + "version": "0.16.0-preview.23", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", From 89eb9cc85888847308cc582907020f94a5e9c2f3 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Thu, 21 Nov 2024 18:01:31 -0300 Subject: [PATCH 38/38] use build/cjs for browser. bump version --- LICENSE | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index cf4b924..42aeef0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015-2016 Endel Dreyer +Copyright (c) 2015-2024 Endel Dreyer MIT License: diff --git a/package.json b/package.json index ad8957d..f199cec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.16.0-preview.23", + "version": "0.16.0-preview.24", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", @@ -31,7 +31,7 @@ "typings": "lib/index.d.ts", "exports": { ".": { - "browser": "./lib/index.js", + "browser": "./build/cjs/index.js", "import": "./build/esm/index.mjs", "require": "./build/cjs/index.js", "types": "./lib/index.d.ts"