@colyseus/core 0.17.52 → 0.17.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/Room.cjs +1 -1
- package/build/Room.cjs.map +2 -2
- package/build/Room.mjs +1 -1
- package/build/Room.mjs.map +2 -2
- package/build/Transport.cjs.map +2 -2
- package/build/Transport.d.ts +11 -0
- package/build/Transport.mjs.map +2 -2
- package/build/matchmaker/LocalDriver/Query.cjs +5 -5
- package/build/matchmaker/LocalDriver/Query.cjs.map +2 -2
- package/build/matchmaker/LocalDriver/Query.mjs +5 -5
- package/build/matchmaker/LocalDriver/Query.mjs.map +2 -2
- package/build/matchmaker/RegisteredHandler.cjs +1 -1
- package/build/matchmaker/RegisteredHandler.cjs.map +2 -2
- package/build/matchmaker/RegisteredHandler.mjs +1 -1
- package/build/matchmaker/RegisteredHandler.mjs.map +2 -2
- package/build/serializer/SchemaSerializer.cjs +25 -9
- package/build/serializer/SchemaSerializer.cjs.map +2 -2
- package/build/serializer/SchemaSerializer.d.ts +10 -0
- package/build/serializer/SchemaSerializer.mjs +25 -9
- package/build/serializer/SchemaSerializer.mjs.map +2 -2
- package/build/utils/Utils.cjs +1 -1
- package/build/utils/Utils.cjs.map +2 -2
- package/build/utils/Utils.mjs +1 -1
- package/build/utils/Utils.mjs.map +2 -2
- package/package.json +8 -8
- package/src/Room.ts +2 -1
- package/src/Transport.ts +11 -0
- package/src/matchmaker/LocalDriver/Query.ts +5 -5
- package/src/matchmaker/RegisteredHandler.ts +1 -1
- package/src/serializer/SchemaSerializer.ts +27 -9
- package/src/utils/Utils.ts +2 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/Utils.ts"],
|
|
4
|
-
"sourcesContent": ["import { nanoid } from 'nanoid';\nimport { type RoomException, type RoomMethodName } from '../errors/RoomExceptions.ts';\n\nimport { debugAndPrintError, debugMatchMaking } from '../Debug.ts';\n\nexport type Type<T> = new (...args: any[]) => T;\nexport type MethodName<T> = string & {\n [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never\n}[keyof T];\n\n/**\n * Utility type that extracts the return type of a method or the type of a property\n * from a given class/object type.\n *\n * - If the key is a method, returns the awaited return type of that method\n * - If the key is a property, returns the type of that property\n */\nexport type ExtractMethodOrPropertyType<\n TClass,\n TKey extends keyof TClass\n> = TClass[TKey] extends (...args: any[]) => infer R\n ? Awaited<R>\n : TClass[TKey];\n\n/**\n * Return type of `remoteRoomCall()`.\n *\n * Resolves to the method's awaited return type (or the property's type) when\n * the method name was captured as a literal type. Falls back to `any` when it\n * wasn't \u2014 e.g. `remoteRoomCall<MyRoom>(...)` with only the room type given:\n * TypeScript applies the `TMethod` default instead of inferring the literal\n * once an explicit type argument list is present (microsoft/TypeScript#26242).\n * Pass both type arguments (`remoteRoomCall<MyRoom, 'myMethod'>`) for a\n * precise return type.\n */\nexport type RemoteRoomCallReturn<\n TRoom,\n TMethod extends keyof TRoom\n> = keyof TRoom extends TMethod\n ? any\n : ExtractMethodOrPropertyType<TRoom, TMethod>;\n\n// remote room call timeouts\nexport const REMOTE_ROOM_SHORT_TIMEOUT = Number(process.env.COLYSEUS_PRESENCE_SHORT_TIMEOUT || 2000);\nexport const MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME = Number(process.env.COLYSEUS_MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME || 0.5);\n\n// a peer that removes this process's room listings leaves a receipt. this\n// process looks for it every INTERVAL (ms) and restores them. the TTL (seconds)\n// only bounds what dead processes leave behind.\nexport const SWEPT_CHECK_INTERVAL = Number(process.env.COLYSEUS_SWEPT_CHECK_INTERVAL || 5000);\nexport const SWEPT_RECEIPT_TTL = Number(process.env.COLYSEUS_SWEPT_RECEIPT_TTL || 600);\n\nexport function generateId(length: number = 9) {\n return nanoid(length);\n}\n\nexport function getBearerToken(authHeader: string) {\n return (authHeader && authHeader.startsWith(\"Bearer \") && authHeader.substring(7, authHeader.length)) || undefined;\n}\n\n// nodemon sends SIGUSR2 before reloading\n// (https://github.com/remy/nodemon#controlling-shutdown-of-your-script)\n//\nconst signals: NodeJS.Signals[] = ['SIGINT', 'SIGTERM', 'SIGUSR2'];\n\nexport function registerGracefulShutdown(callback: (err?: Error) => void) {\n /**\n * Gracefully shutdown on uncaught errors\n */\n process.on('uncaughtException', (err) => {\n debugAndPrintError(err);\n callback(err);\n });\n\n signals.forEach((signal) =>\n process.once(signal, () => callback()));\n}\n\nexport function retry<T = any>(\n cb: Function,\n maxRetries: number = 3,\n errorWhiteList: any[] = [],\n retries: number = 0,\n) {\n return new Promise<T>((resolve, reject) => {\n cb()\n .then(resolve)\n .catch((e: any) => {\n if (\n errorWhiteList.indexOf(e.constructor) !== -1 &&\n retries++ < maxRetries\n ) {\n setTimeout(() => {\n debugMatchMaking(\"retrying due to error (error: %s, retries: %s, maxRetries: %s)\", e.message, retries, maxRetries);\n retry<T>(cb, maxRetries, errorWhiteList, retries).\n then(resolve).\n catch((e2) => reject(e2));\n }, Math.floor(Math.random() * Math.pow(2, retries) * 400));\n\n } else {\n reject(e);\n }\n });\n });\n}\n\nexport function spliceOne(arr: any[], index: number): boolean {\n // manually splice availableRooms array\n // http://jsperf.com/manual-splice\n if (index === -1 || index >= arr.length) {\n return false;\n }\n\n const len = arr.length - 1;\n for (let i = index; i < len; i++) {\n arr[i] = arr[i + 1];\n }\n\n arr.length = len;\n return true;\n}\n\nexport class Deferred<T = any> {\n public promise: Promise<T>;\n\n public resolve: Function;\n public reject: Function;\n\n constructor(promise?: Promise<T>) {\n this.promise = promise ?? new Promise<T>((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n\n public then(onFulfilled?: (value: T) => any, onRejected?: (reason: any) => any) {\n return this.promise.then(onFulfilled, onRejected);\n }\n\n public catch(func: (value: any) => any) {\n return this.promise.catch(func);\n }\n\n static reject (reason?: any) {\n return new Deferred(Promise.reject(reason));\n }\n\n static resolve<T = any>(value?: T) {\n return new Deferred<T>(Promise.resolve(value));\n }\n\n}\n\nexport function merge(a: any, ...objs: any[]): any {\n for (let i = 0, len = objs.length; i < len; i++) {\n const b = objs[i];\n for (const key in b) {\n if (
|
|
5
|
-
"mappings": ";;;;;;;;AAAA,SAAS,cAAc;AACvB,OAAwD;AAExD,SAAS,oBAAoB,wBAAwB;AAwC9C,IAAM,4BAA4B,OAAO,QAAQ,IAAI,mCAAmC,GAAI;AAC5F,IAAM,uCAAuC,OAAO,QAAQ,IAAI,iDAAiD,GAAG;AAKpH,IAAM,uBAAuB,OAAO,QAAQ,IAAI,iCAAiC,GAAI;AACrF,IAAM,oBAAoB,OAAO,QAAQ,IAAI,8BAA8B,GAAG;AAE9E,SAAS,WAAW,SAAiB,GAAG;AAC7C,SAAO,OAAO,MAAM;AACtB;AAEO,SAAS,eAAe,YAAoB;AACjD,SAAQ,cAAc,WAAW,WAAW,SAAS,KAAK,WAAW,UAAU,GAAG,WAAW,MAAM,KAAM;AAC3G;AAKA,IAAM,UAA4B,CAAC,UAAU,WAAW,SAAS;AAE1D,SAAS,yBAAyB,UAAiC;AAIxE,UAAQ,GAAG,qBAAqB,CAAC,QAAQ;AACvC,uBAAmB,GAAG;AACtB,aAAS,GAAG;AAAA,EACd,CAAC;AAED,UAAQ,QAAQ,CAAC,WACf,QAAQ,KAAK,QAAQ,MAAM,SAAS,CAAC,CAAC;AAC1C;AAEO,SAAS,MACd,IACA,aAAqB,GACrB,iBAAwB,CAAC,GACzB,UAAkB,GAClB;AACA,SAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AACzC,OAAG,EACA,KAAK,OAAO,EACZ,MAAM,CAAC,MAAW;AACjB,UACE,eAAe,QAAQ,EAAE,WAAW,MAAM,MAC1C,YAAY,YACZ;AACA,mBAAW,MAAM;AACf,2BAAiB,kEAAkE,EAAE,SAAS,SAAS,UAAU;AACjH,gBAAS,IAAI,YAAY,gBAAgB,OAAO,EAC9C,KAAK,OAAO,EACZ,MAAM,CAAC,OAAO,OAAO,EAAE,CAAC;AAAA,QAC5B,GAAG,KAAK,MAAM,KAAK,OAAO,IAAI,KAAK,IAAI,GAAG,OAAO,IAAI,GAAG,CAAC;AAAA,MAE3D,OAAO;AACL,eAAO,CAAC;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACL,CAAC;AACH;AAEO,SAAS,UAAU,KAAY,OAAwB;AAG5D,MAAI,UAAU,MAAM,SAAS,IAAI,QAAQ;AACvC,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,IAAI,SAAS;AACzB,WAAS,IAAI,OAAO,IAAI,KAAK,KAAK;AAChC,QAAI,CAAC,IAAI,IAAI,IAAI,CAAC;AAAA,EACpB;AAEA,MAAI,SAAS;AACb,SAAO;AACT;AAEO,IAAM,WAAN,MAAM,UAAkB;AAAA,EAM7B,YAAY,SAAsB;AAChC,SAAK,UAAU,WAAW,IAAI,QAAW,CAAC,SAAS,WAAW;AAC5D,WAAK,UAAU;AACf,WAAK,SAAS;AAAA,IAChB,CAAC;AAAA,EACH;AAAA,EAEO,KAAK,aAAiC,YAAmC;AAC9E,WAAO,KAAK,QAAQ,KAAK,aAAa,UAAU;AAAA,EAClD;AAAA,EAEO,MAAM,MAA2B;AACtC,WAAO,KAAK,QAAQ,MAAM,IAAI;AAAA,EAChC;AAAA,EAEA,OAAO,OAAQ,QAAc;AAC3B,WAAO,IAAI,UAAS,QAAQ,OAAO,MAAM,CAAC;AAAA,EAC5C;AAAA,EAEA,OAAO,QAAiB,OAAW;AACjC,WAAO,IAAI,UAAY,QAAQ,QAAQ,KAAK,CAAC;AAAA,EAC/C;AAEF;AAEO,SAAS,MAAM,MAAW,MAAkB;AACjD,WAAS,IAAI,GAAG,MAAM,KAAK,QAAQ,IAAI,KAAK,KAAK;AAC/C,UAAM,IAAI,KAAK,CAAC;AAChB,eAAW,OAAO,GAAG;
|
|
4
|
+
"sourcesContent": ["import { nanoid } from 'nanoid';\nimport { type RoomException, type RoomMethodName } from '../errors/RoomExceptions.ts';\n\nimport { debugAndPrintError, debugMatchMaking } from '../Debug.ts';\n\nexport type Type<T> = new (...args: any[]) => T;\nexport type MethodName<T> = string & {\n [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never\n}[keyof T];\n\n/**\n * Utility type that extracts the return type of a method or the type of a property\n * from a given class/object type.\n *\n * - If the key is a method, returns the awaited return type of that method\n * - If the key is a property, returns the type of that property\n */\nexport type ExtractMethodOrPropertyType<\n TClass,\n TKey extends keyof TClass\n> = TClass[TKey] extends (...args: any[]) => infer R\n ? Awaited<R>\n : TClass[TKey];\n\n/**\n * Return type of `remoteRoomCall()`.\n *\n * Resolves to the method's awaited return type (or the property's type) when\n * the method name was captured as a literal type. Falls back to `any` when it\n * wasn't \u2014 e.g. `remoteRoomCall<MyRoom>(...)` with only the room type given:\n * TypeScript applies the `TMethod` default instead of inferring the literal\n * once an explicit type argument list is present (microsoft/TypeScript#26242).\n * Pass both type arguments (`remoteRoomCall<MyRoom, 'myMethod'>`) for a\n * precise return type.\n */\nexport type RemoteRoomCallReturn<\n TRoom,\n TMethod extends keyof TRoom\n> = keyof TRoom extends TMethod\n ? any\n : ExtractMethodOrPropertyType<TRoom, TMethod>;\n\n// remote room call timeouts\nexport const REMOTE_ROOM_SHORT_TIMEOUT = Number(process.env.COLYSEUS_PRESENCE_SHORT_TIMEOUT || 2000);\nexport const MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME = Number(process.env.COLYSEUS_MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME || 0.5);\n\n// a peer that removes this process's room listings leaves a receipt. this\n// process looks for it every INTERVAL (ms) and restores them. the TTL (seconds)\n// only bounds what dead processes leave behind.\nexport const SWEPT_CHECK_INTERVAL = Number(process.env.COLYSEUS_SWEPT_CHECK_INTERVAL || 5000);\nexport const SWEPT_RECEIPT_TTL = Number(process.env.COLYSEUS_SWEPT_RECEIPT_TTL || 600);\n\nexport function generateId(length: number = 9) {\n return nanoid(length);\n}\n\nexport function getBearerToken(authHeader: string) {\n return (authHeader && authHeader.startsWith(\"Bearer \") && authHeader.substring(7, authHeader.length)) || undefined;\n}\n\n// nodemon sends SIGUSR2 before reloading\n// (https://github.com/remy/nodemon#controlling-shutdown-of-your-script)\n//\nconst signals: NodeJS.Signals[] = ['SIGINT', 'SIGTERM', 'SIGUSR2'];\n\nexport function registerGracefulShutdown(callback: (err?: Error) => void) {\n /**\n * Gracefully shutdown on uncaught errors\n */\n process.on('uncaughtException', (err) => {\n debugAndPrintError(err);\n callback(err);\n });\n\n signals.forEach((signal) =>\n process.once(signal, () => callback()));\n}\n\nexport function retry<T = any>(\n cb: Function,\n maxRetries: number = 3,\n errorWhiteList: any[] = [],\n retries: number = 0,\n) {\n return new Promise<T>((resolve, reject) => {\n cb()\n .then(resolve)\n .catch((e: any) => {\n if (\n errorWhiteList.indexOf(e.constructor) !== -1 &&\n retries++ < maxRetries\n ) {\n setTimeout(() => {\n debugMatchMaking(\"retrying due to error (error: %s, retries: %s, maxRetries: %s)\", e.message, retries, maxRetries);\n retry<T>(cb, maxRetries, errorWhiteList, retries).\n then(resolve).\n catch((e2) => reject(e2));\n }, Math.floor(Math.random() * Math.pow(2, retries) * 400));\n\n } else {\n reject(e);\n }\n });\n });\n}\n\nexport function spliceOne(arr: any[], index: number): boolean {\n // manually splice availableRooms array\n // http://jsperf.com/manual-splice\n if (index === -1 || index >= arr.length) {\n return false;\n }\n\n const len = arr.length - 1;\n for (let i = index; i < len; i++) {\n arr[i] = arr[i + 1];\n }\n\n arr.length = len;\n return true;\n}\n\nexport class Deferred<T = any> {\n public promise: Promise<T>;\n\n public resolve: Function;\n public reject: Function;\n\n constructor(promise?: Promise<T>) {\n this.promise = promise ?? new Promise<T>((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n\n public then(onFulfilled?: (value: T) => any, onRejected?: (reason: any) => any) {\n return this.promise.then(onFulfilled, onRejected);\n }\n\n public catch(func: (value: any) => any) {\n return this.promise.catch(func);\n }\n\n static reject (reason?: any) {\n return new Deferred(Promise.reject(reason));\n }\n\n static resolve<T = any>(value?: T) {\n return new Deferred<T>(Promise.resolve(value));\n }\n\n}\n\nexport function merge(a: any, ...objs: any[]): any {\n for (let i = 0, len = objs.length; i < len; i++) {\n const b = objs[i];\n for (const key in b) {\n // JSON.parse keeps \"__proto__\" as an own key: assigning it replaces a's prototype\n if (key !== \"__proto__\" && Object.hasOwn(b, key)) {\n a[key] = b[key];\n }\n }\n }\n return a;\n}\n\nexport function wrapTryCatch(\n method: Function,\n onError: (error: RoomException, methodName: RoomMethodName) => void,\n exceptionClass: Type<RoomException>,\n methodName: RoomMethodName,\n rethrow: boolean = false,\n ...additionalErrorArgs: any[]\n) {\n return (...args: any[]) => {\n try {\n const result = method(...args);\n if (typeof (result?.catch) === \"function\") {\n return result.catch((e: Error) => {\n onError(new exceptionClass(e, e.message, ...args, ...additionalErrorArgs), methodName);\n if (rethrow) { throw e; }\n });\n }\n return result;\n } catch (e: any) {\n onError(new exceptionClass(e, e.message, ...args, ...additionalErrorArgs), methodName);\n if (rethrow) { throw e; }\n }\n };\n}\n\n/**\n * Dynamically import a module using either require() or import()\n * based on the current module system (CJS vs ESM).\n *\n * This avoids double-loading packages when running in mixed ESM/CJS environments.\n * Errors are silently caught - await the promise and handle errors at usage site.\n */\nexport function dynamicImport<T = any>(moduleName: string): Promise<T> {\n // __dirname exists in CJS but not in ESM\n if (\n typeof __dirname !== 'undefined' &&\n // @ts-ignore\n typeof (Bun) === 'undefined' // prevent bun from loading CJS modules\n ) {\n // CJS context - use require()\n try {\n return Promise.resolve(require(moduleName));\n } catch (e: any) {\n // If the error is not a MODULE_NOT_FOUND error, reject with the error.\n if (e.code !== 'MODULE_NOT_FOUND') {\n return Promise.reject(e);\n }\n return Promise.resolve(undefined);\n }\n } else {\n // ESM context - use import()\n const promise = import(/* @vite-ignore */ moduleName);\n promise.catch(() => {}); // prevent unhandled rejection warnings\n return promise;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colyseus/core",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.54",
|
|
4
4
|
"description": "Multiplayer Framework for Node.js.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"input": "./src/index.ts",
|
|
@@ -46,30 +46,30 @@
|
|
|
46
46
|
"node": ">= 22.x"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
+
"@colyseus/shared-types": "^0.17.6",
|
|
49
50
|
"@colyseus/msgpackr": "^1.11.3",
|
|
50
51
|
"@colyseus/timer": "^2.0.0",
|
|
51
52
|
"@standard-schema/spec": "^1.0.0",
|
|
52
53
|
"debug": "^4.3.4",
|
|
53
54
|
"nanoid": "^3.3.11",
|
|
54
|
-
"@colyseus/
|
|
55
|
-
"@colyseus/better-call": "^1.3.1"
|
|
56
|
-
"@colyseus/greeting-banner": "^3.0.8"
|
|
55
|
+
"@colyseus/greeting-banner": "^3.0.8",
|
|
56
|
+
"@colyseus/better-call": "^1.3.1"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@colyseus/schema": "^4.0.7",
|
|
60
60
|
"express": "^5.0.0",
|
|
61
61
|
"vitest": "^3.1.1",
|
|
62
|
+
"@colyseus/redis-presence": "^0.17.9",
|
|
62
63
|
"@colyseus/tools": "^0.17.22",
|
|
63
|
-
"@colyseus/redis-
|
|
64
|
-
"@colyseus/redis-driver": "^0.17.7"
|
|
64
|
+
"@colyseus/redis-driver": "^0.17.9"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
+
"@colyseus/ws-transport": "0.17.x",
|
|
67
68
|
"@colyseus/schema": "^4.0.7",
|
|
68
69
|
"@pm2/io": "^6.1.0",
|
|
69
70
|
"express": "^4.16.0 || ^5.0.0",
|
|
70
71
|
"zod": "^4.1.12",
|
|
71
|
-
"@colyseus/better-call": "^1.3.1"
|
|
72
|
-
"@colyseus/ws-transport": "^0.17.13"
|
|
72
|
+
"@colyseus/better-call": "^1.3.1"
|
|
73
73
|
},
|
|
74
74
|
"peerDependenciesMeta": {
|
|
75
75
|
"@colyseus/ws-transport": {
|
package/src/Room.ts
CHANGED
|
@@ -678,7 +678,8 @@ export class Room<T extends RoomOptions = RoomOptions> {
|
|
|
678
678
|
|
|
679
679
|
} else {
|
|
680
680
|
for (const field in meta) {
|
|
681
|
-
|
|
681
|
+
// JSON.parse keeps "__proto__" as an own key: assigning it replaces metadata's prototype
|
|
682
|
+
if (field === "__proto__" || !Object.hasOwn(meta, field)) { continue; }
|
|
682
683
|
this._listing.metadata[field] = meta[field];
|
|
683
684
|
}
|
|
684
685
|
|
package/src/Transport.ts
CHANGED
|
@@ -132,7 +132,18 @@ export interface Client<T extends { userData?: any, auth?: any, messages?: Recor
|
|
|
132
132
|
reconnectionToken: string;
|
|
133
133
|
|
|
134
134
|
// TODO: move these to ClientPrivate
|
|
135
|
+
/**
|
|
136
|
+
* Send raw bytes over the transport's reliable channel.
|
|
137
|
+
*
|
|
138
|
+
* The transport owns `data` from this call on: it may write it later (a
|
|
139
|
+
* socket with backpressure, permessage-deflate), so callers never mutate it
|
|
140
|
+
* afterwards. The same `data` may be handed to several clients.
|
|
141
|
+
*/
|
|
135
142
|
raw(data: Uint8Array | Buffer, options?: ISendOptions, cb?: (err?: Error) => void): void;
|
|
143
|
+
/**
|
|
144
|
+
* {@link raw}, or held until the client finishes joining (or until after the
|
|
145
|
+
* next patch, with `afterNextPatch`). Owns `data` the same way {@link raw} does.
|
|
146
|
+
*/
|
|
136
147
|
enqueueRaw(data: Uint8Array | Buffer, options?: ISendOptions): void;
|
|
137
148
|
|
|
138
149
|
/**
|
|
@@ -25,7 +25,7 @@ export class Query<T extends IRoomCache> {
|
|
|
25
25
|
return rooms.sort((room1: T, room2: T) => {
|
|
26
26
|
for (const field in this.sortOptions) {
|
|
27
27
|
const direction = this.sortOptions[field];
|
|
28
|
-
if (
|
|
28
|
+
if (Object.hasOwn(room1, field)) {
|
|
29
29
|
/**
|
|
30
30
|
* IRoomCache field
|
|
31
31
|
*/
|
|
@@ -37,7 +37,7 @@ export class Query<T extends IRoomCache> {
|
|
|
37
37
|
if (room1[field] > room2[field]) { return -1; }
|
|
38
38
|
if (room1[field] < room2[field]) { return 1; }
|
|
39
39
|
}
|
|
40
|
-
} else if (room1.metadata
|
|
40
|
+
} else if (room1.metadata && Object.hasOwn(room1.metadata, field)) {
|
|
41
41
|
/**
|
|
42
42
|
* metadata field
|
|
43
43
|
*/
|
|
@@ -57,13 +57,13 @@ export class Query<T extends IRoomCache> {
|
|
|
57
57
|
private applyFilter(rooms: T[], conditions: any): T[] {
|
|
58
58
|
return rooms.filter(((room) => {
|
|
59
59
|
for (const field in conditions) {
|
|
60
|
-
if (
|
|
60
|
+
if (Object.hasOwn(conditions, field)) {
|
|
61
61
|
// Check if field exists in room (IRoomCache base fields)
|
|
62
|
-
if (
|
|
62
|
+
if (Object.hasOwn(room, field)) {
|
|
63
63
|
if (room[field] !== conditions[field]) {
|
|
64
64
|
return false;
|
|
65
65
|
}
|
|
66
|
-
} else if (room.metadata
|
|
66
|
+
} else if (room.metadata && Object.hasOwn(room.metadata, field)) {
|
|
67
67
|
// Check if field exists in metadata
|
|
68
68
|
if (room.metadata[field] !== conditions[field]) {
|
|
69
69
|
return false;
|
|
@@ -158,7 +158,7 @@ export class RegisteredHandler<
|
|
|
158
158
|
const field = String(arr[i]);
|
|
159
159
|
|
|
160
160
|
// Handle regular (non-metadata) fields
|
|
161
|
-
if (
|
|
161
|
+
if (Object.hasOwn(options, field)) {
|
|
162
162
|
if (INVALID_OPTION_KEYS.indexOf(field as any) !== -1) {
|
|
163
163
|
logger.warn(`option "${field}" has internal usage and is going to be ignored.`);
|
|
164
164
|
} else {
|
|
@@ -41,23 +41,38 @@ export class SchemaSerializer<T extends Schema> implements Serializer<T> {
|
|
|
41
41
|
public getFullState(client?: Client) {
|
|
42
42
|
if (this.needFullEncode || this.encoder.root.changes.next !== undefined) {
|
|
43
43
|
this.sharedOffsetCache = { offset: 1 };
|
|
44
|
-
|
|
44
|
+
// copy: the next full encode reuses the buffer (slice(): a pooled Buffer would pin 8KB)
|
|
45
|
+
this.fullEncodeCache = this.encoder.encodeAll(this.sharedOffsetCache, this.fullEncodeBuffer).slice();
|
|
46
|
+
this.fitFullEncodeBuffer(this.sharedOffsetCache.offset);
|
|
45
47
|
this.needFullEncode = false;
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
if (this.hasFilters && client?.view) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
this.fullEncodeBuffer
|
|
54
|
-
);
|
|
51
|
+
const it = { ...this.sharedOffsetCache };
|
|
52
|
+
const encoded = this.encoder.encodeAllView(client.view, this.sharedOffsetCache.offset, it, this.fullEncodeBuffer);
|
|
53
|
+
this.fitFullEncodeBuffer(it.offset);
|
|
54
|
+
return encoded;
|
|
55
55
|
|
|
56
56
|
} else {
|
|
57
57
|
return this.fullEncodeCache;
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Grow {@link fullEncodeBuffer} once an encode outgrew it. The encoder grows
|
|
63
|
+
* a buffer it is handed for that one encode only, so otherwise every full
|
|
64
|
+
* encode overflows again and per-view encodes read a truncated shared part.
|
|
65
|
+
*
|
|
66
|
+
* `byteLength` is the iterator's final offset, not the returned length:
|
|
67
|
+
* before @colyseus/schema 4.0.27, a per-view encode that overflows returns
|
|
68
|
+
* its bytes cut short at the old buffer size.
|
|
69
|
+
*/
|
|
70
|
+
protected fitFullEncodeBuffer(byteLength: number) {
|
|
71
|
+
if (byteLength <= this.fullEncodeBuffer.byteLength) { return; }
|
|
72
|
+
this.fullEncodeBuffer = new Uint8Array(byteLength + Encoder.BUFFER_SIZE);
|
|
73
|
+
this.fullEncodeBuffer.set(this.fullEncodeCache);
|
|
74
|
+
}
|
|
75
|
+
|
|
61
76
|
public applyPatches(clients: Client[]) {
|
|
62
77
|
let numClients = clients.length;
|
|
63
78
|
|
|
@@ -119,6 +134,9 @@ export class SchemaSerializer<T extends Schema> implements Serializer<T> {
|
|
|
119
134
|
const encodedChanges = this.encoder.encode(it);
|
|
120
135
|
|
|
121
136
|
if (!this.hasFilters) {
|
|
137
|
+
// copy once for all clients: a transport may still hold it after the next encode (see Client.raw)
|
|
138
|
+
const frame = Buffer.from(encodedChanges);
|
|
139
|
+
|
|
122
140
|
while (numClients--) {
|
|
123
141
|
const client = clients[numClients];
|
|
124
142
|
|
|
@@ -129,7 +147,7 @@ export class SchemaSerializer<T extends Schema> implements Serializer<T> {
|
|
|
129
147
|
continue;
|
|
130
148
|
}
|
|
131
149
|
|
|
132
|
-
client.raw(
|
|
150
|
+
client.raw(frame);
|
|
133
151
|
}
|
|
134
152
|
|
|
135
153
|
} else {
|
|
@@ -154,7 +172,7 @@ export class SchemaSerializer<T extends Schema> implements Serializer<T> {
|
|
|
154
172
|
// allow to pass the same encoded view for multiple clients
|
|
155
173
|
if (encodedView === undefined) {
|
|
156
174
|
encodedView = (view === SHARED_VIEW)
|
|
157
|
-
? encodedChanges
|
|
175
|
+
? Buffer.from(encodedChanges) // encodeView already returns a copy
|
|
158
176
|
: this.encoder.encodeView(client.view, sharedOffset, it);
|
|
159
177
|
this.encodedViews.set(view, encodedView);
|
|
160
178
|
}
|
package/src/utils/Utils.ts
CHANGED
|
@@ -155,7 +155,8 @@ export function merge(a: any, ...objs: any[]): any {
|
|
|
155
155
|
for (let i = 0, len = objs.length; i < len; i++) {
|
|
156
156
|
const b = objs[i];
|
|
157
157
|
for (const key in b) {
|
|
158
|
-
|
|
158
|
+
// JSON.parse keeps "__proto__" as an own key: assigning it replaces a's prototype
|
|
159
|
+
if (key !== "__proto__" && Object.hasOwn(b, key)) {
|
|
159
160
|
a[key] = b[key];
|
|
160
161
|
}
|
|
161
162
|
}
|