@colyseus/core 0.15.11-alpha.1 → 0.15.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/build/MatchMaker.d.ts +13 -11
  2. package/build/MatchMaker.js +53 -66
  3. package/build/MatchMaker.js.map +2 -2
  4. package/build/MatchMaker.mjs +52 -62
  5. package/build/MatchMaker.mjs.map +2 -2
  6. package/build/Room.d.ts +2 -5
  7. package/build/Room.js +32 -23
  8. package/build/Room.js.map +2 -2
  9. package/build/Room.mjs +32 -23
  10. package/build/Room.mjs.map +2 -2
  11. package/build/Server.d.ts +9 -5
  12. package/build/Server.js +4 -12
  13. package/build/Server.js.map +2 -2
  14. package/build/Server.mjs +4 -12
  15. package/build/Server.mjs.map +2 -2
  16. package/build/Stats.d.ts +12 -0
  17. package/build/Stats.js +84 -0
  18. package/build/Stats.js.map +7 -0
  19. package/build/Stats.mjs +56 -0
  20. package/build/Stats.mjs.map +7 -0
  21. package/build/index.d.ts +4 -4
  22. package/build/index.js +0 -10
  23. package/build/index.js.map +2 -2
  24. package/build/index.mjs +4 -9
  25. package/build/index.mjs.map +2 -2
  26. package/build/matchmaker/RegisteredHandler.d.ts +3 -7
  27. package/build/matchmaker/RegisteredHandler.js +0 -5
  28. package/build/matchmaker/RegisteredHandler.js.map +2 -2
  29. package/build/matchmaker/RegisteredHandler.mjs +0 -5
  30. package/build/matchmaker/RegisteredHandler.mjs.map +2 -2
  31. package/build/matchmaker/controller.d.ts +1 -3
  32. package/build/matchmaker/controller.js +3 -6
  33. package/build/matchmaker/controller.js.map +2 -2
  34. package/build/matchmaker/controller.mjs +3 -6
  35. package/build/matchmaker/controller.mjs.map +2 -2
  36. package/build/matchmaker/driver/index.d.ts +1 -1
  37. package/build/matchmaker/driver/index.js +2 -13
  38. package/build/matchmaker/driver/index.js.map +2 -2
  39. package/build/matchmaker/driver/index.mjs +1 -7
  40. package/build/matchmaker/driver/index.mjs.map +2 -2
  41. package/build/matchmaker/driver/interfaces.d.ts +1 -1
  42. package/build/matchmaker/driver/interfaces.js.map +1 -1
  43. package/build/utils/types.d.ts +1 -0
  44. package/build/utils/types.js +15 -0
  45. package/build/utils/types.js.map +7 -0
  46. package/build/utils/types.mjs +0 -0
  47. package/build/utils/types.mjs.map +7 -0
  48. package/package.json +2 -2
@@ -2,11 +2,13 @@ import { Deferred } from './utils/Utils';
2
2
  import { RegisteredHandler } from './matchmaker/RegisteredHandler';
3
3
  import { Room } from './Room';
4
4
  import { Presence } from './presence/Presence';
5
- import { IRoomListingData, MatchMakerDriver, RoomListingData } from './matchmaker/driver';
5
+ import { IRoomListingData, RoomListingData, MatchMakerDriver } from './matchmaker/driver';
6
6
  import controller from './matchmaker/controller';
7
- import { Type } from './types';
8
- export { MatchMakerDriver, controller };
7
+ import * as stats from "./Stats";
8
+ import { Type } from './utils/types';
9
+ export { controller, stats, type MatchMakerDriver };
9
10
  export type ClientOptions = any;
11
+ export type SelectProcessIdCallback = (roomName: string, clientOptions: ClientOptions) => Promise<string>;
10
12
  export interface SeatReservation {
11
13
  sessionId: string;
12
14
  room: RoomListingData;
@@ -16,10 +18,13 @@ export declare let publicAddress: string;
16
18
  export declare let processId: string;
17
19
  export declare let presence: Presence;
18
20
  export declare let driver: MatchMakerDriver;
21
+ export declare let selectProcessIdToCreateRoom: SelectProcessIdCallback;
19
22
  export declare let isGracefullyShuttingDown: boolean;
20
23
  export declare let onReady: Deferred;
21
- export declare let roomCount: number;
22
- export declare function setup(_presence?: Presence, _driver?: MatchMakerDriver, _publicAddress?: string): Promise<void>;
24
+ /**
25
+ * @private
26
+ */
27
+ export declare function setup(_presence?: Presence, _driver?: MatchMakerDriver, _publicAddress?: string, _selectProcessIdToCreateRoom?: SelectProcessIdCallback): Promise<void>;
23
28
  /**
24
29
  * Join or create into a room and return seat reservation
25
30
  */
@@ -71,11 +76,9 @@ export declare function findOneRoomAvailable(roomName: string, clientOptions: Cl
71
76
  * @returns Promise<any> - Returned value from the called or retrieved method/attribute.
72
77
  */
73
78
  export declare function remoteRoomCall<R = any>(roomId: string, method: string, args?: any[], rejectionTimeout?: number): Promise<R>;
74
- export declare function defineRoomType<T extends Type<Room>>(roomName: string, klass: T, defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0]): RegisteredHandler;
75
- export declare function removeRoomType(roomName: string): void;
76
- export declare function hasHandler(roomName: string): boolean;
77
- export declare function getHandler(roomName: string): RegisteredHandler;
78
- export declare function getRoomClass(roomName: string): typeof Room;
79
+ export declare function defineRoomType<T extends Type<Room>>(name: string, klass: T, defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0]): RegisteredHandler;
80
+ export declare function removeRoomType(name: string): void;
81
+ export declare function hasHandler(name: string): boolean;
79
82
  /**
80
83
  * Creates a new room.
81
84
  *
@@ -96,4 +99,3 @@ export declare function gracefullyShutdown(): Promise<any>;
96
99
  * Reserve a seat for a client in a room
97
100
  */
98
101
  export declare function reserveSeatFor(room: RoomListingData, options: any): Promise<SeatReservation>;
99
- export declare function getRoomCountKey(): string;
@@ -23,7 +23,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
24
24
  var MatchMaker_exports = {};
25
25
  __export(MatchMaker_exports, {
26
- MatchMakerDriver: () => import_driver.MatchMakerDriver,
27
26
  controller: () => import_controller.default,
28
27
  create: () => create,
29
28
  createRoom: () => createRoom,
@@ -31,10 +30,7 @@ __export(MatchMaker_exports, {
31
30
  disconnectAll: () => disconnectAll,
32
31
  driver: () => driver,
33
32
  findOneRoomAvailable: () => findOneRoomAvailable,
34
- getHandler: () => getHandler,
35
33
  getRoomById: () => getRoomById,
36
- getRoomClass: () => getRoomClass,
37
- getRoomCountKey: () => getRoomCountKey,
38
34
  gracefullyShutdown: () => gracefullyShutdown,
39
35
  handleCreateRoom: () => handleCreateRoom,
40
36
  hasHandler: () => hasHandler,
@@ -51,8 +47,9 @@ __export(MatchMaker_exports, {
51
47
  remoteRoomCall: () => remoteRoomCall,
52
48
  removeRoomType: () => removeRoomType,
53
49
  reserveSeatFor: () => reserveSeatFor,
54
- roomCount: () => roomCount,
55
- setup: () => setup
50
+ selectProcessIdToCreateRoom: () => selectProcessIdToCreateRoom,
51
+ setup: () => setup,
52
+ stats: () => stats
56
53
  });
57
54
  module.exports = __toCommonJS(MatchMaker_exports);
58
55
  var import_Protocol = require("./Protocol");
@@ -67,6 +64,7 @@ var import_SeatReservationError = require("./errors/SeatReservationError");
67
64
  var import_ServerError = require("./errors/ServerError");
68
65
  var import_driver = require("./matchmaker/driver");
69
66
  var import_controller = __toESM(require("./matchmaker/controller"));
67
+ var stats = __toESM(require("./Stats"));
70
68
  var import_Logger = require("./Logger");
71
69
  var import_discovery = require("./discovery");
72
70
  const handlers = {};
@@ -75,10 +73,10 @@ let publicAddress;
75
73
  let processId;
76
74
  let presence;
77
75
  let driver;
76
+ let selectProcessIdToCreateRoom;
78
77
  let isGracefullyShuttingDown;
79
78
  let onReady;
80
- let roomCount = 0;
81
- async function setup(_presence, _driver, _publicAddress) {
79
+ async function setup(_presence, _driver, _publicAddress, _selectProcessIdToCreateRoom) {
82
80
  onReady = new import_Utils.Deferred();
83
81
  presence = _presence || new import_LocalPresence.LocalPresence();
84
82
  driver = _driver || new import_driver.LocalDriver();
@@ -90,10 +88,13 @@ async function setup(_presence, _driver, _publicAddress) {
90
88
  processId = (0, import_Utils.generateId)();
91
89
  }
92
90
  isGracefullyShuttingDown = false;
91
+ selectProcessIdToCreateRoom = _selectProcessIdToCreateRoom || async function() {
92
+ return (await stats.fetchAll()).sort((p1, p2) => p1.roomCount > p2.roomCount ? 1 : -1)[0].processId;
93
+ };
93
94
  (0, import_IPC.subscribeIPC)(presence, processId, getProcessChannel(), (_, args) => {
94
95
  return handleCreateRoom.apply(void 0, args);
95
96
  });
96
- await presence.hset(getRoomCountKey(), processId, roomCount.toString());
97
+ await stats.reset();
97
98
  if (import_DevMode.isDevMode) {
98
99
  await (0, import_DevMode.reloadFromCache)();
99
100
  }
@@ -124,8 +125,10 @@ async function join(roomName, clientOptions = {}) {
124
125
  async function reconnect(roomId, clientOptions = {}) {
125
126
  const room = await driver.findOne({ roomId });
126
127
  if (!room) {
127
- import_Logger.logger.info(`\u274C room "${roomId}" has been disposed. Did you missed .allowReconnection()?
128
+ if (process.env.NODE_ENV !== "production") {
129
+ import_Logger.logger.info(`\u274C room "${roomId}" has been disposed. Did you missed .allowReconnection()?
128
130
  \u{1F449} https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);
131
+ }
129
132
  throw new import_ServerError.ServerError(import_Protocol.ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room "${roomId}" has been disposed.`);
130
133
  }
131
134
  const reconnectionToken = clientOptions.reconnectionToken;
@@ -136,8 +139,10 @@ async function reconnect(roomId, clientOptions = {}) {
136
139
  if (sessionId) {
137
140
  return { room, sessionId };
138
141
  } else {
139
- import_Logger.logger.info(`\u274C reconnection token invalid or expired. Did you missed .allowReconnection()?
142
+ if (process.env.NODE_ENV !== "production") {
143
+ import_Logger.logger.info(`\u274C reconnection token invalid or expired. Did you missed .allowReconnection()?
140
144
  \u{1F449} https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);
145
+ }
141
146
  throw new import_ServerError.ServerError(import_Protocol.ErrorCode.MATCHMAKE_EXPIRED, `reconnection token invalid or expired.`);
142
147
  }
143
148
  }
@@ -155,7 +160,10 @@ async function query(conditions = {}) {
155
160
  }
156
161
  async function findOneRoomAvailable(roomName, clientOptions) {
157
162
  return await awaitRoomAvailable(roomName, async () => {
158
- const handler = getHandler(roomName);
163
+ const handler = handlers[roomName];
164
+ if (!handler) {
165
+ throw new import_ServerError.ServerError(import_Protocol.ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name "${roomName}" not defined`);
166
+ }
159
167
  const roomQuery = driver.findOne({
160
168
  locked: false,
161
169
  name: roomName,
@@ -172,7 +180,7 @@ async function remoteRoomCall(roomId, method, args, rejectionTimeout = import_Ut
172
180
  const room = rooms[roomId];
173
181
  if (!room) {
174
182
  try {
175
- return await (0, import_IPC.requestFromIPC)(presence, getRoomChannel(roomId), method, args);
183
+ return await (0, import_IPC.requestFromIPC)(presence, getRoomChannel(roomId), method, args, rejectionTimeout);
176
184
  } catch (e) {
177
185
  const request = `${method}${args && " with args " + JSON.stringify(args) || ""}`;
178
186
  throw new import_ServerError.ServerError(
@@ -184,57 +192,40 @@ async function remoteRoomCall(roomId, method, args, rejectionTimeout = import_Ut
184
192
  return !args && typeof room[method] !== "function" ? room[method] : await room[method].apply(room, args && args.map((arg) => JSON.parse(JSON.stringify(arg))));
185
193
  }
186
194
  }
187
- function defineRoomType(roomName, klass, defaultOptions) {
195
+ function defineRoomType(name, klass, defaultOptions) {
188
196
  const registeredHandler = new import_RegisteredHandler.RegisteredHandler(klass, defaultOptions);
189
- handlers[roomName] = registeredHandler;
190
- if (klass.prototype["onAuth"] !== import_Room.Room.prototype["onAuth"]) {
191
- console.warn("onAuth() at the instance level will be deprecated soon. Please use static onAuth() instead.");
192
- }
197
+ handlers[name] = registeredHandler;
193
198
  if (!import_DevMode.isDevMode) {
194
- cleanupStaleRooms(roomName);
199
+ cleanupStaleRooms(name);
195
200
  }
196
201
  return registeredHandler;
197
202
  }
198
- function removeRoomType(roomName) {
199
- delete handlers[roomName];
203
+ function removeRoomType(name) {
204
+ delete handlers[name];
200
205
  if (!import_DevMode.isDevMode) {
201
- cleanupStaleRooms(roomName);
202
- }
203
- }
204
- function hasHandler(roomName) {
205
- console.warn("hasHandler() is deprecated. Use getHandler() instead.");
206
- return handlers[roomName] !== void 0;
207
- }
208
- function getHandler(roomName) {
209
- const handler = handlers[roomName];
210
- if (!handler) {
211
- throw new import_ServerError.ServerError(import_Protocol.ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name "${roomName}" not defined`);
206
+ cleanupStaleRooms(name);
212
207
  }
213
- return handler;
214
208
  }
215
- function getRoomClass(roomName) {
216
- return getHandler(roomName).klass;
209
+ function hasHandler(name) {
210
+ return handlers[name] !== void 0;
217
211
  }
218
212
  async function createRoom(roomName, clientOptions) {
219
- const roomsSpawnedByProcessId = await presence.hgetall(getRoomCountKey());
220
- const processIdWithFewerRooms = Object.keys(roomsSpawnedByProcessId).sort((p1, p2) => {
221
- return Number(roomsSpawnedByProcessId[p1]) > Number(roomsSpawnedByProcessId[p2]) ? 1 : -1;
222
- })[0] || processId;
213
+ const selectedProcessId = await selectProcessIdToCreateRoom(roomName, clientOptions);
223
214
  let room;
224
- if (processIdWithFewerRooms === processId) {
215
+ if (selectedProcessId === processId) {
225
216
  room = await handleCreateRoom(roomName, clientOptions);
226
217
  } else {
227
218
  try {
228
219
  room = await (0, import_IPC.requestFromIPC)(
229
220
  presence,
230
- getProcessChannel(processIdWithFewerRooms),
221
+ getProcessChannel(selectedProcessId),
231
222
  void 0,
232
223
  [roomName, clientOptions],
233
224
  import_Utils.REMOTE_ROOM_SHORT_TIMEOUT
234
225
  );
235
226
  } catch (e) {
236
- await presence.hdel(getRoomCountKey(), processIdWithFewerRooms);
237
227
  (0, import_Debug.debugAndPrintError)(e);
228
+ await stats.excludeProcess(selectedProcessId);
238
229
  room = await handleCreateRoom(roomName, clientOptions);
239
230
  }
240
231
  }
@@ -248,8 +239,11 @@ async function createRoom(roomName, clientOptions) {
248
239
  return room;
249
240
  }
250
241
  async function handleCreateRoom(roomName, clientOptions, restoringRoomId) {
251
- const handler = getHandler(roomName);
252
- const room = new handler.klass();
242
+ const registeredHandler = handlers[roomName];
243
+ if (!registeredHandler) {
244
+ throw new import_ServerError.ServerError(import_Protocol.ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name "${roomName}" not defined`);
245
+ }
246
+ const room = new registeredHandler.klass();
253
247
  if (restoringRoomId && import_DevMode.isDevMode) {
254
248
  room.roomId = restoringRoomId;
255
249
  } else {
@@ -257,7 +251,7 @@ async function handleCreateRoom(roomName, clientOptions, restoringRoomId) {
257
251
  }
258
252
  room.roomName = roomName;
259
253
  room.presence = presence;
260
- const additionalListingData = handler.getFilterOptions(clientOptions);
254
+ const additionalListingData = registeredHandler.getFilterOptions(clientOptions);
261
255
  if (publicAddress) {
262
256
  additionalListingData.publicAddress = publicAddress;
263
257
  }
@@ -268,9 +262,7 @@ async function handleCreateRoom(roomName, clientOptions, restoringRoomId) {
268
262
  });
269
263
  if (room.onCreate) {
270
264
  try {
271
- await room.onCreate((0, import_Utils.merge)({}, clientOptions, handler.options));
272
- roomCount++;
273
- presence.hset(getRoomCountKey(), processId, roomCount.toString());
265
+ await room.onCreate((0, import_Utils.merge)({}, clientOptions, registeredHandler.options));
274
266
  } catch (e) {
275
267
  (0, import_Debug.debugAndPrintError)(e);
276
268
  throw new import_ServerError.ServerError(
@@ -283,6 +275,8 @@ async function handleCreateRoom(roomName, clientOptions, restoringRoomId) {
283
275
  room.listing.roomId = room.roomId;
284
276
  room.listing.maxClients = room.maxClients;
285
277
  (0, import_Debug.debugMatchMaking)("spawning '%s', roomId: %s, processId: %s", roomName, room.roomId, processId);
278
+ stats.local.roomCount++;
279
+ stats.persist();
286
280
  room._events.on("lock", lockRoom.bind(this, room));
287
281
  room._events.on("unlock", unlockRoom.bind(this, room));
288
282
  room._events.on("join", onClientJoinRoom.bind(this, room));
@@ -291,7 +285,7 @@ async function handleCreateRoom(roomName, clientOptions, restoringRoomId) {
291
285
  room._events.once("disconnect", () => room._events.removeAllListeners());
292
286
  await createRoomReferences(room, true);
293
287
  await room.listing.save();
294
- handler.emit("create", room);
288
+ registeredHandler.emit("create", room);
295
289
  return room.listing;
296
290
  }
297
291
  function getRoomById(roomId) {
@@ -316,7 +310,7 @@ async function gracefullyShutdown() {
316
310
  if (import_DevMode.isDevMode) {
317
311
  await (0, import_DevMode.cacheRoomHistory)(rooms);
318
312
  }
319
- presence.hdel(getRoomCountKey(), processId);
313
+ stats.excludeProcess(processId);
320
314
  presence.unsubscribe(getProcessChannel());
321
315
  return Promise.all(disconnectAll(
322
316
  import_DevMode.isDevMode ? import_Protocol.Protocol.WS_CLOSE_DEVMODE_RESTART : void 0
@@ -398,11 +392,13 @@ async function awaitRoomAvailable(roomToJoin, callback) {
398
392
  });
399
393
  }
400
394
  function onClientJoinRoom(room, client) {
401
- presence.incr(getGlobalCCUCounter());
395
+ stats.local.ccu++;
396
+ stats.persist();
402
397
  handlers[room.roomName].emit("join", room, client);
403
398
  }
404
399
  function onClientLeaveRoom(room, client, willDispose) {
405
- presence.decr(getGlobalCCUCounter());
400
+ stats.local.ccu--;
401
+ stats.persist();
406
402
  handlers[room.roomName].emit("leave", room, client, willDispose);
407
403
  }
408
404
  function lockRoom(room) {
@@ -416,8 +412,8 @@ async function unlockRoom(room) {
416
412
  async function disposeRoom(roomName, room) {
417
413
  (0, import_Debug.debugMatchMaking)("disposing '%s' (%s) on processId '%s'", roomName, room.roomId, processId);
418
414
  if (!isGracefullyShuttingDown) {
419
- roomCount--;
420
- presence.hset(getRoomCountKey(), processId, roomCount.toString());
415
+ stats.local.roomCount--;
416
+ stats.persist();
421
417
  if (import_DevMode.isDevMode) {
422
418
  await presence.hdel((0, import_DevMode.getRoomRestoreListKey)(), room.roomId);
423
419
  }
@@ -427,9 +423,6 @@ async function disposeRoom(roomName, room) {
427
423
  presence.unsubscribe(getRoomChannel(room.roomId));
428
424
  delete rooms[room.roomId];
429
425
  }
430
- function getRoomCountKey() {
431
- return "roomcount";
432
- }
433
426
  function getRoomChannel(roomId) {
434
427
  return `$${roomId}`;
435
428
  }
@@ -439,12 +432,8 @@ function getHandlerConcurrencyKey(name) {
439
432
  function getProcessChannel(id = processId) {
440
433
  return `p:${id}`;
441
434
  }
442
- function getGlobalCCUCounter() {
443
- return "_ccu";
444
- }
445
435
  // Annotate the CommonJS export names for ESM import in node:
446
436
  0 && (module.exports = {
447
- MatchMakerDriver,
448
437
  controller,
449
438
  create,
450
439
  createRoom,
@@ -452,10 +441,7 @@ function getGlobalCCUCounter() {
452
441
  disconnectAll,
453
442
  driver,
454
443
  findOneRoomAvailable,
455
- getHandler,
456
444
  getRoomById,
457
- getRoomClass,
458
- getRoomCountKey,
459
445
  gracefullyShutdown,
460
446
  handleCreateRoom,
461
447
  hasHandler,
@@ -472,6 +458,7 @@ function getGlobalCCUCounter() {
472
458
  remoteRoomCall,
473
459
  removeRoomType,
474
460
  reserveSeatFor,
475
- roomCount,
476
- setup
461
+ selectProcessIdToCreateRoom,
462
+ setup,
463
+ stats
477
464
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/MatchMaker.ts"],
4
- "sourcesContent": ["import { ErrorCode, Protocol } from './Protocol';\n\nimport { requestFromIPC, subscribeIPC } from './IPC';\n\nimport { Deferred, generateId, merge, REMOTE_ROOM_SHORT_TIMEOUT, retry } from './utils/Utils';\nimport { isDevMode, cacheRoomHistory, getPreviousProcessId, getRoomRestoreListKey, reloadFromCache } from './utils/DevMode';\n\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler';\nimport { Room, RoomInternalState } from './Room';\n\nimport { LocalPresence } from './presence/LocalPresence';\nimport { Presence } from './presence/Presence';\n\nimport { debugAndPrintError, debugMatchMaking } from './Debug';\nimport { SeatReservationError } from './errors/SeatReservationError';\nimport { ServerError } from './errors/ServerError';\n\nimport { IRoomListingData, MatchMakerDriver, RoomListingData, LocalDriver } from './matchmaker/driver';\nimport controller from './matchmaker/controller';\n\nimport { logger } from './Logger';\nimport { Client } from './Transport';\nimport { Type } from './types';\nimport { getHostname } from \"./discovery\";\n\nexport { MatchMakerDriver, controller };\n\nexport type ClientOptions = any;\n\nexport interface SeatReservation {\n sessionId: string;\n room: RoomListingData;\n devMode?: boolean;\n}\n\nconst handlers: {[id: string]: RegisteredHandler} = {};\nconst rooms: {[roomId: string]: Room} = {};\n\nexport let publicAddress: string;\nexport let processId: string;\nexport let presence: Presence;\nexport let driver: MatchMakerDriver;\n\nexport let isGracefullyShuttingDown: boolean;\nexport let onReady: Deferred;\n\nexport let roomCount = 0;\n\nexport async function setup(\n _presence?: Presence,\n _driver?: MatchMakerDriver,\n _publicAddress?: string,\n) {\n onReady = new Deferred();\n presence = _presence || new LocalPresence();\n driver = _driver || new LocalDriver();\n publicAddress = _publicAddress;\n\n // devMode: try to retrieve previous processId\n if (isDevMode) { processId = await getPreviousProcessId(await getHostname()); }\n\n // ensure processId is set\n if (!processId) { processId = generateId(); }\n\n isGracefullyShuttingDown = false;\n\n /**\n * Subscribe to remote `handleCreateRoom` calls.\n */\n subscribeIPC(presence, processId, getProcessChannel(), (_, args) => {\n return handleCreateRoom.apply(undefined, args);\n });\n\n await presence.hset(getRoomCountKey(), processId, roomCount.toString());\n\n if (isDevMode) {\n await reloadFromCache();\n }\n\n onReady.resolve();\n}\n\n/**\n * Join or create into a room and return seat reservation\n */\nexport async function joinOrCreate(roomName: string, clientOptions: ClientOptions = {}) {\n return await retry<Promise<SeatReservation>>(async () => {\n let room = await findOneRoomAvailable(roomName, clientOptions);\n\n if (!room) {\n room = await createRoom(roomName, clientOptions);\n }\n\n return await reserveSeatFor(room, clientOptions);\n }, 5, [SeatReservationError]);\n}\n\n/**\n * Create a room and return seat reservation\n */\nexport async function create(roomName: string, clientOptions: ClientOptions = {}) {\n const room = await createRoom(roomName, clientOptions);\n return reserveSeatFor(room, clientOptions);\n}\n\n/**\n * Join a room and return seat reservation\n */\nexport async function join(roomName: string, clientOptions: ClientOptions = {}) {\n return await retry<Promise<SeatReservation>>(async () => {\n const room = await findOneRoomAvailable(roomName, clientOptions);\n\n if (!room) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_CRITERIA, `no rooms found with provided criteria`);\n }\n\n return reserveSeatFor(room, clientOptions);\n });\n}\n\n/**\n * Join a room by id and return seat reservation\n */\nexport async function reconnect(roomId: string, clientOptions: ClientOptions = {}) {\n const room = await driver.findOne({ roomId });\n if (!room) {\n logger.info(`\u274C room \"${roomId}\" has been disposed. Did you missed .allowReconnection()?\\n\uD83D\uDC49 https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" has been disposed.`);\n }\n\n // check for reconnection\n const reconnectionToken = clientOptions.reconnectionToken;\n if (!reconnectionToken) { throw new ServerError(ErrorCode.MATCHMAKE_UNHANDLED, `'reconnectionToken' must be provided for reconnection.`); }\n\n // respond to re-connection!\n const sessionId = await remoteRoomCall(room.roomId, 'checkReconnectionToken', [reconnectionToken]);\n if (sessionId) {\n return { room, sessionId };\n\n } else {\n logger.info(`\u274C reconnection token invalid or expired. Did you missed .allowReconnection()?\\n\uD83D\uDC49 https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, `reconnection token invalid or expired.`);\n }\n}\n\n/**\n * Join a room by id and return client seat reservation. An exception is thrown if a room is not found for roomId.\n *\n * @param roomId - The Id of the specific room instance.\n * @param clientOptions - Options for the client seat reservation (for `onJoin`/`onAuth`)\n *\n * @returns Promise<SeatReservation> - A promise which contains `sessionId` and `RoomListingData`.\n */\nexport async function joinById(roomId: string, clientOptions: ClientOptions = {}) {\n const room = await driver.findOne({ roomId });\n\n if (!room) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" not found`);\n\n } else if (room.locked) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" is locked`);\n }\n\n return reserveSeatFor(room, clientOptions);\n}\n\n/**\n * Perform a query for all cached rooms\n */\nexport async function query(conditions: Partial<IRoomListingData> = {}) {\n return await driver.find(conditions);\n}\n\n/**\n * Find for a public and unlocked room available.\n *\n * @param roomName - The Id of the specific room.\n * @param clientOptions - Options for the client seat reservation (for `onJoin`/`onAuth`).\n *\n * @returns Promise<RoomListingData> - A promise contaning an object which includes room metadata and configurations.\n */\nexport async function findOneRoomAvailable(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n return await awaitRoomAvailable(roomName, async () => {\n const handler = getHandler(roomName);\n\n const roomQuery = driver.findOne({\n locked: false,\n name: roomName,\n private: false,\n ...handler.getFilterOptions(clientOptions),\n });\n\n if (handler.sortOptions) {\n roomQuery.sort(handler.sortOptions);\n }\n\n return await roomQuery;\n });\n}\n\n/**\n * Call a method or return a property on a remote room.\n *\n * @param roomId - The Id of the specific room instance.\n * @param method - Method or attribute to call or retrive.\n * @param args - Array of arguments for the method\n *\n * @returns Promise<any> - Returned value from the called or retrieved method/attribute.\n */\nexport async function remoteRoomCall<R= any>(\n roomId: string,\n method: string,\n args?: any[],\n rejectionTimeout = REMOTE_ROOM_SHORT_TIMEOUT,\n): Promise<R> {\n const room = rooms[roomId];\n\n if (!room) {\n try {\n return await requestFromIPC<R>(presence, getRoomChannel(roomId), method, args);\n\n } catch (e) {\n const request = `${method}${args && ' with args ' + JSON.stringify(args) || ''}`;\n throw new ServerError(\n ErrorCode.MATCHMAKE_UNHANDLED,\n `remote room (${roomId}) timed out, requesting \"${request}\". (${rejectionTimeout}ms exceeded)`,\n );\n }\n\n } else {\n return (!args && typeof (room[method]) !== 'function')\n ? room[method]\n : (await room[method].apply(room, args && args.map((arg) => JSON.parse(JSON.stringify(arg)))));\n }\n}\n\nexport function defineRoomType<T extends Type<Room>>(\n roomName: string,\n klass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n) {\n const registeredHandler = new RegisteredHandler(klass, defaultOptions);\n\n handlers[roomName] = registeredHandler;\n\n // TODO: remove this check on version 0.16\n if (klass.prototype['onAuth'] !== Room.prototype['onAuth']) {\n console.warn(\"onAuth() at the instance level will be deprecated soon. Please use static onAuth() instead.\");\n }\n\n if (!isDevMode) {\n cleanupStaleRooms(roomName);\n }\n\n return registeredHandler;\n}\n\nexport function removeRoomType(roomName: string) {\n delete handlers[roomName];\n\n if (!isDevMode) {\n cleanupStaleRooms(roomName);\n }\n}\n\n// TODO: legacy; remove me on 1.0\nexport function hasHandler(roomName: string) {\n console.warn(\"hasHandler() is deprecated. Use getHandler() instead.\");\n return handlers[roomName] !== undefined;\n}\n\nexport function getHandler(roomName: string) {\n const handler = handlers[roomName];\n\n if (!handler) {\n throw new ServerError(ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n }\n\n return handler;\n}\n\nexport function getRoomClass(roomName: string) {\n return getHandler(roomName).klass as unknown as typeof Room\n}\n\n/**\n * Creates a new room.\n *\n * @param roomName - The identifier you defined on `gameServer.define()`\n * @param clientOptions - Options for `onCreate`\n *\n * @returns Promise<RoomListingData> - A promise contaning an object which includes room metadata and configurations.\n */\nexport async function createRoom(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n const roomsSpawnedByProcessId = await presence.hgetall(getRoomCountKey());\n\n const processIdWithFewerRooms = (\n Object.keys(roomsSpawnedByProcessId).sort((p1, p2) => {\n return (Number(roomsSpawnedByProcessId[p1]) > Number(roomsSpawnedByProcessId[p2]))\n ? 1\n : -1;\n })[0]\n ) || processId;\n\n let room: RoomListingData;\n if (processIdWithFewerRooms === processId) {\n // create the room on this process!\n room = await handleCreateRoom(roomName, clientOptions);\n } else {\n // ask other process to create the room!\n try {\n room = await requestFromIPC<RoomListingData>(\n presence,\n getProcessChannel(processIdWithFewerRooms),\n undefined,\n [roomName, clientOptions],\n REMOTE_ROOM_SHORT_TIMEOUT,\n );\n\n } catch (e) {\n //\n // clean-up possibly stale process from redis.\n // when a process disconnects ungracefully, it may leave its previous processId under \"roomcount\"\n // if the process is still alive, it will re-add itself shortly after the load-balancer selects it again.\n //\n await presence.hdel(getRoomCountKey(), processIdWithFewerRooms);\n\n // if other process failed to respond, create the room on this process\n debugAndPrintError(e);\n room = await handleCreateRoom(roomName, clientOptions);\n }\n }\n\n if (isDevMode) {\n presence.hset(getRoomRestoreListKey(), room.roomId, JSON.stringify({\n \"clientOptions\": clientOptions,\n \"roomName\": roomName,\n \"processId\": processId\n }));\n }\n\n return room;\n}\n\nexport async function handleCreateRoom(roomName: string, clientOptions: ClientOptions, restoringRoomId?: string): Promise<RoomListingData> {\n const handler = getHandler(roomName);\n const room = new handler.klass();\n\n // set room public attributes\n if (restoringRoomId && isDevMode) {\n room.roomId = restoringRoomId;\n\n } else {\n room.roomId = generateId();\n }\n\n room.roomName = roomName;\n room.presence = presence;\n\n const additionalListingData: any = handler.getFilterOptions(clientOptions);\n\n // assign public host\n if (publicAddress) {\n additionalListingData.publicAddress = publicAddress;\n }\n\n // create a RoomCache reference.\n room.listing = driver.createInstance({\n name: roomName,\n processId,\n ...additionalListingData\n });\n\n if (room.onCreate) {\n try {\n await room.onCreate(merge({}, clientOptions, handler.options));\n\n // increment amount of rooms this process is handling\n roomCount++;\n presence.hset(getRoomCountKey(), processId, roomCount.toString());\n } catch (e) {\n debugAndPrintError(e);\n throw new ServerError(\n e.code || ErrorCode.MATCHMAKE_UNHANDLED,\n e.message,\n );\n }\n }\n\n room['_internalState'] = RoomInternalState.CREATED;\n\n room.listing.roomId = room.roomId;\n room.listing.maxClients = room.maxClients;\n\n // imediatelly ask client to join the room\n debugMatchMaking('spawning \\'%s\\', roomId: %s, processId: %s', roomName, room.roomId, processId);\n\n room._events.on('lock', lockRoom.bind(this, room));\n room._events.on('unlock', unlockRoom.bind(this, room));\n room._events.on('join', onClientJoinRoom.bind(this, room));\n room._events.on('leave', onClientLeaveRoom.bind(this, room));\n room._events.once('dispose', disposeRoom.bind(this, roomName, room));\n room._events.once('disconnect', () => room._events.removeAllListeners());\n\n // room always start unlocked\n await createRoomReferences(room, true);\n await room.listing.save();\n\n handler.emit('create', room);\n\n return room.listing;\n}\n\nexport function getRoomById(roomId: string) {\n return rooms[roomId];\n}\n\n/**\n * Disconnects every client on every room in the current process.\n */\nexport function disconnectAll(closeCode?: number) {\n const promises: Array<Promise<any>> = [];\n\n for (const roomId in rooms) {\n if (!rooms.hasOwnProperty(roomId)) { continue; }\n promises.push(rooms[roomId].disconnect(closeCode));\n }\n\n return promises;\n}\n\nexport async function gracefullyShutdown(): Promise<any> {\n if (isGracefullyShuttingDown) {\n return Promise.reject('already_shutting_down');\n }\n\n isGracefullyShuttingDown = true;\n\n debugMatchMaking(`${processId} is shutting down!`);\n\n if (isDevMode) {\n await cacheRoomHistory(rooms);\n }\n\n // remove processId from room count key\n presence.hdel(getRoomCountKey(), processId);\n\n // unsubscribe from process id channel\n presence.unsubscribe(getProcessChannel());\n\n return Promise.all(disconnectAll(\n (isDevMode)\n ? Protocol.WS_CLOSE_DEVMODE_RESTART\n : undefined\n ));\n}\n\n/**\n * Reserve a seat for a client in a room\n */\nexport async function reserveSeatFor(room: RoomListingData, options: any) {\n const sessionId: string = generateId();\n\n debugMatchMaking(\n 'reserving seat. sessionId: \\'%s\\', roomId: \\'%s\\', processId: \\'%s\\'',\n sessionId, room.roomId, processId,\n );\n\n let successfulSeatReservation: boolean;\n\n try {\n successfulSeatReservation = await remoteRoomCall(room.roomId, '_reserveSeat', [sessionId, options]);\n\n } catch (e) {\n debugMatchMaking(e);\n successfulSeatReservation = false;\n }\n\n if (!successfulSeatReservation) {\n throw new SeatReservationError(`${room.roomId} is already full.`);\n }\n\n const response: SeatReservation = { room, sessionId };\n\n if (isDevMode) {\n response.devMode = isDevMode;\n }\n\n return response;\n}\n\nasync function cleanupStaleRooms(roomName: string) {\n //\n // clean-up possibly stale room ids\n // (ungraceful shutdowns using Redis can result on stale room ids still on memory.)\n //\n const cachedRooms = await driver.find({ name: roomName }, { _id: 1 });\n\n // remove connecting counts\n await presence.del(getHandlerConcurrencyKey(roomName));\n\n await Promise.all(cachedRooms.map(async (room) => {\n try {\n // use hardcoded short timeout for cleaning up stale rooms.\n await remoteRoomCall(room.roomId, 'roomId');\n\n } catch (e) {\n debugMatchMaking(`cleaning up stale room '${roomName}', roomId: ${room.roomId}`);\n room.remove();\n }\n }));\n}\n\nasync function createRoomReferences(room: Room, init: boolean = false): Promise<boolean> {\n rooms[room.roomId] = room;\n\n if (init) {\n await subscribeIPC(\n presence,\n processId,\n getRoomChannel(room.roomId),\n (method, args) => {\n return (!args && typeof (room[method]) !== 'function')\n ? room[method]\n : room[method].apply(room, args);\n },\n );\n }\n\n return true;\n}\n\nasync function awaitRoomAvailable(roomToJoin: string, callback: Function): Promise<RoomListingData> {\n return new Promise(async (resolve, reject) => {\n const concurrencyKey = getHandlerConcurrencyKey(roomToJoin);\n const concurrency = await presence.incr(concurrencyKey) - 1;\n\n //\n // avoid having too long timeout if 10+ clients ask to join at the same time\n //\n // TODO: we need a better solution here. either a lock or queue system should be implemented instead.\n // https://github.com/colyseus/colyseus/issues/466\n //\n const concurrencyTimeout = Math.min(concurrency * 100, 500);\n\n if (concurrency > 0) {\n debugMatchMaking(\n 'receiving %d concurrent requests for joining \\'%s\\' (waiting %d ms)',\n concurrency, roomToJoin, concurrencyTimeout,\n );\n }\n\n setTimeout(async () => {\n try {\n const result = await callback();\n resolve(result);\n\n } catch (e) {\n reject(e);\n\n } finally {\n await presence.decr(concurrencyKey);\n }\n }, concurrencyTimeout);\n });\n}\n\nfunction onClientJoinRoom(room: Room, client: Client) {\n // increment global CCU\n presence.incr(getGlobalCCUCounter());\n handlers[room.roomName].emit('join', room, client);\n}\n\nfunction onClientLeaveRoom(room: Room, client: Client, willDispose: boolean) {\n // decrement global CCU\n presence.decr(getGlobalCCUCounter());\n handlers[room.roomName].emit('leave', room, client, willDispose);\n}\n\nfunction lockRoom(room: Room): void {\n // emit public event on registered handler\n handlers[room.roomName].emit('lock', room);\n}\n\nasync function unlockRoom(room: Room) {\n if (await createRoomReferences(room)) {\n // emit public event on registered handler\n handlers[room.roomName].emit('unlock', room);\n }\n}\n\nasync function disposeRoom(roomName: string, room: Room) {\n debugMatchMaking('disposing \\'%s\\' (%s) on processId \\'%s\\'', roomName, room.roomId, processId);\n\n // decrease amount of rooms this process is handling\n if (!isGracefullyShuttingDown) {\n roomCount--;\n presence.hset(getRoomCountKey(), processId, roomCount.toString());\n\n // remove from devMode restore list\n if (isDevMode) {\n await presence.hdel(getRoomRestoreListKey(), room.roomId);\n }\n }\n\n // emit disposal on registered session handler\n handlers[roomName].emit('dispose', room);\n\n // remove concurrency key\n presence.del(getHandlerConcurrencyKey(roomName));\n\n // unsubscribe from remote connections\n presence.unsubscribe(getRoomChannel(room.roomId));\n\n // remove actual room reference\n delete rooms[room.roomId];\n}\n\n//\n// Presence keys\n//\nexport function getRoomCountKey() {\n return 'roomcount';\n}\n\nfunction getRoomChannel(roomId: string) {\n return `$${roomId}`;\n}\n\nfunction getHandlerConcurrencyKey(name: string) {\n return `c:${name}`;\n}\n\nfunction getProcessChannel(id: string = processId) {\n return `p:${id}`;\n}\n\nfunction getGlobalCCUCounter() {\n return \"_ccu\";\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { ErrorCode, Protocol } from './Protocol';\n\nimport { requestFromIPC, subscribeIPC } from './IPC';\n\nimport { Deferred, generateId, merge, REMOTE_ROOM_SHORT_TIMEOUT, retry } from './utils/Utils';\nimport { isDevMode, cacheRoomHistory, getPreviousProcessId, getRoomRestoreListKey, reloadFromCache } from './utils/DevMode';\n\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler';\nimport { Room, RoomInternalState } from './Room';\n\nimport { LocalPresence } from './presence/LocalPresence';\nimport { Presence } from './presence/Presence';\n\nimport { debugAndPrintError, debugMatchMaking } from './Debug';\nimport { SeatReservationError } from './errors/SeatReservationError';\nimport { ServerError } from './errors/ServerError';\n\nimport { IRoomListingData, RoomListingData, LocalDriver, MatchMakerDriver } from './matchmaker/driver';\nimport controller from './matchmaker/controller';\nimport * as stats from \"./Stats\";\n\nimport { logger } from './Logger';\nimport { Client } from './Transport';\nimport { Type } from './utils/types';\nimport { getHostname } from \"./discovery\";\n\nexport { controller, stats, type MatchMakerDriver };\n\nexport type ClientOptions = any;\nexport type SelectProcessIdCallback = (roomName: string, clientOptions: ClientOptions) => Promise<string>;\n\nexport interface SeatReservation {\n sessionId: string;\n room: RoomListingData;\n devMode?: boolean;\n}\n\nconst handlers: {[id: string]: RegisteredHandler} = {};\nconst rooms: {[roomId: string]: Room} = {};\n\nexport let publicAddress: string;\nexport let processId: string;\nexport let presence: Presence;\nexport let driver: MatchMakerDriver;\nexport let selectProcessIdToCreateRoom: SelectProcessIdCallback;\n\nexport let isGracefullyShuttingDown: boolean;\nexport let onReady: Deferred;\n\n/**\n * @private\n */\nexport async function setup(\n _presence?: Presence,\n _driver?: MatchMakerDriver,\n _publicAddress?: string,\n _selectProcessIdToCreateRoom?: SelectProcessIdCallback,\n) {\n onReady = new Deferred();\n presence = _presence || new LocalPresence();\n driver = _driver || new LocalDriver();\n publicAddress = _publicAddress;\n\n // devMode: try to retrieve previous processId\n if (isDevMode) { processId = await getPreviousProcessId(await getHostname()); }\n\n // ensure processId is set\n if (!processId) { processId = generateId(); }\n\n isGracefullyShuttingDown = false;\n\n /**\n * Define default `assignRoomToProcessId` method.\n * By default, return the process with least amount of rooms created\n */\n selectProcessIdToCreateRoom = _selectProcessIdToCreateRoom || async function () {\n return (await stats.fetchAll())\n .sort((p1, p2) => p1.roomCount > p2.roomCount ? 1 : -1)[0]\n .processId;\n };\n\n /**\n * Subscribe to remote `handleCreateRoom` calls.\n */\n subscribeIPC(presence, processId, getProcessChannel(), (_, args) => {\n return handleCreateRoom.apply(undefined, args);\n });\n\n await stats.reset();\n\n if (isDevMode) {\n await reloadFromCache();\n }\n\n onReady.resolve();\n}\n\n/**\n * Join or create into a room and return seat reservation\n */\nexport async function joinOrCreate(roomName: string, clientOptions: ClientOptions = {}) {\n return await retry<Promise<SeatReservation>>(async () => {\n let room = await findOneRoomAvailable(roomName, clientOptions);\n\n if (!room) {\n room = await createRoom(roomName, clientOptions);\n }\n\n return await reserveSeatFor(room, clientOptions);\n }, 5, [SeatReservationError]);\n}\n\n/**\n * Create a room and return seat reservation\n */\nexport async function create(roomName: string, clientOptions: ClientOptions = {}) {\n const room = await createRoom(roomName, clientOptions);\n return reserveSeatFor(room, clientOptions);\n}\n\n/**\n * Join a room and return seat reservation\n */\nexport async function join(roomName: string, clientOptions: ClientOptions = {}) {\n return await retry<Promise<SeatReservation>>(async () => {\n const room = await findOneRoomAvailable(roomName, clientOptions);\n\n if (!room) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_CRITERIA, `no rooms found with provided criteria`);\n }\n\n return reserveSeatFor(room, clientOptions);\n });\n}\n\n/**\n * Join a room by id and return seat reservation\n */\nexport async function reconnect(roomId: string, clientOptions: ClientOptions = {}) {\n const room = await driver.findOne({ roomId });\n if (!room) {\n // TODO: support a \"logLevel\" out of the box?\n if (process.env.NODE_ENV !== 'production') {\n logger.info(`\u274C room \"${roomId}\" has been disposed. Did you missed .allowReconnection()?\\n\uD83D\uDC49 https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);\n }\n\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" has been disposed.`);\n }\n\n // check for reconnection\n const reconnectionToken = clientOptions.reconnectionToken;\n if (!reconnectionToken) { throw new ServerError(ErrorCode.MATCHMAKE_UNHANDLED, `'reconnectionToken' must be provided for reconnection.`); }\n\n // respond to re-connection!\n const sessionId = await remoteRoomCall(room.roomId, 'checkReconnectionToken', [reconnectionToken]);\n if (sessionId) {\n return { room, sessionId };\n\n } else {\n // TODO: support a \"logLevel\" out of the box?\n if (process.env.NODE_ENV !== 'production') {\n logger.info(`\u274C reconnection token invalid or expired. Did you missed .allowReconnection()?\\n\uD83D\uDC49 https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);\n }\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, `reconnection token invalid or expired.`);\n }\n}\n\n/**\n * Join a room by id and return client seat reservation. An exception is thrown if a room is not found for roomId.\n *\n * @param roomId - The Id of the specific room instance.\n * @param clientOptions - Options for the client seat reservation (for `onJoin`/`onAuth`)\n *\n * @returns Promise<SeatReservation> - A promise which contains `sessionId` and `RoomListingData`.\n */\nexport async function joinById(roomId: string, clientOptions: ClientOptions = {}) {\n const room = await driver.findOne({ roomId });\n\n if (!room) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" not found`);\n\n } else if (room.locked) {\n throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" is locked`);\n }\n\n return reserveSeatFor(room, clientOptions);\n}\n\n/**\n * Perform a query for all cached rooms\n */\nexport async function query(conditions: Partial<IRoomListingData> = {}) {\n return await driver.find(conditions);\n}\n\n/**\n * Find for a public and unlocked room available.\n *\n * @param roomName - The Id of the specific room.\n * @param clientOptions - Options for the client seat reservation (for `onJoin`/`onAuth`).\n *\n * @returns Promise<RoomListingData> - A promise contaning an object which includes room metadata and configurations.\n */\nexport async function findOneRoomAvailable(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n return await awaitRoomAvailable(roomName, async () => {\n const handler = handlers[roomName];\n if (!handler) {\n throw new ServerError( ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n }\n\n const roomQuery = driver.findOne({\n locked: false,\n name: roomName,\n private: false,\n ...handler.getFilterOptions(clientOptions),\n });\n\n if (handler.sortOptions) {\n roomQuery.sort(handler.sortOptions);\n }\n\n return await roomQuery;\n });\n}\n\n/**\n * Call a method or return a property on a remote room.\n *\n * @param roomId - The Id of the specific room instance.\n * @param method - Method or attribute to call or retrive.\n * @param args - Array of arguments for the method\n *\n * @returns Promise<any> - Returned value from the called or retrieved method/attribute.\n */\nexport async function remoteRoomCall<R= any>(\n roomId: string,\n method: string,\n args?: any[],\n rejectionTimeout = REMOTE_ROOM_SHORT_TIMEOUT,\n): Promise<R> {\n const room = rooms[roomId];\n\n if (!room) {\n try {\n return await requestFromIPC<R>(presence, getRoomChannel(roomId), method, args, rejectionTimeout);\n\n } catch (e) {\n const request = `${method}${args && ' with args ' + JSON.stringify(args) || ''}`;\n throw new ServerError(\n ErrorCode.MATCHMAKE_UNHANDLED,\n `remote room (${roomId}) timed out, requesting \"${request}\". (${rejectionTimeout}ms exceeded)`,\n );\n }\n\n } else {\n return (!args && typeof (room[method]) !== 'function')\n ? room[method]\n : (await room[method].apply(room, args && args.map((arg) => JSON.parse(JSON.stringify(arg)))));\n }\n}\n\nexport function defineRoomType<T extends Type<Room>>(\n name: string,\n klass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n) {\n const registeredHandler = new RegisteredHandler(klass, defaultOptions);\n\n handlers[name] = registeredHandler;\n\n if (!isDevMode) {\n cleanupStaleRooms(name);\n }\n\n return registeredHandler;\n}\n\nexport function removeRoomType(name: string) {\n delete handlers[name];\n\n if (!isDevMode) {\n cleanupStaleRooms(name);\n }\n}\n\nexport function hasHandler(name: string) {\n return handlers[ name ] !== undefined;\n}\n\n/**\n * Creates a new room.\n *\n * @param roomName - The identifier you defined on `gameServer.define()`\n * @param clientOptions - Options for `onCreate`\n *\n * @returns Promise<RoomListingData> - A promise contaning an object which includes room metadata and configurations.\n */\nexport async function createRoom(roomName: string, clientOptions: ClientOptions): Promise<RoomListingData> {\n const selectedProcessId = await selectProcessIdToCreateRoom(roomName, clientOptions);\n\n let room: RoomListingData;\n if (selectedProcessId === processId) {\n // create the room on this process!\n room = await handleCreateRoom(roomName, clientOptions);\n\n } else {\n // ask other process to create the room!\n try {\n room = await requestFromIPC<RoomListingData>(\n presence,\n getProcessChannel(selectedProcessId),\n undefined,\n [roomName, clientOptions],\n REMOTE_ROOM_SHORT_TIMEOUT,\n );\n\n } catch (e) {\n debugAndPrintError(e);\n\n //\n // clean-up possibly stale process from redis.\n // when a process disconnects ungracefully, it may leave its previous processId under \"roomcount\"\n // if the process is still alive, it will re-add itself shortly after the load-balancer selects it again.\n //\n await stats.excludeProcess(selectedProcessId);\n\n // if other process failed to respond, create the room on this process\n room = await handleCreateRoom(roomName, clientOptions);\n }\n }\n\n if (isDevMode) {\n presence.hset(getRoomRestoreListKey(), room.roomId, JSON.stringify({\n \"clientOptions\": clientOptions,\n \"roomName\": roomName,\n \"processId\": processId\n }));\n }\n\n return room;\n}\n\nexport async function handleCreateRoom(roomName: string, clientOptions: ClientOptions, restoringRoomId?: string): Promise<RoomListingData> {\n const registeredHandler = handlers[roomName];\n\n if (!registeredHandler) {\n throw new ServerError( ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n }\n\n const room = new registeredHandler.klass();\n\n // set room public attributes\n if (restoringRoomId && isDevMode) {\n room.roomId = restoringRoomId;\n\n } else {\n room.roomId = generateId();\n }\n\n room.roomName = roomName;\n room.presence = presence;\n\n const additionalListingData: any = registeredHandler.getFilterOptions(clientOptions);\n\n // assign public host\n if (publicAddress) {\n additionalListingData.publicAddress = publicAddress;\n }\n\n // create a RoomCache reference.\n room.listing = driver.createInstance({\n name: roomName,\n processId,\n ...additionalListingData\n });\n\n if (room.onCreate) {\n try {\n await room.onCreate(merge({}, clientOptions, registeredHandler.options));\n\n } catch (e) {\n debugAndPrintError(e);\n throw new ServerError(\n e.code || ErrorCode.MATCHMAKE_UNHANDLED,\n e.message,\n );\n }\n }\n\n room['_internalState'] = RoomInternalState.CREATED;\n\n room.listing.roomId = room.roomId;\n room.listing.maxClients = room.maxClients;\n\n // imediatelly ask client to join the room\n debugMatchMaking('spawning \\'%s\\', roomId: %s, processId: %s', roomName, room.roomId, processId);\n\n // increment amount of rooms this process is handling\n stats.local.roomCount++;\n stats.persist();\n\n room._events.on('lock', lockRoom.bind(this, room));\n room._events.on('unlock', unlockRoom.bind(this, room));\n room._events.on('join', onClientJoinRoom.bind(this, room));\n room._events.on('leave', onClientLeaveRoom.bind(this, room));\n room._events.once('dispose', disposeRoom.bind(this, roomName, room));\n room._events.once('disconnect', () => room._events.removeAllListeners());\n\n // room always start unlocked\n await createRoomReferences(room, true);\n await room.listing.save();\n\n registeredHandler.emit('create', room);\n\n return room.listing;\n}\n\nexport function getRoomById(roomId: string) {\n return rooms[roomId];\n}\n\n/**\n * Disconnects every client on every room in the current process.\n */\nexport function disconnectAll(closeCode?: number) {\n const promises: Array<Promise<any>> = [];\n\n for (const roomId in rooms) {\n if (!rooms.hasOwnProperty(roomId)) { continue; }\n promises.push(rooms[roomId].disconnect(closeCode));\n }\n\n return promises;\n}\n\nexport async function gracefullyShutdown(): Promise<any> {\n if (isGracefullyShuttingDown) {\n return Promise.reject('already_shutting_down');\n }\n\n isGracefullyShuttingDown = true;\n\n debugMatchMaking(`${processId} is shutting down!`);\n\n if (isDevMode) {\n await cacheRoomHistory(rooms);\n }\n\n // remove processId from room count key\n stats.excludeProcess(processId);\n\n // unsubscribe from process id channel\n presence.unsubscribe(getProcessChannel());\n\n return Promise.all(disconnectAll(\n (isDevMode)\n ? Protocol.WS_CLOSE_DEVMODE_RESTART\n : undefined\n ));\n}\n\n/**\n * Reserve a seat for a client in a room\n */\nexport async function reserveSeatFor(room: RoomListingData, options: any) {\n const sessionId: string = generateId();\n\n debugMatchMaking(\n 'reserving seat. sessionId: \\'%s\\', roomId: \\'%s\\', processId: \\'%s\\'',\n sessionId, room.roomId, processId,\n );\n\n let successfulSeatReservation: boolean;\n\n try {\n successfulSeatReservation = await remoteRoomCall(room.roomId, '_reserveSeat', [sessionId, options]);\n\n } catch (e) {\n debugMatchMaking(e);\n successfulSeatReservation = false;\n }\n\n if (!successfulSeatReservation) {\n throw new SeatReservationError(`${room.roomId} is already full.`);\n }\n\n const response: SeatReservation = { room, sessionId };\n\n if (isDevMode) {\n response.devMode = isDevMode;\n }\n\n return response;\n}\n\nasync function cleanupStaleRooms(roomName: string) {\n //\n // clean-up possibly stale room ids\n // (ungraceful shutdowns using Redis can result on stale room ids still on memory.)\n //\n const cachedRooms = await driver.find({ name: roomName }, { _id: 1 });\n\n // remove connecting counts\n await presence.del(getHandlerConcurrencyKey(roomName));\n\n await Promise.all(cachedRooms.map(async (room) => {\n try {\n // use hardcoded short timeout for cleaning up stale rooms.\n await remoteRoomCall(room.roomId, 'roomId');\n\n } catch (e) {\n debugMatchMaking(`cleaning up stale room '${roomName}', roomId: ${room.roomId}`);\n room.remove();\n }\n }));\n}\n\nasync function createRoomReferences(room: Room, init: boolean = false): Promise<boolean> {\n rooms[room.roomId] = room;\n\n if (init) {\n await subscribeIPC(\n presence,\n processId,\n getRoomChannel(room.roomId),\n (method, args) => {\n return (!args && typeof (room[method]) !== 'function')\n ? room[method]\n : room[method].apply(room, args);\n },\n );\n }\n\n return true;\n}\n\nasync function awaitRoomAvailable(roomToJoin: string, callback: Function): Promise<RoomListingData> {\n return new Promise(async (resolve, reject) => {\n const concurrencyKey = getHandlerConcurrencyKey(roomToJoin);\n const concurrency = await presence.incr(concurrencyKey) - 1;\n\n //\n // avoid having too long timeout if 10+ clients ask to join at the same time\n //\n // TODO: we need a better solution here. either a lock or queue system should be implemented instead.\n // https://github.com/colyseus/colyseus/issues/466\n //\n const concurrencyTimeout = Math.min(concurrency * 100, 500);\n\n if (concurrency > 0) {\n debugMatchMaking(\n 'receiving %d concurrent requests for joining \\'%s\\' (waiting %d ms)',\n concurrency, roomToJoin, concurrencyTimeout,\n );\n }\n\n setTimeout(async () => {\n try {\n const result = await callback();\n resolve(result);\n\n } catch (e) {\n reject(e);\n\n } finally {\n await presence.decr(concurrencyKey);\n }\n }, concurrencyTimeout);\n });\n}\n\nfunction onClientJoinRoom(room: Room, client: Client) {\n // increment local CCU\n stats.local.ccu++;\n stats.persist();\n\n handlers[room.roomName].emit('join', room, client);\n}\n\nfunction onClientLeaveRoom(room: Room, client: Client, willDispose: boolean) {\n // decrement local CCU\n stats.local.ccu--;\n stats.persist();\n\n handlers[room.roomName].emit('leave', room, client, willDispose);\n}\n\nfunction lockRoom(room: Room): void {\n // emit public event on registered handler\n handlers[room.roomName].emit('lock', room);\n}\n\nasync function unlockRoom(room: Room) {\n if (await createRoomReferences(room)) {\n // emit public event on registered handler\n handlers[room.roomName].emit('unlock', room);\n }\n}\n\nasync function disposeRoom(roomName: string, room: Room) {\n debugMatchMaking('disposing \\'%s\\' (%s) on processId \\'%s\\'', roomName, room.roomId, processId);\n\n // decrease amount of rooms this process is handling\n if (!isGracefullyShuttingDown) {\n stats.local.roomCount--;\n stats.persist();\n\n // remove from devMode restore list\n if (isDevMode) {\n await presence.hdel(getRoomRestoreListKey(), room.roomId);\n }\n }\n\n // emit disposal on registered session handler\n handlers[roomName].emit('dispose', room);\n\n // remove concurrency key\n presence.del(getHandlerConcurrencyKey(roomName));\n\n // unsubscribe from remote connections\n presence.unsubscribe(getRoomChannel(room.roomId));\n\n // remove actual room reference\n delete rooms[room.roomId];\n}\n\n//\n// Presence keys\n//\nfunction getRoomChannel(roomId: string) {\n return `$${roomId}`;\n}\n\nfunction getHandlerConcurrencyKey(name: string) {\n return `c:${name}`;\n}\n\nfunction getProcessChannel(id: string = processId) {\n return `p:${id}`;\n}"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,sCAAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAoC;AAEpC,iBAA6C;AAE7C,mBAA8E;AAC9E,qBAA0G;AAE1G,+BAAkC;AAClC,kBAAwC;AAExC,2BAA8B;AAG9B,mBAAqD;AACrD,kCAAqC;AACrC,yBAA4B;AAE5B,oBAAiF;AACjF,wBAAuB;AACvB,YAAuB;AAEvB,oBAAuB;AAGvB,uBAA4B;AAa5B,MAAM,WAA8C,CAAC;AACrD,MAAM,QAAkC,CAAC;AAElC,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AAEJ,IAAI;AACJ,IAAI;AAKX,eAAsB,MACpB,WACA,SACA,gBACA,8BACA;AACA,YAAU,IAAI,sBAAS;AACvB,aAAW,aAAa,IAAI,mCAAc;AAC1C,WAAS,WAAW,IAAI,0BAAY;AACpC,kBAAgB;AAGhB,MAAI,0BAAW;AAAE,gBAAY,UAAM,qCAAqB,UAAM,8BAAY,CAAC;AAAA,EAAG;AAG9E,MAAI,CAAC,WAAW;AAAE,oBAAY,yBAAW;AAAA,EAAG;AAE5C,6BAA2B;AAM3B,gCAA8B,gCAAgC,iBAAkB;AAC9E,YAAQ,MAAM,MAAM,SAAS,GAC1B,KAAK,CAAC,IAAI,OAAO,GAAG,YAAY,GAAG,YAAY,IAAI,EAAE,EAAE,GACvD;AAAA,EACL;AAKA,+BAAa,UAAU,WAAW,kBAAkB,GAAG,CAAC,GAAG,SAAS;AAClE,WAAO,iBAAiB,MAAM,QAAW,IAAI;AAAA,EAC/C,CAAC;AAED,QAAM,MAAM,MAAM;AAElB,MAAI,0BAAW;AACb,cAAM,gCAAgB;AAAA,EACxB;AAEA,UAAQ,QAAQ;AAClB;AAKA,eAAsB,aAAa,UAAkB,gBAA+B,CAAC,GAAG;AACtF,SAAO,UAAM,oBAAgC,YAAY;AACvD,QAAI,OAAO,MAAM,qBAAqB,UAAU,aAAa;AAE7D,QAAI,CAAC,MAAM;AACT,aAAO,MAAM,WAAW,UAAU,aAAa;AAAA,IACjD;AAEA,WAAO,MAAM,eAAe,MAAM,aAAa;AAAA,EACjD,GAAG,GAAG,CAAC,gDAAoB,CAAC;AAC9B;AAKA,eAAsB,OAAO,UAAkB,gBAA+B,CAAC,GAAG;AAChF,QAAM,OAAO,MAAM,WAAW,UAAU,aAAa;AACrD,SAAO,eAAe,MAAM,aAAa;AAC3C;AAKA,eAAsB,KAAK,UAAkB,gBAA+B,CAAC,GAAG;AAC9E,SAAO,UAAM,oBAAgC,YAAY;AACvD,UAAM,OAAO,MAAM,qBAAqB,UAAU,aAAa;AAE/D,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,+BAAY,0BAAU,4BAA4B,uCAAuC;AAAA,IACrG;AAEA,WAAO,eAAe,MAAM,aAAa;AAAA,EAC3C,CAAC;AACH;AAKA,eAAsB,UAAU,QAAgB,gBAA+B,CAAC,GAAG;AACjF,QAAM,OAAO,MAAM,OAAO,QAAQ,EAAE,OAAO,CAAC;AAC5C,MAAI,CAAC,MAAM;AAET,QAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,2BAAO,KAAK,gBAAW;AAAA,iFAA4I;AAAA,IACrK;AAEA,UAAM,IAAI,+BAAY,0BAAU,2BAA2B,SAAS,4BAA4B;AAAA,EAClG;AAGA,QAAM,oBAAoB,cAAc;AACxC,MAAI,CAAC,mBAAmB;AAAE,UAAM,IAAI,+BAAY,0BAAU,qBAAqB,wDAAwD;AAAA,EAAG;AAG1I,QAAM,YAAY,MAAM,eAAe,KAAK,QAAQ,0BAA0B,CAAC,iBAAiB,CAAC;AACjG,MAAI,WAAW;AACb,WAAO,EAAE,MAAM,UAAU;AAAA,EAE3B,OAAO;AAEL,QAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,2BAAO,KAAK;AAAA,iFAA0J;AAAA,IACxK;AACA,UAAM,IAAI,+BAAY,0BAAU,mBAAmB,wCAAwC;AAAA,EAC7F;AACF;AAUA,eAAsB,SAAS,QAAgB,gBAA+B,CAAC,GAAG;AAChF,QAAM,OAAO,MAAM,OAAO,QAAQ,EAAE,OAAO,CAAC;AAE5C,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,+BAAY,0BAAU,2BAA2B,SAAS,mBAAmB;AAAA,EAEzF,WAAW,KAAK,QAAQ;AACtB,UAAM,IAAI,+BAAY,0BAAU,2BAA2B,SAAS,mBAAmB;AAAA,EACzF;AAEA,SAAO,eAAe,MAAM,aAAa;AAC3C;AAKA,eAAsB,MAAM,aAAwC,CAAC,GAAG;AACtE,SAAO,MAAM,OAAO,KAAK,UAAU;AACrC;AAUA,eAAsB,qBAAqB,UAAkB,eAAwD;AACnH,SAAO,MAAM,mBAAmB,UAAU,YAAY;AACpD,UAAM,UAAU,SAAS;AACzB,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,+BAAa,0BAAU,sBAAsB,uBAAuB,uBAAuB;AAAA,IACvG;AAEA,UAAM,YAAY,OAAO,QAAQ;AAAA,MAC/B,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,MACT,GAAG,QAAQ,iBAAiB,aAAa;AAAA,IAC3C,CAAC;AAED,QAAI,QAAQ,aAAa;AACvB,gBAAU,KAAK,QAAQ,WAAW;AAAA,IACpC;AAEA,WAAO,MAAM;AAAA,EACf,CAAC;AACH;AAWA,eAAsB,eACpB,QACA,QACA,MACA,mBAAmB,wCACP;AACZ,QAAM,OAAO,MAAM;AAEnB,MAAI,CAAC,MAAM;AACT,QAAI;AACF,aAAO,UAAM,2BAAkB,UAAU,eAAe,MAAM,GAAG,QAAQ,MAAM,gBAAgB;AAAA,IAEjG,SAAS,GAAP;AACA,YAAM,UAAU,GAAG,SAAS,QAAQ,gBAAgB,KAAK,UAAU,IAAI,KAAK;AAC5E,YAAM,IAAI;AAAA,QACR,0BAAU;AAAA,QACV,gBAAgB,kCAAkC,cAAc;AAAA,MAClE;AAAA,IACF;AAAA,EAEF,OAAO;AACL,WAAQ,CAAC,QAAQ,OAAQ,KAAK,YAAa,aACrC,KAAK,UACJ,MAAM,KAAK,QAAQ,MAAM,MAAM,QAAQ,KAAK,IAAI,CAAC,QAAQ,KAAK,MAAM,KAAK,UAAU,GAAG,CAAC,CAAC,CAAC;AAAA,EAClG;AACF;AAEO,SAAS,eACd,MACA,OACA,gBACA;AACA,QAAM,oBAAoB,IAAI,2CAAkB,OAAO,cAAc;AAErE,WAAS,QAAQ;AAEjB,MAAI,CAAC,0BAAW;AACd,sBAAkB,IAAI;AAAA,EACxB;AAEA,SAAO;AACT;AAEO,SAAS,eAAe,MAAc;AAC3C,SAAO,SAAS;AAEhB,MAAI,CAAC,0BAAW;AACd,sBAAkB,IAAI;AAAA,EACxB;AACF;AAEO,SAAS,WAAW,MAAc;AACvC,SAAO,SAAU,UAAW;AAC9B;AAUA,eAAsB,WAAW,UAAkB,eAAwD;AACzG,QAAM,oBAAoB,MAAM,4BAA4B,UAAU,aAAa;AAEnF,MAAI;AACJ,MAAI,sBAAsB,WAAW;AAEnC,WAAO,MAAM,iBAAiB,UAAU,aAAa;AAAA,EAEvD,OAAO;AAEL,QAAI;AACF,aAAO,UAAM;AAAA,QACX;AAAA,QACA,kBAAkB,iBAAiB;AAAA,QACnC;AAAA,QACA,CAAC,UAAU,aAAa;AAAA,QACxB;AAAA,MACF;AAAA,IAEF,SAAS,GAAP;AACA,2CAAmB,CAAC;AAOpB,YAAM,MAAM,eAAe,iBAAiB;AAG5C,aAAO,MAAM,iBAAiB,UAAU,aAAa;AAAA,IACvD;AAAA,EACF;AAEA,MAAI,0BAAW;AACb,aAAS,SAAK,sCAAsB,GAAG,KAAK,QAAQ,KAAK,UAAU;AAAA,MACjE,iBAAiB;AAAA,MACjB,YAAY;AAAA,MACZ,aAAa;AAAA,IACf,CAAC,CAAC;AAAA,EACJ;AAEA,SAAO;AACT;AAEA,eAAsB,iBAAiB,UAAkB,eAA8B,iBAAoD;AACzI,QAAM,oBAAoB,SAAS;AAEnC,MAAI,CAAC,mBAAmB;AACtB,UAAM,IAAI,+BAAa,0BAAU,sBAAsB,uBAAuB,uBAAuB;AAAA,EACvG;AAEA,QAAM,OAAO,IAAI,kBAAkB,MAAM;AAGzC,MAAI,mBAAmB,0BAAW;AAChC,SAAK,SAAS;AAAA,EAEhB,OAAO;AACL,SAAK,aAAS,yBAAW;AAAA,EAC3B;AAEA,OAAK,WAAW;AAChB,OAAK,WAAW;AAEhB,QAAM,wBAA6B,kBAAkB,iBAAiB,aAAa;AAGnF,MAAI,eAAe;AACjB,0BAAsB,gBAAgB;AAAA,EACxC;AAGA,OAAK,UAAU,OAAO,eAAe;AAAA,IACnC,MAAM;AAAA,IACN;AAAA,IACA,GAAG;AAAA,EACL,CAAC;AAED,MAAI,KAAK,UAAU;AACjB,QAAI;AACF,YAAM,KAAK,aAAS,oBAAM,CAAC,GAAG,eAAe,kBAAkB,OAAO,CAAC;AAAA,IAEzE,SAAS,GAAP;AACA,2CAAmB,CAAC;AACpB,YAAM,IAAI;AAAA,QACR,EAAE,QAAQ,0BAAU;AAAA,QACpB,EAAE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAEA,OAAK,oBAAoB,8BAAkB;AAE3C,OAAK,QAAQ,SAAS,KAAK;AAC3B,OAAK,QAAQ,aAAa,KAAK;AAG/B,qCAAiB,4CAA8C,UAAU,KAAK,QAAQ,SAAS;AAG/F,QAAM,MAAM;AACZ,QAAM,QAAQ;AAEd,OAAK,QAAQ,GAAG,QAAQ,SAAS,KAAK,MAAM,IAAI,CAAC;AACjD,OAAK,QAAQ,GAAG,UAAU,WAAW,KAAK,MAAM,IAAI,CAAC;AACrD,OAAK,QAAQ,GAAG,QAAQ,iBAAiB,KAAK,MAAM,IAAI,CAAC;AACzD,OAAK,QAAQ,GAAG,SAAS,kBAAkB,KAAK,MAAM,IAAI,CAAC;AAC3D,OAAK,QAAQ,KAAK,WAAW,YAAY,KAAK,MAAM,UAAU,IAAI,CAAC;AACnE,OAAK,QAAQ,KAAK,cAAc,MAAM,KAAK,QAAQ,mBAAmB,CAAC;AAGvE,QAAM,qBAAqB,MAAM,IAAI;AACrC,QAAM,KAAK,QAAQ,KAAK;AAExB,oBAAkB,KAAK,UAAU,IAAI;AAErC,SAAO,KAAK;AACd;AAEO,SAAS,YAAY,QAAgB;AAC1C,SAAO,MAAM;AACf;AAKO,SAAS,cAAc,WAAoB;AAChD,QAAM,WAAgC,CAAC;AAEvC,aAAW,UAAU,OAAO;AAC1B,QAAI,CAAC,MAAM,eAAe,MAAM,GAAG;AAAE;AAAA,IAAU;AAC/C,aAAS,KAAK,MAAM,QAAQ,WAAW,SAAS,CAAC;AAAA,EACnD;AAEA,SAAO;AACT;AAEA,eAAsB,qBAAmC;AACvD,MAAI,0BAA0B;AAC5B,WAAO,QAAQ,OAAO,uBAAuB;AAAA,EAC/C;AAEA,6BAA2B;AAE3B,qCAAiB,GAAG,6BAA6B;AAEjD,MAAI,0BAAW;AACb,cAAM,iCAAiB,KAAK;AAAA,EAC9B;AAGA,QAAM,eAAe,SAAS;AAG9B,WAAS,YAAY,kBAAkB,CAAC;AAExC,SAAO,QAAQ,IAAI;AAAA,IAChB,2BACG,yBAAS,2BACT;AAAA,EACN,CAAC;AACH;AAKA,eAAsB,eAAe,MAAuB,SAAc;AACxE,QAAM,gBAAoB,yBAAW;AAErC;AAAA,IACE;AAAA,IACA;AAAA,IAAW,KAAK;AAAA,IAAQ;AAAA,EAC1B;AAEA,MAAI;AAEJ,MAAI;AACF,gCAA4B,MAAM,eAAe,KAAK,QAAQ,gBAAgB,CAAC,WAAW,OAAO,CAAC;AAAA,EAEpG,SAAS,GAAP;AACA,uCAAiB,CAAC;AAClB,gCAA4B;AAAA,EAC9B;AAEA,MAAI,CAAC,2BAA2B;AAC9B,UAAM,IAAI,iDAAqB,GAAG,KAAK,yBAAyB;AAAA,EAClE;AAEA,QAAM,WAA4B,EAAE,MAAM,UAAU;AAEpD,MAAI,0BAAW;AACb,aAAS,UAAU;AAAA,EACrB;AAEA,SAAO;AACT;AAEA,eAAe,kBAAkB,UAAkB;AAKjD,QAAM,cAAc,MAAM,OAAO,KAAK,EAAE,MAAM,SAAS,GAAG,EAAE,KAAK,EAAE,CAAC;AAGpE,QAAM,SAAS,IAAI,yBAAyB,QAAQ,CAAC;AAErD,QAAM,QAAQ,IAAI,YAAY,IAAI,OAAO,SAAS;AAChD,QAAI;AAEF,YAAM,eAAe,KAAK,QAAQ,QAAQ;AAAA,IAE5C,SAAS,GAAP;AACA,yCAAiB,2BAA2B,sBAAsB,KAAK,QAAQ;AAC/E,WAAK,OAAO;AAAA,IACd;AAAA,EACF,CAAC,CAAC;AACJ;AAEA,eAAe,qBAAqB,MAAY,OAAgB,OAAyB;AACvF,QAAM,KAAK,UAAU;AAErB,MAAI,MAAM;AACR,cAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA,eAAe,KAAK,MAAM;AAAA,MAC1B,CAAC,QAAQ,SAAS;AAChB,eAAQ,CAAC,QAAQ,OAAQ,KAAK,YAAa,aACvC,KAAK,UACL,KAAK,QAAQ,MAAM,MAAM,IAAI;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAe,mBAAmB,YAAoB,UAA8C;AAClG,SAAO,IAAI,QAAQ,OAAO,SAAS,WAAW;AAC5C,UAAM,iBAAiB,yBAAyB,UAAU;AAC1D,UAAM,cAAc,MAAM,SAAS,KAAK,cAAc,IAAI;AAQ1D,UAAM,qBAAqB,KAAK,IAAI,cAAc,KAAK,GAAG;AAE1D,QAAI,cAAc,GAAG;AACnB;AAAA,QACE;AAAA,QACA;AAAA,QAAa;AAAA,QAAY;AAAA,MAC3B;AAAA,IACF;AAEA,eAAW,YAAY;AACrB,UAAI;AACF,cAAM,SAAS,MAAM,SAAS;AAC9B,gBAAQ,MAAM;AAAA,MAEhB,SAAS,GAAP;AACA,eAAO,CAAC;AAAA,MAEV,UAAE;AACA,cAAM,SAAS,KAAK,cAAc;AAAA,MACpC;AAAA,IACF,GAAG,kBAAkB;AAAA,EACvB,CAAC;AACH;AAEA,SAAS,iBAAiB,MAAY,QAAgB;AAEpD,QAAM,MAAM;AACZ,QAAM,QAAQ;AAEd,WAAS,KAAK,UAAU,KAAK,QAAQ,MAAM,MAAM;AACnD;AAEA,SAAS,kBAAkB,MAAY,QAAgB,aAAsB;AAE3E,QAAM,MAAM;AACZ,QAAM,QAAQ;AAEd,WAAS,KAAK,UAAU,KAAK,SAAS,MAAM,QAAQ,WAAW;AACjE;AAEA,SAAS,SAAS,MAAkB;AAElC,WAAS,KAAK,UAAU,KAAK,QAAQ,IAAI;AAC3C;AAEA,eAAe,WAAW,MAAY;AACpC,MAAI,MAAM,qBAAqB,IAAI,GAAG;AAEpC,aAAS,KAAK,UAAU,KAAK,UAAU,IAAI;AAAA,EAC7C;AACF;AAEA,eAAe,YAAY,UAAkB,MAAY;AACvD,qCAAiB,yCAA6C,UAAU,KAAK,QAAQ,SAAS;AAG9F,MAAI,CAAC,0BAA0B;AAC7B,UAAM,MAAM;AACZ,UAAM,QAAQ;AAGd,QAAI,0BAAW;AACb,YAAM,SAAS,SAAK,sCAAsB,GAAG,KAAK,MAAM;AAAA,IAC1D;AAAA,EACF;AAGA,WAAS,UAAU,KAAK,WAAW,IAAI;AAGvC,WAAS,IAAI,yBAAyB,QAAQ,CAAC;AAG/C,WAAS,YAAY,eAAe,KAAK,MAAM,CAAC;AAGhD,SAAO,MAAM,KAAK;AACpB;AAKA,SAAS,eAAe,QAAgB;AACtC,SAAO,IAAI;AACb;AAEA,SAAS,yBAAyB,MAAc;AAC9C,SAAO,KAAK;AACd;AAEA,SAAS,kBAAkB,KAAa,WAAW;AACjD,SAAO,KAAK;AACd;",
6
6
  "names": ["controller"]
7
7
  }