@colyseus/core 0.15.45 → 0.16.0-alpha.23
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/README.md +5 -5
- package/build/IPC.js.map +1 -1
- package/build/IPC.mjs.map +1 -1
- package/build/MatchMaker.d.ts +22 -16
- package/build/MatchMaker.js +71 -81
- package/build/MatchMaker.js.map +2 -2
- package/build/MatchMaker.mjs +70 -78
- package/build/MatchMaker.mjs.map +2 -2
- package/build/Protocol.d.ts +3 -9
- package/build/Protocol.js +35 -95
- package/build/Protocol.js.map +2 -2
- package/build/Protocol.mjs +34 -92
- package/build/Protocol.mjs.map +2 -2
- package/build/Room.d.ts +22 -27
- package/build/Room.js +55 -67
- package/build/Room.js.map +3 -3
- package/build/Room.mjs +56 -68
- package/build/Room.mjs.map +2 -2
- package/build/Server.d.ts +0 -1
- package/build/Server.js +4 -4
- package/build/Server.js.map +2 -2
- package/build/Server.mjs +3 -3
- package/build/Server.mjs.map +2 -2
- package/build/Transport.d.ts +37 -17
- package/build/Transport.js.map +2 -2
- package/build/Transport.mjs.map +2 -2
- package/build/index.d.ts +3 -3
- package/build/index.js +3 -3
- package/build/index.js.map +2 -2
- package/build/index.mjs +3 -3
- package/build/index.mjs.map +2 -2
- package/build/matchmaker/Lobby.d.ts +2 -2
- package/build/matchmaker/Lobby.js.map +2 -2
- package/build/matchmaker/Lobby.mjs.map +2 -2
- package/build/matchmaker/RegisteredHandler.d.ts +4 -5
- package/build/matchmaker/RegisteredHandler.js +4 -3
- package/build/matchmaker/RegisteredHandler.js.map +2 -2
- package/build/matchmaker/RegisteredHandler.mjs +4 -3
- package/build/matchmaker/RegisteredHandler.mjs.map +2 -2
- package/build/matchmaker/controller.d.ts +1 -2
- package/build/matchmaker/driver/RoomData.d.ts +3 -3
- package/build/matchmaker/driver/RoomData.js +3 -3
- package/build/matchmaker/driver/RoomData.js.map +2 -2
- package/build/matchmaker/driver/RoomData.mjs +2 -2
- package/build/matchmaker/driver/RoomData.mjs.map +2 -2
- package/build/matchmaker/driver/api.d.ts +104 -0
- package/build/matchmaker/driver/api.js +29 -0
- package/build/matchmaker/driver/api.js.map +7 -0
- package/build/matchmaker/driver/api.mjs +6 -0
- package/build/matchmaker/driver/api.mjs.map +7 -0
- package/build/matchmaker/driver/index.d.ts +7 -7
- package/build/matchmaker/driver/index.js +1 -1
- package/build/matchmaker/driver/index.js.map +2 -2
- package/build/matchmaker/driver/index.mjs +2 -2
- package/build/matchmaker/driver/index.mjs.map +2 -2
- package/build/matchmaker/driver/interfaces.d.ts +7 -11
- package/build/matchmaker/driver/interfaces.js.map +1 -1
- package/build/matchmaker/driver/local/LocalDriver.d.ts +13 -0
- package/build/matchmaker/driver/local/LocalDriver.js +65 -0
- package/build/matchmaker/driver/local/LocalDriver.js.map +7 -0
- package/build/matchmaker/driver/local/LocalDriver.mjs +42 -0
- package/build/matchmaker/driver/local/LocalDriver.mjs.map +7 -0
- package/build/matchmaker/driver/local/Query.d.ts +9 -0
- package/build/matchmaker/driver/local/Query.js +78 -0
- package/build/matchmaker/driver/local/Query.js.map +7 -0
- package/build/matchmaker/driver/local/Query.mjs +55 -0
- package/build/matchmaker/driver/local/Query.mjs.map +7 -0
- package/build/matchmaker/driver/local/RoomData.d.ts +19 -0
- package/build/matchmaker/driver/local/RoomData.js +79 -0
- package/build/matchmaker/driver/local/RoomData.js.map +7 -0
- package/build/matchmaker/driver/local/RoomData.mjs +56 -0
- package/build/matchmaker/driver/local/RoomData.mjs.map +7 -0
- package/build/presence/LocalPresence.d.ts +6 -1
- package/build/presence/LocalPresence.js +61 -0
- package/build/presence/LocalPresence.js.map +3 -3
- package/build/presence/LocalPresence.mjs +61 -0
- package/build/presence/LocalPresence.mjs.map +3 -3
- package/build/presence/Presence.d.ts +6 -0
- package/build/presence/Presence.js.map +1 -1
- package/build/rooms/LobbyRoom.d.ts +4 -4
- package/build/rooms/LobbyRoom.js.map +2 -2
- package/build/rooms/LobbyRoom.mjs.map +2 -2
- package/build/rooms/RelayRoom.js +2 -3
- package/build/rooms/RelayRoom.js.map +2 -2
- package/build/rooms/RelayRoom.mjs +3 -4
- package/build/rooms/RelayRoom.mjs.map +2 -2
- package/build/serializer/SchemaSerializer.d.ts +14 -7
- package/build/serializer/SchemaSerializer.js +66 -38
- package/build/serializer/SchemaSerializer.js.map +2 -2
- package/build/serializer/SchemaSerializer.mjs +67 -39
- package/build/serializer/SchemaSerializer.mjs.map +2 -2
- package/build/serializer/Serializer.d.ts +2 -2
- package/build/serializer/Serializer.js.map +1 -1
- package/build/utils/DevMode.js +1 -1
- package/build/utils/DevMode.js.map +2 -2
- package/build/utils/DevMode.mjs +2 -2
- package/build/utils/DevMode.mjs.map +2 -2
- package/build/utils/Utils.d.ts +2 -9
- package/build/utils/Utils.js +7 -4
- package/build/utils/Utils.js.map +2 -2
- package/build/utils/Utils.mjs +5 -3
- package/build/utils/Utils.mjs.map +2 -2
- package/package.json +5 -6
|
@@ -1,13 +1,20 @@
|
|
|
1
|
-
import { Client } from '..';
|
|
2
1
|
import { Serializer } from './Serializer';
|
|
3
|
-
import { Schema } from '@colyseus/schema';
|
|
2
|
+
import { Encoder, Schema, Iterator, StateView } from '@colyseus/schema';
|
|
3
|
+
import { Client } from '../Transport';
|
|
4
|
+
declare const SHARED_VIEW: {};
|
|
4
5
|
export declare class SchemaSerializer<T> implements Serializer<T> {
|
|
5
6
|
id: string;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
protected encoder: Encoder;
|
|
8
|
+
protected hasFilters: boolean;
|
|
9
|
+
protected handshakeCache: Buffer;
|
|
10
|
+
protected needFullEncode: boolean;
|
|
11
|
+
protected fullEncodeBuffer: Buffer;
|
|
12
|
+
protected fullEncodeCache: Buffer;
|
|
13
|
+
protected sharedOffsetCache: Iterator;
|
|
14
|
+
protected views: Map<StateView | typeof SHARED_VIEW, Buffer>;
|
|
9
15
|
reset(newState: T & Schema): void;
|
|
10
|
-
getFullState(client?: Client):
|
|
16
|
+
getFullState(client?: Client): Buffer;
|
|
11
17
|
applyPatches(clients: Client[]): boolean;
|
|
12
|
-
handshake():
|
|
18
|
+
handshake(): Buffer;
|
|
13
19
|
}
|
|
20
|
+
export {};
|
|
@@ -24,63 +24,91 @@ var import_schema = require("@colyseus/schema");
|
|
|
24
24
|
var import_Debug = require("../Debug");
|
|
25
25
|
var import_Protocol = require("../Protocol");
|
|
26
26
|
var import_Transport = require("../Transport");
|
|
27
|
+
const SHARED_VIEW = {};
|
|
27
28
|
class SchemaSerializer {
|
|
28
29
|
constructor() {
|
|
29
30
|
this.id = "schema";
|
|
30
|
-
this.
|
|
31
|
+
this.hasFilters = false;
|
|
32
|
+
this.needFullEncode = true;
|
|
33
|
+
this.fullEncodeBuffer = Buffer.allocUnsafe(import_schema.Encoder.BUFFER_SIZE);
|
|
34
|
+
this.sharedOffsetCache = { offset: 0 };
|
|
31
35
|
}
|
|
32
36
|
reset(newState) {
|
|
33
|
-
this.
|
|
34
|
-
this.
|
|
37
|
+
this.encoder = new import_schema.Encoder(newState);
|
|
38
|
+
this.hasFilters = this.encoder.context.hasFilters;
|
|
39
|
+
this.fullEncodeBuffer[0] = import_Protocol.Protocol.ROOM_STATE;
|
|
40
|
+
if (this.hasFilters) {
|
|
41
|
+
this.views = /* @__PURE__ */ new Map();
|
|
42
|
+
}
|
|
35
43
|
}
|
|
36
44
|
getFullState(client) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
if (this.needFullEncode || this.encoder.root.changes.size > 0) {
|
|
46
|
+
this.sharedOffsetCache = { offset: 1 };
|
|
47
|
+
this.fullEncodeCache = this.encoder.encodeAll(this.sharedOffsetCache, this.fullEncodeBuffer);
|
|
48
|
+
this.needFullEncode = false;
|
|
49
|
+
}
|
|
50
|
+
if (this.hasFilters && client?.view) {
|
|
51
|
+
return this.encoder.encodeAllView(
|
|
52
|
+
client.view,
|
|
53
|
+
this.sharedOffsetCache.offset,
|
|
54
|
+
{ ...this.sharedOffsetCache },
|
|
55
|
+
this.fullEncodeBuffer
|
|
56
|
+
);
|
|
40
57
|
} else {
|
|
41
|
-
return
|
|
58
|
+
return this.fullEncodeCache;
|
|
42
59
|
}
|
|
43
60
|
}
|
|
44
61
|
applyPatches(clients) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
62
|
+
let numClients = clients.length;
|
|
63
|
+
this.needFullEncode = this.encoder.root.changes.size > 0;
|
|
64
|
+
if (numClients == 0 || !this.needFullEncode && (!this.hasFilters || this.encoder.root.filteredChanges.size === 0)) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
if (import_Debug.debugPatch.enabled) {
|
|
68
|
+
import_Debug.debugPatch.dumpChanges = (0, import_schema.dumpChanges)(this.encoder.state);
|
|
69
|
+
}
|
|
70
|
+
const it = { offset: 1 };
|
|
71
|
+
this.encoder.sharedBuffer[0] = import_Protocol.Protocol.ROOM_STATE_PATCH;
|
|
72
|
+
const encodedChanges = this.encoder.encode(it);
|
|
73
|
+
if (!this.hasFilters) {
|
|
74
|
+
while (numClients--) {
|
|
75
|
+
const client = clients[numClients];
|
|
76
|
+
if (client.state !== import_Transport.ClientState.JOINED) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
client.raw(encodedChanges);
|
|
50
80
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
client.raw(patches);
|
|
58
|
-
}
|
|
81
|
+
} else {
|
|
82
|
+
const sharedOffset = it.offset;
|
|
83
|
+
while (numClients--) {
|
|
84
|
+
const client = clients[numClients];
|
|
85
|
+
if (client.state !== import_Transport.ClientState.JOINED) {
|
|
86
|
+
continue;
|
|
59
87
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
client.raw([import_Protocol.Protocol.ROOM_STATE_PATCH, ...filteredPatches]);
|
|
66
|
-
}
|
|
88
|
+
const view = client.view || SHARED_VIEW;
|
|
89
|
+
let encodedView = this.views.get(view);
|
|
90
|
+
if (encodedView === void 0) {
|
|
91
|
+
encodedView = view === SHARED_VIEW ? encodedChanges : this.encoder.encodeView(client.view, sharedOffset, it);
|
|
92
|
+
this.views.set(view, encodedView);
|
|
67
93
|
}
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
if (import_Debug.debugPatch.enabled) {
|
|
71
|
-
(0, import_Debug.debugPatch)(
|
|
72
|
-
"%d bytes sent to %d clients, %j",
|
|
73
|
-
patches.length,
|
|
74
|
-
clients.length,
|
|
75
|
-
import_Debug.debugPatch.dumpChanges
|
|
76
|
-
);
|
|
94
|
+
client.raw(encodedView);
|
|
77
95
|
}
|
|
96
|
+
this.views.clear();
|
|
97
|
+
}
|
|
98
|
+
this.encoder.discardChanges();
|
|
99
|
+
if (import_Debug.debugPatch.enabled) {
|
|
100
|
+
(0, import_Debug.debugPatch)(
|
|
101
|
+
"%d bytes sent to %d clients, %j",
|
|
102
|
+
encodedChanges.length,
|
|
103
|
+
clients.length,
|
|
104
|
+
import_Debug.debugPatch.dumpChanges
|
|
105
|
+
);
|
|
78
106
|
}
|
|
79
|
-
return
|
|
107
|
+
return true;
|
|
80
108
|
}
|
|
81
109
|
handshake() {
|
|
82
110
|
if (!this.handshakeCache) {
|
|
83
|
-
this.handshakeCache = this.state && import_schema.Reflection.encode(this.state);
|
|
111
|
+
this.handshakeCache = this.encoder.state && import_schema.Reflection.encode(this.encoder.state);
|
|
84
112
|
}
|
|
85
113
|
return this.handshakeCache;
|
|
86
114
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/serializer/SchemaSerializer.ts"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import { Serializer } from './Serializer';\n\nimport { Encoder, dumpChanges, Reflection, Schema, Iterator, StateView } from '@colyseus/schema';\nimport { debugPatch } from '../Debug';\nimport { Protocol } from '../Protocol';\nimport { Client, ClientState } from '../Transport';\n\nconst SHARED_VIEW = {};\n\nexport class SchemaSerializer<T> implements Serializer<T> {\n public id = 'schema';\n\n protected encoder: Encoder;\n protected hasFilters: boolean = false;\n\n protected handshakeCache: Buffer;\n\n // flag to avoid re-encoding full state if no changes were made\n protected needFullEncode: boolean = true;\n\n // TODO: make this optional. allocating a new buffer for each room may not be always necessary.\n protected fullEncodeBuffer: Buffer = Buffer.allocUnsafe(Encoder.BUFFER_SIZE);\n protected fullEncodeCache: Buffer;\n protected sharedOffsetCache: Iterator = { offset: 0 };\n\n protected views: Map<StateView | typeof SHARED_VIEW, Buffer>;\n\n public reset(newState: T & Schema) {\n this.encoder = new Encoder(newState);\n this.hasFilters = this.encoder.context.hasFilters;\n\n // cache ROOM_STATE byte as part of the encoded buffer\n this.fullEncodeBuffer[0] = Protocol.ROOM_STATE;\n\n if (this.hasFilters) {\n this.views = new Map();\n }\n }\n\n public getFullState(client?: Client) {\n if (this.needFullEncode || this.encoder.root.changes.size > 0) {\n this.sharedOffsetCache = { offset: 1 };\n this.fullEncodeCache = this.encoder.encodeAll(this.sharedOffsetCache, this.fullEncodeBuffer);\n this.needFullEncode = false;\n }\n\n if (this.hasFilters && client?.view) {\n return this.encoder.encodeAllView(\n client.view,\n this.sharedOffsetCache.offset,\n { ...this.sharedOffsetCache },\n this.fullEncodeBuffer\n );\n\n } else {\n return this.fullEncodeCache;\n }\n }\n\n public applyPatches(clients: Client[]) {\n let numClients = clients.length;\n this.needFullEncode = (this.encoder.root.changes.size > 0);\n\n if (\n numClients == 0 ||\n (\n !this.needFullEncode &&\n (!this.hasFilters || this.encoder.root.filteredChanges.size === 0)\n )\n ) {\n // skip patching state if:\n // - no clients are connected\n // - no changes were made\n // - no \"filtered changes\" were made when using filters\n return false;\n }\n\n\n // dump changes for patch debugging\n if (debugPatch.enabled) {\n (debugPatch as any).dumpChanges = dumpChanges(this.encoder.state);\n }\n\n // get patch bytes\n const it: Iterator = { offset: 1 };\n this.encoder.sharedBuffer[0] = Protocol.ROOM_STATE_PATCH;\n\n // encode changes once, for all clients\n const encodedChanges = this.encoder.encode(it);\n\n if (!this.hasFilters) {\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n client.raw(encodedChanges);\n }\n\n } else {\n // cache shared offset\n const sharedOffset = it.offset;\n\n // encode state multiple times, for each client\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n const view = client.view || SHARED_VIEW;\n\n let encodedView = this.views.get(view);\n\n // allow to pass the same encoded view for multiple clients\n if (encodedView === undefined) {\n encodedView = (view === SHARED_VIEW)\n ? encodedChanges\n : this.encoder.encodeView(client.view, sharedOffset, it);\n this.views.set(view, encodedView);\n }\n\n client.raw(encodedView);\n }\n\n // clear views\n this.views.clear();\n }\n\n // discard changes after sending\n this.encoder.discardChanges();\n\n // debug patches\n if (debugPatch.enabled) {\n debugPatch(\n '%d bytes sent to %d clients, %j',\n encodedChanges.length,\n clients.length,\n (debugPatch as any).dumpChanges,\n );\n }\n\n return true;\n }\n\n public handshake() {\n /**\n * Cache handshake to avoid encoding it for each client joining\n */\n if (!this.handshakeCache) {\n // TODO: re-use handshake buffer for all rooms\n this.handshakeCache = (this.encoder.state && Reflection.encode(this.encoder.state));\n }\n\n return this.handshakeCache;\n }\n\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,oBAA8E;AAC9E,mBAA2B;AAC3B,sBAAyB;AACzB,uBAAoC;AAEpC,MAAM,cAAc,CAAC;AAEd,MAAM,iBAA6C;AAAA,EAAnD;AACL,SAAO,KAAK;AAGZ,SAAU,aAAsB;AAKhC,SAAU,iBAA0B;AAGpC,SAAU,mBAA2B,OAAO,YAAY,sBAAQ,WAAW;AAE3E,SAAU,oBAA8B,EAAE,QAAQ,EAAE;AAAA;AAAA,EAI7C,MAAM,UAAsB;AACjC,SAAK,UAAU,IAAI,sBAAQ,QAAQ;AACnC,SAAK,aAAa,KAAK,QAAQ,QAAQ;AAGvC,SAAK,iBAAiB,KAAK,yBAAS;AAEpC,QAAI,KAAK,YAAY;AACnB,WAAK,QAAQ,oBAAI,IAAI;AAAA,IACvB;AAAA,EACF;AAAA,EAEO,aAAa,QAAiB;AACnC,QAAI,KAAK,kBAAkB,KAAK,QAAQ,KAAK,QAAQ,OAAO,GAAG;AAC7D,WAAK,oBAAoB,EAAE,QAAQ,EAAE;AACrC,WAAK,kBAAkB,KAAK,QAAQ,UAAU,KAAK,mBAAmB,KAAK,gBAAgB;AAC3F,WAAK,iBAAiB;AAAA,IACxB;AAEA,QAAI,KAAK,cAAc,QAAQ,MAAM;AACnC,aAAO,KAAK,QAAQ;AAAA,QAClB,OAAO;AAAA,QACP,KAAK,kBAAkB;AAAA,QACvB,EAAE,GAAG,KAAK,kBAAkB;AAAA,QAC5B,KAAK;AAAA,MACP;AAAA,IAEF,OAAO;AACL,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA,EAEO,aAAa,SAAmB;AACrC,QAAI,aAAa,QAAQ;AACzB,SAAK,iBAAkB,KAAK,QAAQ,KAAK,QAAQ,OAAO;AAExD,QACE,cAAc,KAEZ,CAAC,KAAK,mBACL,CAAC,KAAK,cAAc,KAAK,QAAQ,KAAK,gBAAgB,SAAS,IAElE;AAKA,aAAO;AAAA,IACT;AAIA,QAAI,wBAAW,SAAS;AACtB,MAAC,wBAAmB,kBAAc,2BAAY,KAAK,QAAQ,KAAK;AAAA,IAClE;AAGA,UAAM,KAAe,EAAE,QAAQ,EAAE;AACjC,SAAK,QAAQ,aAAa,KAAK,yBAAS;AAGxC,UAAM,iBAAiB,KAAK,QAAQ,OAAO,EAAE;AAE7C,QAAI,CAAC,KAAK,YAAY;AACpB,aAAO,cAAc;AACnB,cAAM,SAAS,QAAQ;AAKvB,YAAI,OAAO,UAAU,6BAAY,QAAQ;AACvC;AAAA,QACF;AAEA,eAAO,IAAI,cAAc;AAAA,MAC3B;AAAA,IAEF,OAAO;AAEL,YAAM,eAAe,GAAG;AAGxB,aAAO,cAAc;AACnB,cAAM,SAAS,QAAQ;AAKvB,YAAI,OAAO,UAAU,6BAAY,QAAQ;AACvC;AAAA,QACF;AAEA,cAAM,OAAO,OAAO,QAAQ;AAE5B,YAAI,cAAc,KAAK,MAAM,IAAI,IAAI;AAGrC,YAAI,gBAAgB,QAAW;AAC7B,wBAAe,SAAS,cACpB,iBACA,KAAK,QAAQ,WAAW,OAAO,MAAM,cAAc,EAAE;AACzD,eAAK,MAAM,IAAI,MAAM,WAAW;AAAA,QAClC;AAEA,eAAO,IAAI,WAAW;AAAA,MACxB;AAGA,WAAK,MAAM,MAAM;AAAA,IACnB;AAGA,SAAK,QAAQ,eAAe;AAG5B,QAAI,wBAAW,SAAS;AACtB;AAAA,QACE;AAAA,QACA,eAAe;AAAA,QACf,QAAQ;AAAA,QACP,wBAAmB;AAAA,MACtB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,YAAY;AAIjB,QAAI,CAAC,KAAK,gBAAgB;AAExB,WAAK,iBAAkB,KAAK,QAAQ,SAAS,yBAAW,OAAO,KAAK,QAAQ,KAAK;AAAA,IACnF;AAEA,WAAO,KAAK;AAAA,EACd;AAEF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,64 +1,92 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Encoder, dumpChanges, Reflection } from "@colyseus/schema";
|
|
2
2
|
import { debugPatch } from "../Debug";
|
|
3
3
|
import { Protocol } from "../Protocol";
|
|
4
4
|
import { ClientState } from "../Transport";
|
|
5
|
+
const SHARED_VIEW = {};
|
|
5
6
|
class SchemaSerializer {
|
|
6
7
|
constructor() {
|
|
7
8
|
this.id = "schema";
|
|
8
|
-
this.
|
|
9
|
+
this.hasFilters = false;
|
|
10
|
+
this.needFullEncode = true;
|
|
11
|
+
this.fullEncodeBuffer = Buffer.allocUnsafe(Encoder.BUFFER_SIZE);
|
|
12
|
+
this.sharedOffsetCache = { offset: 0 };
|
|
9
13
|
}
|
|
10
14
|
reset(newState) {
|
|
11
|
-
this.
|
|
12
|
-
this.
|
|
15
|
+
this.encoder = new Encoder(newState);
|
|
16
|
+
this.hasFilters = this.encoder.context.hasFilters;
|
|
17
|
+
this.fullEncodeBuffer[0] = Protocol.ROOM_STATE;
|
|
18
|
+
if (this.hasFilters) {
|
|
19
|
+
this.views = /* @__PURE__ */ new Map();
|
|
20
|
+
}
|
|
13
21
|
}
|
|
14
22
|
getFullState(client) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
23
|
+
if (this.needFullEncode || this.encoder.root.changes.size > 0) {
|
|
24
|
+
this.sharedOffsetCache = { offset: 1 };
|
|
25
|
+
this.fullEncodeCache = this.encoder.encodeAll(this.sharedOffsetCache, this.fullEncodeBuffer);
|
|
26
|
+
this.needFullEncode = false;
|
|
27
|
+
}
|
|
28
|
+
if (this.hasFilters && client?.view) {
|
|
29
|
+
return this.encoder.encodeAllView(
|
|
30
|
+
client.view,
|
|
31
|
+
this.sharedOffsetCache.offset,
|
|
32
|
+
{ ...this.sharedOffsetCache },
|
|
33
|
+
this.fullEncodeBuffer
|
|
34
|
+
);
|
|
18
35
|
} else {
|
|
19
|
-
return
|
|
36
|
+
return this.fullEncodeCache;
|
|
20
37
|
}
|
|
21
38
|
}
|
|
22
39
|
applyPatches(clients) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
let numClients = clients.length;
|
|
41
|
+
this.needFullEncode = this.encoder.root.changes.size > 0;
|
|
42
|
+
if (numClients == 0 || !this.needFullEncode && (!this.hasFilters || this.encoder.root.filteredChanges.size === 0)) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
if (debugPatch.enabled) {
|
|
46
|
+
debugPatch.dumpChanges = dumpChanges(this.encoder.state);
|
|
47
|
+
}
|
|
48
|
+
const it = { offset: 1 };
|
|
49
|
+
this.encoder.sharedBuffer[0] = Protocol.ROOM_STATE_PATCH;
|
|
50
|
+
const encodedChanges = this.encoder.encode(it);
|
|
51
|
+
if (!this.hasFilters) {
|
|
52
|
+
while (numClients--) {
|
|
53
|
+
const client = clients[numClients];
|
|
54
|
+
if (client.state !== ClientState.JOINED) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
client.raw(encodedChanges);
|
|
28
58
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
client.raw(patches);
|
|
36
|
-
}
|
|
59
|
+
} else {
|
|
60
|
+
const sharedOffset = it.offset;
|
|
61
|
+
while (numClients--) {
|
|
62
|
+
const client = clients[numClients];
|
|
63
|
+
if (client.state !== ClientState.JOINED) {
|
|
64
|
+
continue;
|
|
37
65
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
client.raw([Protocol.ROOM_STATE_PATCH, ...filteredPatches]);
|
|
44
|
-
}
|
|
66
|
+
const view = client.view || SHARED_VIEW;
|
|
67
|
+
let encodedView = this.views.get(view);
|
|
68
|
+
if (encodedView === void 0) {
|
|
69
|
+
encodedView = view === SHARED_VIEW ? encodedChanges : this.encoder.encodeView(client.view, sharedOffset, it);
|
|
70
|
+
this.views.set(view, encodedView);
|
|
45
71
|
}
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
if (debugPatch.enabled) {
|
|
49
|
-
debugPatch(
|
|
50
|
-
"%d bytes sent to %d clients, %j",
|
|
51
|
-
patches.length,
|
|
52
|
-
clients.length,
|
|
53
|
-
debugPatch.dumpChanges
|
|
54
|
-
);
|
|
72
|
+
client.raw(encodedView);
|
|
55
73
|
}
|
|
74
|
+
this.views.clear();
|
|
75
|
+
}
|
|
76
|
+
this.encoder.discardChanges();
|
|
77
|
+
if (debugPatch.enabled) {
|
|
78
|
+
debugPatch(
|
|
79
|
+
"%d bytes sent to %d clients, %j",
|
|
80
|
+
encodedChanges.length,
|
|
81
|
+
clients.length,
|
|
82
|
+
debugPatch.dumpChanges
|
|
83
|
+
);
|
|
56
84
|
}
|
|
57
|
-
return
|
|
85
|
+
return true;
|
|
58
86
|
}
|
|
59
87
|
handshake() {
|
|
60
88
|
if (!this.handshakeCache) {
|
|
61
|
-
this.handshakeCache = this.state && Reflection.encode(this.state);
|
|
89
|
+
this.handshakeCache = this.encoder.state && Reflection.encode(this.encoder.state);
|
|
62
90
|
}
|
|
63
91
|
return this.handshakeCache;
|
|
64
92
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/serializer/SchemaSerializer.ts"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { Serializer } from './Serializer';\n\nimport { Encoder, dumpChanges, Reflection, Schema, Iterator, StateView } from '@colyseus/schema';\nimport { debugPatch } from '../Debug';\nimport { Protocol } from '../Protocol';\nimport { Client, ClientState } from '../Transport';\n\nconst SHARED_VIEW = {};\n\nexport class SchemaSerializer<T> implements Serializer<T> {\n public id = 'schema';\n\n protected encoder: Encoder;\n protected hasFilters: boolean = false;\n\n protected handshakeCache: Buffer;\n\n // flag to avoid re-encoding full state if no changes were made\n protected needFullEncode: boolean = true;\n\n // TODO: make this optional. allocating a new buffer for each room may not be always necessary.\n protected fullEncodeBuffer: Buffer = Buffer.allocUnsafe(Encoder.BUFFER_SIZE);\n protected fullEncodeCache: Buffer;\n protected sharedOffsetCache: Iterator = { offset: 0 };\n\n protected views: Map<StateView | typeof SHARED_VIEW, Buffer>;\n\n public reset(newState: T & Schema) {\n this.encoder = new Encoder(newState);\n this.hasFilters = this.encoder.context.hasFilters;\n\n // cache ROOM_STATE byte as part of the encoded buffer\n this.fullEncodeBuffer[0] = Protocol.ROOM_STATE;\n\n if (this.hasFilters) {\n this.views = new Map();\n }\n }\n\n public getFullState(client?: Client) {\n if (this.needFullEncode || this.encoder.root.changes.size > 0) {\n this.sharedOffsetCache = { offset: 1 };\n this.fullEncodeCache = this.encoder.encodeAll(this.sharedOffsetCache, this.fullEncodeBuffer);\n this.needFullEncode = false;\n }\n\n if (this.hasFilters && client?.view) {\n return this.encoder.encodeAllView(\n client.view,\n this.sharedOffsetCache.offset,\n { ...this.sharedOffsetCache },\n this.fullEncodeBuffer\n );\n\n } else {\n return this.fullEncodeCache;\n }\n }\n\n public applyPatches(clients: Client[]) {\n let numClients = clients.length;\n this.needFullEncode = (this.encoder.root.changes.size > 0);\n\n if (\n numClients == 0 ||\n (\n !this.needFullEncode &&\n (!this.hasFilters || this.encoder.root.filteredChanges.size === 0)\n )\n ) {\n // skip patching state if:\n // - no clients are connected\n // - no changes were made\n // - no \"filtered changes\" were made when using filters\n return false;\n }\n\n\n // dump changes for patch debugging\n if (debugPatch.enabled) {\n (debugPatch as any).dumpChanges = dumpChanges(this.encoder.state);\n }\n\n // get patch bytes\n const it: Iterator = { offset: 1 };\n this.encoder.sharedBuffer[0] = Protocol.ROOM_STATE_PATCH;\n\n // encode changes once, for all clients\n const encodedChanges = this.encoder.encode(it);\n\n if (!this.hasFilters) {\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n client.raw(encodedChanges);\n }\n\n } else {\n // cache shared offset\n const sharedOffset = it.offset;\n\n // encode state multiple times, for each client\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n const view = client.view || SHARED_VIEW;\n\n let encodedView = this.views.get(view);\n\n // allow to pass the same encoded view for multiple clients\n if (encodedView === undefined) {\n encodedView = (view === SHARED_VIEW)\n ? encodedChanges\n : this.encoder.encodeView(client.view, sharedOffset, it);\n this.views.set(view, encodedView);\n }\n\n client.raw(encodedView);\n }\n\n // clear views\n this.views.clear();\n }\n\n // discard changes after sending\n this.encoder.discardChanges();\n\n // debug patches\n if (debugPatch.enabled) {\n debugPatch(\n '%d bytes sent to %d clients, %j',\n encodedChanges.length,\n clients.length,\n (debugPatch as any).dumpChanges,\n );\n }\n\n return true;\n }\n\n public handshake() {\n /**\n * Cache handshake to avoid encoding it for each client joining\n */\n if (!this.handshakeCache) {\n // TODO: re-use handshake buffer for all rooms\n this.handshakeCache = (this.encoder.state && Reflection.encode(this.encoder.state));\n }\n\n return this.handshakeCache;\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAEA,SAAS,SAAS,aAAa,kBAA+C;AAC9E,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAiB,mBAAmB;AAEpC,MAAM,cAAc,CAAC;AAEd,MAAM,iBAA6C;AAAA,EAAnD;AACL,SAAO,KAAK;AAGZ,SAAU,aAAsB;AAKhC,SAAU,iBAA0B;AAGpC,SAAU,mBAA2B,OAAO,YAAY,QAAQ,WAAW;AAE3E,SAAU,oBAA8B,EAAE,QAAQ,EAAE;AAAA;AAAA,EAI7C,MAAM,UAAsB;AACjC,SAAK,UAAU,IAAI,QAAQ,QAAQ;AACnC,SAAK,aAAa,KAAK,QAAQ,QAAQ;AAGvC,SAAK,iBAAiB,KAAK,SAAS;AAEpC,QAAI,KAAK,YAAY;AACnB,WAAK,QAAQ,oBAAI,IAAI;AAAA,IACvB;AAAA,EACF;AAAA,EAEO,aAAa,QAAiB;AACnC,QAAI,KAAK,kBAAkB,KAAK,QAAQ,KAAK,QAAQ,OAAO,GAAG;AAC7D,WAAK,oBAAoB,EAAE,QAAQ,EAAE;AACrC,WAAK,kBAAkB,KAAK,QAAQ,UAAU,KAAK,mBAAmB,KAAK,gBAAgB;AAC3F,WAAK,iBAAiB;AAAA,IACxB;AAEA,QAAI,KAAK,cAAc,QAAQ,MAAM;AACnC,aAAO,KAAK,QAAQ;AAAA,QAClB,OAAO;AAAA,QACP,KAAK,kBAAkB;AAAA,QACvB,EAAE,GAAG,KAAK,kBAAkB;AAAA,QAC5B,KAAK;AAAA,MACP;AAAA,IAEF,OAAO;AACL,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA,EAEO,aAAa,SAAmB;AACrC,QAAI,aAAa,QAAQ;AACzB,SAAK,iBAAkB,KAAK,QAAQ,KAAK,QAAQ,OAAO;AAExD,QACE,cAAc,KAEZ,CAAC,KAAK,mBACL,CAAC,KAAK,cAAc,KAAK,QAAQ,KAAK,gBAAgB,SAAS,IAElE;AAKA,aAAO;AAAA,IACT;AAIA,QAAI,WAAW,SAAS;AACtB,MAAC,WAAmB,cAAc,YAAY,KAAK,QAAQ,KAAK;AAAA,IAClE;AAGA,UAAM,KAAe,EAAE,QAAQ,EAAE;AACjC,SAAK,QAAQ,aAAa,KAAK,SAAS;AAGxC,UAAM,iBAAiB,KAAK,QAAQ,OAAO,EAAE;AAE7C,QAAI,CAAC,KAAK,YAAY;AACpB,aAAO,cAAc;AACnB,cAAM,SAAS,QAAQ;AAKvB,YAAI,OAAO,UAAU,YAAY,QAAQ;AACvC;AAAA,QACF;AAEA,eAAO,IAAI,cAAc;AAAA,MAC3B;AAAA,IAEF,OAAO;AAEL,YAAM,eAAe,GAAG;AAGxB,aAAO,cAAc;AACnB,cAAM,SAAS,QAAQ;AAKvB,YAAI,OAAO,UAAU,YAAY,QAAQ;AACvC;AAAA,QACF;AAEA,cAAM,OAAO,OAAO,QAAQ;AAE5B,YAAI,cAAc,KAAK,MAAM,IAAI,IAAI;AAGrC,YAAI,gBAAgB,QAAW;AAC7B,wBAAe,SAAS,cACpB,iBACA,KAAK,QAAQ,WAAW,OAAO,MAAM,cAAc,EAAE;AACzD,eAAK,MAAM,IAAI,MAAM,WAAW;AAAA,QAClC;AAEA,eAAO,IAAI,WAAW;AAAA,MACxB;AAGA,WAAK,MAAM,MAAM;AAAA,IACnB;AAGA,SAAK,QAAQ,eAAe;AAG5B,QAAI,WAAW,SAAS;AACtB;AAAA,QACE;AAAA,QACA,eAAe;AAAA,QACf,QAAQ;AAAA,QACP,WAAmB;AAAA,MACtB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,YAAY;AAIjB,QAAI,CAAC,KAAK,gBAAgB;AAExB,WAAK,iBAAkB,KAAK,QAAQ,SAAS,WAAW,OAAO,KAAK,QAAQ,KAAK;AAAA,IACnF;AAEA,WAAO,KAAK;AAAA,EACd;AAEF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,7 +2,7 @@ import { Client } from '..';
|
|
|
2
2
|
export interface Serializer<T> {
|
|
3
3
|
id: string;
|
|
4
4
|
reset(data: any): void;
|
|
5
|
-
getFullState(client?: Client):
|
|
5
|
+
getFullState(client?: Client): Buffer;
|
|
6
6
|
applyPatches(clients: Client[], state: T): boolean;
|
|
7
|
-
handshake?():
|
|
7
|
+
handshake?(): Buffer;
|
|
8
8
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/serializer/Serializer.ts"],
|
|
4
|
-
"sourcesContent": ["import { Client } from '..';\n\nexport interface Serializer<T> {\n id: string;\n reset(data: any): void;\n getFullState(client?: Client):
|
|
4
|
+
"sourcesContent": ["import { Client } from '..';\n\nexport interface Serializer<T> {\n id: string;\n reset(data: any): void;\n getFullState(client?: Client): Buffer;\n applyPatches(clients: Client[], state: T): boolean;\n handshake?(): Buffer;\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/utils/DevMode.js
CHANGED
|
@@ -49,7 +49,7 @@ async function reloadFromCache() {
|
|
|
49
49
|
const roomHistory = JSON.parse(value);
|
|
50
50
|
debugDevMode("restoring room %s (%s)", roomHistory.roomName, roomId);
|
|
51
51
|
const recreatedRoomListing = await (0, import_MatchMaker.handleCreateRoom)(roomHistory.roomName, roomHistory.clientOptions, roomId);
|
|
52
|
-
const recreatedRoom = (0, import_MatchMaker.
|
|
52
|
+
const recreatedRoom = (0, import_MatchMaker.getLocalRoomById)(recreatedRoomListing.roomId);
|
|
53
53
|
import_Logger.logger.debug(`\u{1F504} room '${roomId}' has been restored.`);
|
|
54
54
|
if (roomHistory.hasOwnProperty("state")) {
|
|
55
55
|
recreatedRoom.state.decode(roomHistory.state);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/DevMode.ts"],
|
|
4
|
-
"sourcesContent": ["import debug from \"debug\";\nimport { logger } from \"../Logger\";\nimport { debugAndPrintError } from \"../Debug\";\n\nimport {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkB;AAClB,oBAAuB;AACvB,mBAAmC;AAEnC,
|
|
4
|
+
"sourcesContent": ["import debug from \"debug\";\nimport { logger } from \"../Logger\";\nimport { debugAndPrintError } from \"../Debug\";\n\nimport { getLocalRoomById, handleCreateRoom, presence, remoteRoomCall } from \"../MatchMaker\";\nimport type { Room } from \"../Room\";\n\nexport const debugDevMode = debug('colyseus:devmode');\n\nexport let isDevMode: boolean = false;\n\nexport function setDevMode(bool: boolean) {\n isDevMode = bool;\n}\n\nexport async function reloadFromCache() {\n const roomHistoryList = Object.entries(await presence.hgetall(getRoomRestoreListKey()));\n debugDevMode(\"rooms to restore: %i\", roomHistoryList.length);\n\n for (const [roomId, value] of roomHistoryList) {\n const roomHistory = JSON.parse(value);\n debugDevMode(\"restoring room %s (%s)\", roomHistory.roomName, roomId);\n\n const recreatedRoomListing = await handleCreateRoom(roomHistory.roomName, roomHistory.clientOptions, roomId);\n const recreatedRoom = getLocalRoomById(recreatedRoomListing.roomId);\n logger.debug(`\uD83D\uDD04 room '${roomId}' has been restored.`);\n\n // Set previous state\n if (roomHistory.hasOwnProperty(\"state\")) {\n recreatedRoom.state.decode(roomHistory.state);\n\n //\n // WORKAROUND: @colyseus/schema is not capable of encoding a decoded\n // state. thus, we need a fresh clone immediately after decoding\n //\n recreatedRoom.setState(recreatedRoom.state.clone());\n logger.debug(`\uD83D\uDCCB room '${roomId}' state =>`, recreatedRoom.state.toJSON());\n }\n\n // call `onRestoreRoom` with custom 'cache'd property.\n recreatedRoom.onRestoreRoom?.(roomHistory[\"cache\"]);\n\n // Reserve seats for clients from cached history\n if (roomHistory.clients) {\n for (const previousSessionId of roomHistory.clients) {\n // reserve seat for 20 seconds\n await remoteRoomCall(recreatedRoomListing.roomId, '_reserveSeat', [previousSessionId, {}, 20, false, true]);\n }\n }\n }\n\n if (roomHistoryList.length > 0) {\n logger.debug(\"\u2705\", roomHistoryList.length, \"room(s) have been restored.\");\n }\n}\n\nexport async function cacheRoomHistory(rooms: { [roomId: string]: Room }) {\n for (const room of Object.values(rooms)) {\n const roomHistoryResult = await presence.hget(getRoomRestoreListKey(), room.roomId);\n if (roomHistoryResult) {\n try {\n const roomHistory = JSON.parse(roomHistoryResult);\n\n // custom cache method\n roomHistory[\"cache\"] = room.onCacheRoom?.();\n\n // encode state\n debugDevMode(\"caching room %s (%s)\", room.roomName, room.roomId);\n\n if (room.state) {\n roomHistory[\"state\"] = room.state.encodeAll();\n }\n\n // cache active clients and reserved seats\n roomHistory[\"clients\"] = room.clients.map((client) => client.sessionId);\n\n for (const sessionId in room['reservedSeats']) {\n roomHistory[\"clients\"].push(sessionId);\n }\n\n await presence.hset(getRoomRestoreListKey(), room.roomId, JSON.stringify(roomHistory));\n\n // Rewrite updated room history\n logger.debug(`\uD83D\uDCBE caching room '${room.roomId}' (clients: ${room.clients.length}, state size: ${(roomHistory[\"state\"] || []).length} bytes)`);\n\n } catch (e) {\n debugAndPrintError(`\u274C couldn't cache room '${room.roomId}', due to:\\n${e.stack}`);\n }\n }\n }\n}\n\nexport async function getPreviousProcessId(hostname) {\n return await presence.hget(getProcessRestoreKey(), hostname);\n}\n\nexport function getRoomRestoreListKey() {\n return 'roomhistory';\n}\n\nexport function getProcessRestoreKey() {\n return 'processhistory';\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkB;AAClB,oBAAuB;AACvB,mBAAmC;AAEnC,wBAA6E;AAGtE,MAAM,mBAAe,aAAAA,SAAM,kBAAkB;AAE7C,IAAI,YAAqB;AAEzB,SAAS,WAAW,MAAe;AACxC,cAAY;AACd;AAEA,eAAsB,kBAAkB;AACtC,QAAM,kBAAkB,OAAO,QAAQ,MAAM,2BAAS,QAAQ,sBAAsB,CAAC,CAAC;AACtF,eAAa,wBAAwB,gBAAgB,MAAM;AAE3D,aAAW,CAAC,QAAQ,KAAK,KAAK,iBAAiB;AAC7C,UAAM,cAAc,KAAK,MAAM,KAAK;AACpC,iBAAa,0BAA0B,YAAY,UAAU,MAAM;AAEnE,UAAM,uBAAuB,UAAM,oCAAiB,YAAY,UAAU,YAAY,eAAe,MAAM;AAC3G,UAAM,oBAAgB,oCAAiB,qBAAqB,MAAM;AAClE,yBAAO,MAAM,mBAAY,4BAA4B;AAGrD,QAAI,YAAY,eAAe,OAAO,GAAG;AACvC,oBAAc,MAAM,OAAO,YAAY,KAAK;AAM5C,oBAAc,SAAS,cAAc,MAAM,MAAM,CAAC;AAClD,2BAAO,MAAM,mBAAY,oBAAoB,cAAc,MAAM,OAAO,CAAC;AAAA,IAC3E;AAGA,kBAAc,gBAAgB,YAAY,QAAQ;AAGlD,QAAI,YAAY,SAAS;AACvB,iBAAW,qBAAqB,YAAY,SAAS;AAEnD,kBAAM,kCAAe,qBAAqB,QAAQ,gBAAgB,CAAC,mBAAmB,CAAC,GAAG,IAAI,OAAO,IAAI,CAAC;AAAA,MAC5G;AAAA,IACF;AAAA,EACF;AAEA,MAAI,gBAAgB,SAAS,GAAG;AAC9B,yBAAO,MAAM,UAAK,gBAAgB,QAAQ,6BAA6B;AAAA,EACzE;AACF;AAEA,eAAsB,iBAAiB,OAAmC;AACxE,aAAW,QAAQ,OAAO,OAAO,KAAK,GAAG;AACvC,UAAM,oBAAoB,MAAM,2BAAS,KAAK,sBAAsB,GAAG,KAAK,MAAM;AAClF,QAAI,mBAAmB;AACrB,UAAI;AACF,cAAM,cAAc,KAAK,MAAM,iBAAiB;AAGhD,oBAAY,WAAW,KAAK,cAAc;AAG1C,qBAAa,wBAAwB,KAAK,UAAU,KAAK,MAAM;AAE/D,YAAI,KAAK,OAAO;AACd,sBAAY,WAAW,KAAK,MAAM,UAAU;AAAA,QAC9C;AAGA,oBAAY,aAAa,KAAK,QAAQ,IAAI,CAAC,WAAW,OAAO,SAAS;AAEtE,mBAAW,aAAa,KAAK,kBAAkB;AAC7C,sBAAY,WAAW,KAAK,SAAS;AAAA,QACvC;AAEA,cAAM,2BAAS,KAAK,sBAAsB,GAAG,KAAK,QAAQ,KAAK,UAAU,WAAW,CAAC;AAGrF,6BAAO,MAAM,2BAAoB,KAAK,qBAAqB,KAAK,QAAQ,wBAAwB,YAAY,YAAY,CAAC,GAAG,eAAe;AAAA,MAE7I,SAAS,GAAP;AACA,6CAAmB,+BAA0B,KAAK;AAAA,EAAqB,EAAE,OAAO;AAAA,MAClF;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAsB,qBAAqB,UAAU;AACnD,SAAO,MAAM,2BAAS,KAAK,qBAAqB,GAAG,QAAQ;AAC7D;AAEO,SAAS,wBAAwB;AACtC,SAAO;AACT;AAEO,SAAS,uBAAuB;AACrC,SAAO;AACT;",
|
|
6
6
|
"names": ["debug"]
|
|
7
7
|
}
|
package/build/utils/DevMode.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import debug from "debug";
|
|
2
2
|
import { logger } from "../Logger";
|
|
3
3
|
import { debugAndPrintError } from "../Debug";
|
|
4
|
-
import {
|
|
4
|
+
import { getLocalRoomById, handleCreateRoom, presence, remoteRoomCall } from "../MatchMaker";
|
|
5
5
|
const debugDevMode = debug("colyseus:devmode");
|
|
6
6
|
let isDevMode = false;
|
|
7
7
|
function setDevMode(bool) {
|
|
@@ -14,7 +14,7 @@ async function reloadFromCache() {
|
|
|
14
14
|
const roomHistory = JSON.parse(value);
|
|
15
15
|
debugDevMode("restoring room %s (%s)", roomHistory.roomName, roomId);
|
|
16
16
|
const recreatedRoomListing = await handleCreateRoom(roomHistory.roomName, roomHistory.clientOptions, roomId);
|
|
17
|
-
const recreatedRoom =
|
|
17
|
+
const recreatedRoom = getLocalRoomById(recreatedRoomListing.roomId);
|
|
18
18
|
logger.debug(`\u{1F504} room '${roomId}' has been restored.`);
|
|
19
19
|
if (roomHistory.hasOwnProperty("state")) {
|
|
20
20
|
recreatedRoom.state.decode(roomHistory.state);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/DevMode.ts"],
|
|
4
|
-
"sourcesContent": ["import debug from \"debug\";\nimport { logger } from \"../Logger\";\nimport { debugAndPrintError } from \"../Debug\";\n\nimport {
|
|
5
|
-
"mappings": "AAAA,OAAO,WAAW;AAClB,SAAS,cAAc;AACvB,SAAS,0BAA0B;AAEnC,SAAS,
|
|
4
|
+
"sourcesContent": ["import debug from \"debug\";\nimport { logger } from \"../Logger\";\nimport { debugAndPrintError } from \"../Debug\";\n\nimport { getLocalRoomById, handleCreateRoom, presence, remoteRoomCall } from \"../MatchMaker\";\nimport type { Room } from \"../Room\";\n\nexport const debugDevMode = debug('colyseus:devmode');\n\nexport let isDevMode: boolean = false;\n\nexport function setDevMode(bool: boolean) {\n isDevMode = bool;\n}\n\nexport async function reloadFromCache() {\n const roomHistoryList = Object.entries(await presence.hgetall(getRoomRestoreListKey()));\n debugDevMode(\"rooms to restore: %i\", roomHistoryList.length);\n\n for (const [roomId, value] of roomHistoryList) {\n const roomHistory = JSON.parse(value);\n debugDevMode(\"restoring room %s (%s)\", roomHistory.roomName, roomId);\n\n const recreatedRoomListing = await handleCreateRoom(roomHistory.roomName, roomHistory.clientOptions, roomId);\n const recreatedRoom = getLocalRoomById(recreatedRoomListing.roomId);\n logger.debug(`\uD83D\uDD04 room '${roomId}' has been restored.`);\n\n // Set previous state\n if (roomHistory.hasOwnProperty(\"state\")) {\n recreatedRoom.state.decode(roomHistory.state);\n\n //\n // WORKAROUND: @colyseus/schema is not capable of encoding a decoded\n // state. thus, we need a fresh clone immediately after decoding\n //\n recreatedRoom.setState(recreatedRoom.state.clone());\n logger.debug(`\uD83D\uDCCB room '${roomId}' state =>`, recreatedRoom.state.toJSON());\n }\n\n // call `onRestoreRoom` with custom 'cache'd property.\n recreatedRoom.onRestoreRoom?.(roomHistory[\"cache\"]);\n\n // Reserve seats for clients from cached history\n if (roomHistory.clients) {\n for (const previousSessionId of roomHistory.clients) {\n // reserve seat for 20 seconds\n await remoteRoomCall(recreatedRoomListing.roomId, '_reserveSeat', [previousSessionId, {}, 20, false, true]);\n }\n }\n }\n\n if (roomHistoryList.length > 0) {\n logger.debug(\"\u2705\", roomHistoryList.length, \"room(s) have been restored.\");\n }\n}\n\nexport async function cacheRoomHistory(rooms: { [roomId: string]: Room }) {\n for (const room of Object.values(rooms)) {\n const roomHistoryResult = await presence.hget(getRoomRestoreListKey(), room.roomId);\n if (roomHistoryResult) {\n try {\n const roomHistory = JSON.parse(roomHistoryResult);\n\n // custom cache method\n roomHistory[\"cache\"] = room.onCacheRoom?.();\n\n // encode state\n debugDevMode(\"caching room %s (%s)\", room.roomName, room.roomId);\n\n if (room.state) {\n roomHistory[\"state\"] = room.state.encodeAll();\n }\n\n // cache active clients and reserved seats\n roomHistory[\"clients\"] = room.clients.map((client) => client.sessionId);\n\n for (const sessionId in room['reservedSeats']) {\n roomHistory[\"clients\"].push(sessionId);\n }\n\n await presence.hset(getRoomRestoreListKey(), room.roomId, JSON.stringify(roomHistory));\n\n // Rewrite updated room history\n logger.debug(`\uD83D\uDCBE caching room '${room.roomId}' (clients: ${room.clients.length}, state size: ${(roomHistory[\"state\"] || []).length} bytes)`);\n\n } catch (e) {\n debugAndPrintError(`\u274C couldn't cache room '${room.roomId}', due to:\\n${e.stack}`);\n }\n }\n }\n}\n\nexport async function getPreviousProcessId(hostname) {\n return await presence.hget(getProcessRestoreKey(), hostname);\n}\n\nexport function getRoomRestoreListKey() {\n return 'roomhistory';\n}\n\nexport function getProcessRestoreKey() {\n return 'processhistory';\n}\n"],
|
|
5
|
+
"mappings": "AAAA,OAAO,WAAW;AAClB,SAAS,cAAc;AACvB,SAAS,0BAA0B;AAEnC,SAAS,kBAAkB,kBAAkB,UAAU,sBAAsB;AAGtE,MAAM,eAAe,MAAM,kBAAkB;AAE7C,IAAI,YAAqB;AAEzB,SAAS,WAAW,MAAe;AACxC,cAAY;AACd;AAEA,eAAsB,kBAAkB;AACtC,QAAM,kBAAkB,OAAO,QAAQ,MAAM,SAAS,QAAQ,sBAAsB,CAAC,CAAC;AACtF,eAAa,wBAAwB,gBAAgB,MAAM;AAE3D,aAAW,CAAC,QAAQ,KAAK,KAAK,iBAAiB;AAC7C,UAAM,cAAc,KAAK,MAAM,KAAK;AACpC,iBAAa,0BAA0B,YAAY,UAAU,MAAM;AAEnE,UAAM,uBAAuB,MAAM,iBAAiB,YAAY,UAAU,YAAY,eAAe,MAAM;AAC3G,UAAM,gBAAgB,iBAAiB,qBAAqB,MAAM;AAClE,WAAO,MAAM,mBAAY,4BAA4B;AAGrD,QAAI,YAAY,eAAe,OAAO,GAAG;AACvC,oBAAc,MAAM,OAAO,YAAY,KAAK;AAM5C,oBAAc,SAAS,cAAc,MAAM,MAAM,CAAC;AAClD,aAAO,MAAM,mBAAY,oBAAoB,cAAc,MAAM,OAAO,CAAC;AAAA,IAC3E;AAGA,kBAAc,gBAAgB,YAAY,QAAQ;AAGlD,QAAI,YAAY,SAAS;AACvB,iBAAW,qBAAqB,YAAY,SAAS;AAEnD,cAAM,eAAe,qBAAqB,QAAQ,gBAAgB,CAAC,mBAAmB,CAAC,GAAG,IAAI,OAAO,IAAI,CAAC;AAAA,MAC5G;AAAA,IACF;AAAA,EACF;AAEA,MAAI,gBAAgB,SAAS,GAAG;AAC9B,WAAO,MAAM,UAAK,gBAAgB,QAAQ,6BAA6B;AAAA,EACzE;AACF;AAEA,eAAsB,iBAAiB,OAAmC;AACxE,aAAW,QAAQ,OAAO,OAAO,KAAK,GAAG;AACvC,UAAM,oBAAoB,MAAM,SAAS,KAAK,sBAAsB,GAAG,KAAK,MAAM;AAClF,QAAI,mBAAmB;AACrB,UAAI;AACF,cAAM,cAAc,KAAK,MAAM,iBAAiB;AAGhD,oBAAY,WAAW,KAAK,cAAc;AAG1C,qBAAa,wBAAwB,KAAK,UAAU,KAAK,MAAM;AAE/D,YAAI,KAAK,OAAO;AACd,sBAAY,WAAW,KAAK,MAAM,UAAU;AAAA,QAC9C;AAGA,oBAAY,aAAa,KAAK,QAAQ,IAAI,CAAC,WAAW,OAAO,SAAS;AAEtE,mBAAW,aAAa,KAAK,kBAAkB;AAC7C,sBAAY,WAAW,KAAK,SAAS;AAAA,QACvC;AAEA,cAAM,SAAS,KAAK,sBAAsB,GAAG,KAAK,QAAQ,KAAK,UAAU,WAAW,CAAC;AAGrF,eAAO,MAAM,2BAAoB,KAAK,qBAAqB,KAAK,QAAQ,wBAAwB,YAAY,YAAY,CAAC,GAAG,eAAe;AAAA,MAE7I,SAAS,GAAP;AACA,2BAAmB,+BAA0B,KAAK;AAAA,EAAqB,EAAE,OAAO;AAAA,MAClF;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAsB,qBAAqB,UAAU;AACnD,SAAO,MAAM,SAAS,KAAK,qBAAqB,GAAG,QAAQ;AAC7D;AAEO,SAAS,wBAAwB;AACtC,SAAO;AACT;AAEO,SAAS,uBAAuB;AACrC,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/utils/Utils.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
/// <reference types="node" />
|
|
3
1
|
import { EventEmitter } from "events";
|
|
4
|
-
import { ServerOpts, Socket } from "net";
|
|
5
2
|
export declare const REMOTE_ROOM_SHORT_TIMEOUT: number;
|
|
3
|
+
export declare const MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME: number;
|
|
6
4
|
export declare function generateId(length?: number): any;
|
|
7
5
|
export declare function getBearerToken(authHeader: string): string;
|
|
8
6
|
export declare function registerGracefulShutdown(callback: (err?: Error) => void): void;
|
|
@@ -17,10 +15,5 @@ export declare class Deferred<T = any> {
|
|
|
17
15
|
catch(func: (value: any) => any): Promise<any>;
|
|
18
16
|
}
|
|
19
17
|
export declare function merge(a: any, ...objs: any[]): any;
|
|
20
|
-
export declare
|
|
21
|
-
constructor(options?: ServerOpts, connectionListener?: (socket: Socket) => void): any;
|
|
22
|
-
listen(port?: number, hostname?: string, backlog?: number, listeningListener?: () => void): this;
|
|
23
|
-
close(callback?: (err?: Error) => void): this;
|
|
24
|
-
}
|
|
25
|
-
export declare class DummyServer extends EventEmitter {
|
|
18
|
+
export declare class HttpServerMock extends EventEmitter {
|
|
26
19
|
}
|
package/build/utils/Utils.js
CHANGED
|
@@ -24,7 +24,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
24
24
|
var Utils_exports = {};
|
|
25
25
|
__export(Utils_exports, {
|
|
26
26
|
Deferred: () => Deferred,
|
|
27
|
-
|
|
27
|
+
HttpServerMock: () => HttpServerMock,
|
|
28
|
+
MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME: () => MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME,
|
|
28
29
|
REMOTE_ROOM_SHORT_TIMEOUT: () => REMOTE_ROOM_SHORT_TIMEOUT,
|
|
29
30
|
generateId: () => generateId,
|
|
30
31
|
getBearerToken: () => getBearerToken,
|
|
@@ -35,11 +36,12 @@ __export(Utils_exports, {
|
|
|
35
36
|
});
|
|
36
37
|
module.exports = __toCommonJS(Utils_exports);
|
|
37
38
|
var import_nanoid = __toESM(require("nanoid"));
|
|
38
|
-
var import_msgpackr = require("msgpackr");
|
|
39
|
+
var import_msgpackr = require("@colyseus/msgpackr");
|
|
39
40
|
var import_Debug = require("../Debug");
|
|
40
41
|
var import_events = require("events");
|
|
41
42
|
var import_schema = require("@colyseus/schema");
|
|
42
43
|
const REMOTE_ROOM_SHORT_TIMEOUT = Number(process.env.COLYSEUS_PRESENCE_SHORT_TIMEOUT || 2e3);
|
|
44
|
+
const MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME = Number(process.env.COLYSEUS_MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME || 1);
|
|
43
45
|
function generateId(length = 9) {
|
|
44
46
|
return (0, import_nanoid.default)(length);
|
|
45
47
|
}
|
|
@@ -103,7 +105,7 @@ function merge(a, ...objs) {
|
|
|
103
105
|
}
|
|
104
106
|
return a;
|
|
105
107
|
}
|
|
106
|
-
class
|
|
108
|
+
class HttpServerMock extends import_events.EventEmitter {
|
|
107
109
|
}
|
|
108
110
|
(0, import_msgpackr.addExtension)({
|
|
109
111
|
Class: import_schema.Schema,
|
|
@@ -118,7 +120,8 @@ class DummyServer extends import_events.EventEmitter {
|
|
|
118
120
|
// Annotate the CommonJS export names for ESM import in node:
|
|
119
121
|
0 && (module.exports = {
|
|
120
122
|
Deferred,
|
|
121
|
-
|
|
123
|
+
HttpServerMock,
|
|
124
|
+
MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME,
|
|
122
125
|
REMOTE_ROOM_SHORT_TIMEOUT,
|
|
123
126
|
generateId,
|
|
124
127
|
getBearerToken,
|
package/build/utils/Utils.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/Utils.ts"],
|
|
4
|
-
"sourcesContent": ["import nanoid from 'nanoid';\nimport { addExtension } from 'msgpackr';\n\nimport { debugAndPrintError } from '../Debug';\nimport { EventEmitter } from \"events\";\nimport {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAmB;AACnB,sBAA6B;AAE7B,mBAAmC;AACnC,oBAA6B;
|
|
4
|
+
"sourcesContent": ["import nanoid from 'nanoid';\nimport { addExtension } from '@colyseus/msgpackr';\n\nimport { debugAndPrintError } from '../Debug';\nimport { EventEmitter } from \"events\";\nimport { Schema } from \"@colyseus/schema\";\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 || 1);\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) => {\n if (\n errorWhiteList.indexOf(e.constructor) !== -1 &&\n retries++ < maxRetries\n ) {\n setTimeout(() => {\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() {\n this.promise = new Promise<T>((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n\n public then(func: (value: T) => any) {\n return this.promise.then.apply(this.promise, arguments);\n }\n\n public catch(func: (value: any) => any) {\n return this.promise.catch(func);\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 (b.hasOwnProperty(key)) {\n a[key] = b[key];\n }\n }\n }\n return a;\n}\n\nexport class HttpServerMock extends EventEmitter {}\n\n// Add msgpackr extension to avoid circular references when encoding\n// https://github.com/kriszyp/msgpackr#custom-extensions\naddExtension({\n Class: Schema,\n type: 0,\n\n read(datum: any): any {\n return datum;\n },\n\n write(instance: any): any {\n return instance.toJSON();\n }\n});\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAmB;AACnB,sBAA6B;AAE7B,mBAAmC;AACnC,oBAA6B;AAC7B,oBAAuB;AAGhB,MAAM,4BAA4B,OAAO,QAAQ,IAAI,mCAAmC,GAAI;AAC5F,MAAM,uCAAuC,OAAO,QAAQ,IAAI,iDAAiD,CAAC;AAElH,SAAS,WAAW,SAAiB,GAAG;AAC7C,aAAO,cAAAA,SAAO,MAAM;AACtB;AAEO,SAAS,eAAe,YAAoB;AACjD,SAAQ,cAAc,WAAW,WAAW,SAAS,KAAK,WAAW,UAAU,GAAG,WAAW,MAAM,KAAM;AAC3G;AAKA,MAAM,UAA4B,CAAC,UAAU,WAAW,SAAS;AAE1D,SAAS,yBAAyB,UAAiC;AAIxE,UAAQ,GAAG,qBAAqB,CAAC,QAAQ;AACvC,yCAAmB,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,MAAM;AACZ,UACE,eAAe,QAAQ,EAAE,WAAW,MAAM,MAC1C,YAAY,YACZ;AACA,mBAAW,MAAM;AACf,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,KAAK,IAAI,IAAI;AAAA,EACnB;AAEA,MAAI,SAAS;AACb,SAAO;AACT;AAEO,MAAM,SAAiB;AAAA,EAM5B,cAAc;AACZ,SAAK,UAAU,IAAI,QAAW,CAAC,SAAS,WAAW;AACjD,WAAK,UAAU;AACf,WAAK,SAAS;AAAA,IAChB,CAAC;AAAA,EACH;AAAA,EAEO,KAAK,MAAyB;AACnC,WAAO,KAAK,QAAQ,KAAK,MAAM,KAAK,SAAS,SAAS;AAAA,EACxD;AAAA,EAEO,MAAM,MAA2B;AACtC,WAAO,KAAK,QAAQ,MAAM,IAAI;AAAA,EAChC;AAEF;AAEO,SAAS,MAAM,MAAW,MAAkB;AACjD,WAAS,IAAI,GAAG,MAAM,KAAK,QAAQ,IAAI,KAAK,KAAK;AAC/C,UAAM,IAAI,KAAK;AACf,eAAW,OAAO,GAAG;AACnB,UAAI,EAAE,eAAe,GAAG,GAAG;AACzB,UAAE,OAAO,EAAE;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEO,MAAM,uBAAuB,2BAAa;AAAC;AAAA,IAIlD,8BAAa;AAAA,EACX,OAAO;AAAA,EACP,MAAM;AAAA,EAEN,KAAK,OAAiB;AACpB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAoB;AACxB,WAAO,SAAS,OAAO;AAAA,EACzB;AACF,CAAC;",
|
|
6
6
|
"names": ["nanoid"]
|
|
7
7
|
}
|