@colyseus/core 0.17.43 → 0.18.0

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 (95) hide show
  1. package/build/MatchMaker.cjs +19 -6
  2. package/build/MatchMaker.cjs.map +2 -2
  3. package/build/MatchMaker.d.ts +10 -0
  4. package/build/MatchMaker.mjs +18 -6
  5. package/build/MatchMaker.mjs.map +2 -2
  6. package/build/Protocol.cjs +102 -37
  7. package/build/Protocol.cjs.map +2 -2
  8. package/build/Protocol.d.ts +33 -2
  9. package/build/Protocol.mjs +102 -37
  10. package/build/Protocol.mjs.map +2 -2
  11. package/build/Room.cjs +296 -19
  12. package/build/Room.cjs.map +3 -3
  13. package/build/Room.d.ts +186 -3
  14. package/build/Room.mjs +303 -21
  15. package/build/Room.mjs.map +3 -3
  16. package/build/RoomPlugin.cjs +252 -0
  17. package/build/RoomPlugin.cjs.map +7 -0
  18. package/build/RoomPlugin.d.ts +271 -0
  19. package/build/RoomPlugin.mjs +220 -0
  20. package/build/RoomPlugin.mjs.map +7 -0
  21. package/build/Server.cjs +49 -15
  22. package/build/Server.cjs.map +2 -2
  23. package/build/Server.d.ts +25 -0
  24. package/build/Server.mjs +50 -16
  25. package/build/Server.mjs.map +2 -2
  26. package/build/Transport.cjs +38 -2
  27. package/build/Transport.cjs.map +2 -2
  28. package/build/Transport.d.ts +40 -4
  29. package/build/Transport.mjs +38 -2
  30. package/build/Transport.mjs.map +2 -2
  31. package/build/index.cjs +11 -2
  32. package/build/index.cjs.map +2 -2
  33. package/build/index.d.ts +2 -1
  34. package/build/index.mjs +12 -2
  35. package/build/index.mjs.map +2 -2
  36. package/build/input/InputBuffer.cjs +113 -0
  37. package/build/input/InputBuffer.cjs.map +7 -0
  38. package/build/input/InputBuffer.d.ts +136 -0
  39. package/build/input/InputBuffer.mjs +86 -0
  40. package/build/input/InputBuffer.mjs.map +7 -0
  41. package/build/internal.cjs +61 -0
  42. package/build/internal.cjs.map +7 -0
  43. package/build/internal.d.ts +9 -0
  44. package/build/internal.mjs +29 -0
  45. package/build/internal.mjs.map +7 -0
  46. package/build/matchmaker/LocalDriver/LocalDriver.cjs +13 -0
  47. package/build/matchmaker/LocalDriver/LocalDriver.cjs.map +2 -2
  48. package/build/matchmaker/LocalDriver/LocalDriver.d.ts +1 -0
  49. package/build/matchmaker/LocalDriver/LocalDriver.mjs +13 -0
  50. package/build/matchmaker/LocalDriver/LocalDriver.mjs.map +2 -2
  51. package/build/matchmaker/driver.cjs.map +1 -1
  52. package/build/matchmaker/driver.d.ts +12 -0
  53. package/build/matchmaker/driver.mjs.map +1 -1
  54. package/build/presence/LocalPresence.d.ts +1 -1
  55. package/build/rooms/LobbyRoom.cjs +8 -10
  56. package/build/rooms/LobbyRoom.cjs.map +2 -2
  57. package/build/rooms/LobbyRoom.d.ts +4 -3
  58. package/build/rooms/LobbyRoom.mjs +8 -10
  59. package/build/rooms/LobbyRoom.mjs.map +2 -2
  60. package/build/rooms/RelayRoom.cjs +12 -16
  61. package/build/rooms/RelayRoom.cjs.map +2 -2
  62. package/build/rooms/RelayRoom.d.ts +32 -11
  63. package/build/rooms/RelayRoom.mjs +10 -16
  64. package/build/rooms/RelayRoom.mjs.map +2 -2
  65. package/build/router/index.cjs +65 -4
  66. package/build/router/index.cjs.map +2 -2
  67. package/build/router/index.d.ts +30 -6
  68. package/build/router/index.mjs +66 -6
  69. package/build/router/index.mjs.map +3 -3
  70. package/build/utils/Env.cjs +4 -8
  71. package/build/utils/Env.cjs.map +3 -3
  72. package/build/utils/Env.mjs +4 -8
  73. package/build/utils/Env.mjs.map +2 -2
  74. package/build/utils/UserSessionIndex.cjs +162 -0
  75. package/build/utils/UserSessionIndex.cjs.map +7 -0
  76. package/build/utils/UserSessionIndex.d.ts +166 -0
  77. package/build/utils/UserSessionIndex.mjs +130 -0
  78. package/build/utils/UserSessionIndex.mjs.map +7 -0
  79. package/package.json +20 -15
  80. package/src/MatchMaker.ts +40 -6
  81. package/src/Protocol.ts +130 -59
  82. package/src/Room.ts +475 -22
  83. package/src/RoomPlugin.ts +563 -0
  84. package/src/Server.ts +81 -22
  85. package/src/Transport.ts +76 -8
  86. package/src/index.ts +10 -1
  87. package/src/input/InputBuffer.ts +192 -0
  88. package/src/internal.ts +46 -0
  89. package/src/matchmaker/LocalDriver/LocalDriver.ts +10 -0
  90. package/src/matchmaker/driver.ts +13 -0
  91. package/src/rooms/LobbyRoom.ts +12 -8
  92. package/src/rooms/RelayRoom.ts +9 -15
  93. package/src/router/index.ts +112 -11
  94. package/src/utils/Env.ts +4 -12
  95. package/src/utils/UserSessionIndex.ts +311 -0
package/build/index.mjs CHANGED
@@ -7,6 +7,11 @@ import {
7
7
  } from "@colyseus/shared-types";
8
8
  import { Server, defineRoom, defineServer, registerRoomDefinitions, unregisterRoomDefinitions } from "./Server.mjs";
9
9
  import { Room, room, RoomInternalState, validate } from "./Room.mjs";
10
+ import {
11
+ RoomPlugin,
12
+ definePlugins,
13
+ attachToTestRoom
14
+ } from "./RoomPlugin.mjs";
10
15
  import { getMessageBytes } from "./Protocol.mjs";
11
16
  import { RegisteredHandler } from "./matchmaker/RegisteredHandler.mjs";
12
17
  import { ServerError } from "./errors/ServerError.mjs";
@@ -51,8 +56,9 @@ import {
51
56
  createInternalContext,
52
57
  createMiddleware,
53
58
  createRouter,
59
+ basicAuth,
54
60
  toNodeHandler,
55
- __globalEndpoints
61
+ dualModeEndpoints
56
62
  } from "./router/index.mjs";
57
63
  import { logger } from "./Logger.mjs";
58
64
  export {
@@ -77,13 +83,15 @@ export {
77
83
  RelayRoom,
78
84
  Room,
79
85
  RoomInternalState,
86
+ RoomPlugin,
80
87
  SchemaSerializer,
81
88
  Server,
82
89
  ServerError,
83
90
  SimulationIntervalException,
84
91
  TimedEventException,
85
92
  Transport,
86
- __globalEndpoints,
93
+ attachToTestRoom,
94
+ basicAuth,
87
95
  connectClientToRoom,
88
96
  createEndpoint,
89
97
  createInternalContext,
@@ -98,8 +106,10 @@ export {
98
106
  debugMessage,
99
107
  debugPatch,
100
108
  debugPresence,
109
+ definePlugins,
101
110
  defineRoom,
102
111
  defineServer,
112
+ dualModeEndpoints,
103
113
  dynamicImport,
104
114
  generateId,
105
115
  getBearerToken,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["import { ClockTimer as Clock, Delayed } from '@colyseus/timer';\n\n// Shared types - re-export from @colyseus/shared-types for convenience\nexport {\n Protocol,\n ErrorCode,\n CloseCode,\n type InferState,\n type ExtractRoomMessages,\n type ExtractRoomClientMessages,\n} from '@colyseus/shared-types';\n\n// Core classes\nexport { Server, defineRoom, defineServer, registerRoomDefinitions, unregisterRoomDefinitions, type RoomDefinitions, type ServerOptions, type SDKTypes } from './Server.ts';\nexport { Room, room, RoomInternalState, validate, type RoomOptions, type MessageHandlerWithFormat, type Messages, type ExtractRoomState, type ExtractRoomMetadata, type ExtractRoomClient } from './Room.ts';\nexport { getMessageBytes } from './Protocol.ts';\nexport { RegisteredHandler } from './matchmaker/RegisteredHandler.ts';\nexport { ServerError } from './errors/ServerError.ts';\n\nexport {\n type RoomException,\n type RoomMethodName,\n OnCreateException,\n OnAuthException,\n OnJoinException,\n OnLeaveException,\n OnDisposeException,\n OnMessageException,\n SimulationIntervalException,\n TimedEventException,\n} from './errors/RoomExceptions.ts';\n\n// MatchMaker\nimport * as matchMaker from './MatchMaker.ts';\nexport { matchMaker };\nexport { updateLobby, subscribeLobby } from './matchmaker/Lobby.ts';\nexport { createNodeMatchmakingMiddleware } from './router/node.ts';\n\n// Driver\nexport * from './matchmaker/LocalDriver/LocalDriver.ts';\nexport { initializeRoomCache } from './matchmaker/driver.ts';\n\n// Transport\nexport { type Client, type ClientPrivate, type AuthContext, ClientState, ClientArray, Transport, type ISendOptions, connectClientToRoom } from './Transport.ts';\n\n// Presence\nexport { type Presence } from './presence/Presence.ts';\nexport { LocalPresence } from './presence/LocalPresence.ts';\n\n// Serializers\nexport { type Serializer } from './serializer/Serializer.ts';\nexport { SchemaSerializer } from './serializer/SchemaSerializer.ts';\n\n// Utilities\nexport { Clock, Delayed };\nexport { generateId, Deferred, spliceOne, getBearerToken, dynamicImport } from './utils/Utils.ts';\nexport { isDevMode, setDevMode } from './utils/DevMode.ts';\n\n// IPC\nexport { subscribeIPC, requestFromIPC } from './IPC.ts';\n\n// Debug\nexport {\n debugMatchMaking,\n debugMessage,\n debugPatch,\n debugError,\n debugConnection,\n debugDriver,\n debugPresence,\n debugAndPrintError,\n} from './Debug.ts';\n\n// Default rooms\nexport { LobbyRoom } from './rooms/LobbyRoom.ts';\nexport { RelayRoom } from './rooms/RelayRoom.ts';\nexport { QueueRoom, type QueueOptions, type QueueMatchGroup, type QueueMatchTeam, type QueueClientData } from './rooms/QueueRoom.ts';\n\n// Router / Endpoints\nexport {\n createEndpoint,\n createInternalContext,\n createMiddleware,\n createRouter,\n toNodeHandler,\n __globalEndpoints,\n type Router,\n type RouterConfig,\n type Endpoint,\n type EndpointHandler,\n type EndpointOptions,\n type EndpointContext,\n type StrictEndpoint,\n} from './router/index.ts';\n\n// Abstract logging support\nexport { logger } from './Logger.ts';\n"],
5
- "mappings": ";AAAA,SAAS,cAAc,OAAO,eAAe;AAG7C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP,SAAS,QAAQ,YAAY,cAAc,yBAAyB,iCAA0F;AAC9J,SAAS,MAAM,MAAM,mBAAmB,gBAAyJ;AACjM,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAClC,SAAS,mBAAmB;AAE5B;AAAA,EAGE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,YAAY,gBAAgB;AAE5B,SAAS,aAAa,sBAAsB;AAC5C,SAAS,uCAAuC;AAGhD,cAAc;AACd,SAAS,2BAA2B;AAGpC,SAA4D,aAAa,aAAa,WAA8B,2BAA2B;AAG/I,eAA8B;AAC9B,SAAS,qBAAqB;AAG9B,eAAgC;AAChC,SAAS,wBAAwB;AAIjC,SAAS,YAAY,UAAU,WAAW,gBAAgB,qBAAqB;AAC/E,SAAS,WAAW,kBAAkB;AAGtC,SAAS,cAAc,sBAAsB;AAG7C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,iBAAiB;AAC1B,SAAS,iBAAiB;AAC1B,SAAS,iBAAqG;AAG9G;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAQK;AAGP,SAAS,cAAc;",
4
+ "sourcesContent": ["import { ClockTimer as Clock, Delayed } from '@colyseus/timer';\n\n// Shared types - re-export from @colyseus/shared-types for convenience\nexport {\n Protocol,\n ErrorCode,\n CloseCode,\n type InferState,\n type ExtractRoomMessages,\n type ExtractRoomClientMessages,\n} from '@colyseus/shared-types';\n\n// Core classes\nexport { Server, defineRoom, defineServer, registerRoomDefinitions, unregisterRoomDefinitions, type RoomDefinitions, type ServerOptions, type SDKTypes } from './Server.ts';\nexport { Room, room, RoomInternalState, validate, type RoomOptions, type MessageHandlerWithFormat, type Messages, type ExtractRoomState, type ExtractRoomMetadata, type ExtractRoomClient } from './Room.ts';\nexport {\n RoomPlugin, definePlugins, attachToTestRoom,\n type RoomPluginOrder, type PluginDependencies, type RoomPluginClass,\n} from './RoomPlugin.ts';\nexport { getMessageBytes } from './Protocol.ts';\nexport { RegisteredHandler } from './matchmaker/RegisteredHandler.ts';\nexport { ServerError } from './errors/ServerError.ts';\n\nexport {\n type RoomException,\n type RoomMethodName,\n OnCreateException,\n OnAuthException,\n OnJoinException,\n OnLeaveException,\n OnDisposeException,\n OnMessageException,\n SimulationIntervalException,\n TimedEventException,\n} from './errors/RoomExceptions.ts';\n\n// MatchMaker\nimport * as matchMaker from './MatchMaker.ts';\nexport { matchMaker };\nexport { updateLobby, subscribeLobby } from './matchmaker/Lobby.ts';\nexport { createNodeMatchmakingMiddleware } from './router/node.ts';\n\n// Driver\nexport * from './matchmaker/LocalDriver/LocalDriver.ts';\nexport { initializeRoomCache } from './matchmaker/driver.ts';\n\n// Transport\nexport { type Client, type ClientPrivate, type AuthContext, ClientState, ClientArray, Transport, type ISendOptions, connectClientToRoom } from './Transport.ts';\n\n// Presence\nexport { type Presence } from './presence/Presence.ts';\nexport { LocalPresence } from './presence/LocalPresence.ts';\n\n// Serializers\nexport { type Serializer } from './serializer/Serializer.ts';\nexport { SchemaSerializer } from './serializer/SchemaSerializer.ts';\n\n// Utilities\nexport { Clock, Delayed };\nexport { generateId, Deferred, spliceOne, getBearerToken, dynamicImport } from './utils/Utils.ts';\nexport { isDevMode, setDevMode } from './utils/DevMode.ts';\n\n// IPC\nexport { subscribeIPC, requestFromIPC } from './IPC.ts';\n\n// Debug\nexport {\n debugMatchMaking,\n debugMessage,\n debugPatch,\n debugError,\n debugConnection,\n debugDriver,\n debugPresence,\n debugAndPrintError,\n} from './Debug.ts';\n\n// Default rooms\nexport { LobbyRoom } from './rooms/LobbyRoom.ts';\nexport { RelayRoom } from './rooms/RelayRoom.ts';\nexport { QueueRoom, type QueueOptions, type QueueMatchGroup, type QueueMatchTeam, type QueueClientData } from './rooms/QueueRoom.ts';\n\n// Router / Endpoints\nexport {\n createEndpoint,\n createInternalContext,\n createMiddleware,\n createRouter,\n basicAuth,\n type BasicAuthOptions,\n toNodeHandler,\n dualModeEndpoints,\n type Router,\n type RouterConfig,\n type Endpoint,\n type EndpointHandler,\n type EndpointOptions,\n type EndpointContext,\n type StrictEndpoint,\n type ExpressMiddleware,\n type NodeHandler,\n type DualModeHelpers,\n} from './router/index.ts';\n\n// Abstract logging support\nexport { logger } from './Logger.ts';\n"],
5
+ "mappings": ";AAAA,SAAS,cAAc,OAAO,eAAe;AAG7C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP,SAAS,QAAQ,YAAY,cAAc,yBAAyB,iCAA0F;AAC9J,SAAS,MAAM,MAAM,mBAAmB,gBAAyJ;AACjM;AAAA,EACE;AAAA,EAAY;AAAA,EAAe;AAAA,OAEtB;AACP,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAClC,SAAS,mBAAmB;AAE5B;AAAA,EAGE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,YAAY,gBAAgB;AAE5B,SAAS,aAAa,sBAAsB;AAC5C,SAAS,uCAAuC;AAGhD,cAAc;AACd,SAAS,2BAA2B;AAGpC,SAA4D,aAAa,aAAa,WAA8B,2BAA2B;AAG/I,eAA8B;AAC9B,SAAS,qBAAqB;AAG9B,eAAgC;AAChC,SAAS,wBAAwB;AAIjC,SAAS,YAAY,UAAU,WAAW,gBAAgB,qBAAqB;AAC/E,SAAS,WAAW,kBAAkB;AAGtC,SAAS,cAAc,sBAAsB;AAG7C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,iBAAiB;AAC1B,SAAS,iBAAiB;AAC1B,SAAS,iBAAqG;AAG9G;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,OAWK;AAGP,SAAS,cAAc;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // packages/core/src/input/InputBuffer.ts
21
+ var InputBuffer_exports = {};
22
+ __export(InputBuffer_exports, {
23
+ InputAccessorImpl: () => InputAccessorImpl,
24
+ InputBufferImpl: () => InputBufferImpl,
25
+ NO_OP_INPUT_ACCESSOR: () => NO_OP_INPUT_ACCESSOR
26
+ });
27
+ module.exports = __toCommonJS(InputBuffer_exports);
28
+ var InputBufferImpl = class {
29
+ constructor(maxSize, seqField) {
30
+ this._items = [];
31
+ this._lastSeq = -Infinity;
32
+ this._maxSize = maxSize;
33
+ this._seqField = seqField;
34
+ }
35
+ push(snapshot) {
36
+ this._items.push(snapshot);
37
+ if (this._items.length > this._maxSize) {
38
+ this._items.shift();
39
+ }
40
+ }
41
+ /** Returns true if `value` hasn't been seen, and updates the last-seen marker. */
42
+ accept(value) {
43
+ if (value <= this._lastSeq) {
44
+ return false;
45
+ }
46
+ this._lastSeq = value;
47
+ return true;
48
+ }
49
+ drain() {
50
+ const out = this._items;
51
+ this._items = [];
52
+ return out;
53
+ }
54
+ peek() {
55
+ return this._items.slice();
56
+ }
57
+ at(value) {
58
+ if (this._seqField === void 0) {
59
+ return void 0;
60
+ }
61
+ for (let i = 0; i < this._items.length; i++) {
62
+ if (this._items[i][this._seqField] === value) {
63
+ return this._items[i];
64
+ }
65
+ }
66
+ return void 0;
67
+ }
68
+ get size() {
69
+ return this._items.length;
70
+ }
71
+ clear() {
72
+ this._items.length = 0;
73
+ this._lastSeq = -Infinity;
74
+ }
75
+ };
76
+ var InputAccessorImpl = class {
77
+ constructor(client) {
78
+ this._client = client;
79
+ }
80
+ get latest() {
81
+ return this._client._input;
82
+ }
83
+ at(value) {
84
+ return this._client._inputBuffer?.at(value);
85
+ }
86
+ drain() {
87
+ return this._client._inputBuffer?.drain() ?? [];
88
+ }
89
+ peek() {
90
+ return this._client._inputBuffer?.peek() ?? [];
91
+ }
92
+ get size() {
93
+ return this._client._inputBuffer?.size ?? 0;
94
+ }
95
+ clear() {
96
+ this._client._inputBuffer?.clear();
97
+ }
98
+ };
99
+ var NO_OP_INPUT_ACCESSOR = Object.freeze({
100
+ latest: void 0,
101
+ at: () => void 0,
102
+ drain: () => [],
103
+ peek: () => [],
104
+ size: 0,
105
+ clear: () => {
106
+ }
107
+ });
108
+ // Annotate the CommonJS export names for ESM import in node:
109
+ 0 && (module.exports = {
110
+ InputAccessorImpl,
111
+ InputBufferImpl,
112
+ NO_OP_INPUT_ACCESSOR
113
+ });
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/input/InputBuffer.ts"],
4
+ "sourcesContent": ["import type { ClientPrivate } from '../Transport.ts';\n\n/**\n * Names of fields on `I` whose values are `number` \u2014 used by\n * `Room.defineInput()` to constrain `seqField` to actually-numeric fields\n * on the input schema. Filters out booleans, strings, methods, etc.\n */\nexport type NumericFieldsOf<I> = {\n [K in keyof I]: I[K] extends number ? (K extends string ? K : never) : never;\n}[keyof I];\n\n/**\n * Internal: input configuration captured by `Room.defineInput()`. The schema\n * constructor is stored here so the runtime doesn't need to know it through\n * the public `room.input` (which is now a callable accessor).\n *\n * @internal\n */\nexport interface InputOptions {\n /**\n * Schema constructor used to allocate per-client input instances on join.\n * Captured by `defineInput()` from its `type` argument.\n *\n * Typed loosely (`new () => any`) to sidestep type-identity issues across\n * duplicate `@colyseus/schema` installs; the runtime calls\n * `instance.clone()` and friends, which match by shape.\n */\n ctor: new () => any;\n\n /**\n * Name of a monotonically-increasing numeric field on the input schema used\n * to order and dedupe incoming frames. When set, the framework:\n * - Drops redundant frames (`input[seqField]` \u2264 the last-seen value are\n * discarded before they enter the buffer). Matches the unreliable-mode\n * ring-redundancy pattern out of the box.\n * - Powers `room.input(sessionId).at(value)` lookups.\n *\n * Despite the name, \"seq\" here is broader than an integer counter \u2014 any\n * monotonic numeric field works:\n * - **Sequence counter** (`\"seq\"`, `\"tick\"`, `\"frame\"`) \u2014 typical for\n * lockstep / rollback netcode (Photon Quantum, GGPO).\n * - **Timestamp** (`\"timestamp\"`, milliseconds or seconds) \u2014 useful for\n * variable-rate clients, lag compensation, hit registration (Unreal CMC\n * uses float-seconds timestamps via `FSavedMove_Character.TimeStamp`).\n *\n * Whichever you use, the field must increase monotonically across frames\n * for dedupe to work.\n */\n seqField?: string;\n\n /**\n * > 0 enables per-client buffering of cloned snapshots \u2014 required for\n * `room.input(sessionId).drain() / .peek() / .at()` to return populated\n * data. Oldest drops on overflow. Set to `0` to disable (`.latest` still\n * works).\n */\n bufferMaxSize: number;\n}\n\n/**\n * Per-client input accessor returned by `room.input(sessionId)`. Combines the\n * latest decoded instance with the (optional) snapshot ring buffer.\n *\n * - {@link latest} \u2014 the bound Schema instance, mutated in place by the\n * decoder. Cheapest read; use when only the most recent state matters.\n * - {@link drain} / {@link peek} / {@link at} \u2014 populated when\n * `defineInput()` was called with `bufferMaxSize > 0` (default 32).\n * Use for rollback netcode / lockstep where every frame matters.\n *\n * Returned for unknown sessionIds and rooms without `defineInput()` is a\n * frozen no-op accessor (latest=undefined, drain/peek=[], at=undefined,\n * size=0, clear=no-op).\n */\nexport interface InputAccessor<I = any> {\n /** Latest decoded input. `undefined` when unknown sessionId or no input declared. */\n readonly latest: I | undefined;\n\n /**\n * Find the buffered snapshot whose `[seqField]` equals `value`. The field\n * name is the Room's `defineInput()` `seqField`. Linear scan \u2014 cheap for\n * typical buffer sizes; not intended for very large rings. Returns\n * `undefined` when no match is buffered (or `seqField` isn't configured).\n *\n * Useful for tick-aligned retrieval (lockstep, rollback).\n */\n at(value: number): I | undefined;\n\n /** Take everything buffered (oldest \u2192 newest) and clear. Snapshots are safe to retain. */\n drain(): I[];\n\n /** Read everything buffered without consuming. */\n peek(): I[];\n\n /** Number of snapshots currently buffered. */\n readonly size: number;\n\n /** Drop all buffered snapshots (also resets the dedupe tracker). */\n clear(): void;\n}\n\n/**\n * Callable returned by `Room.defineInput()`. Assign it to `this.input` and\n * call `room.input(sessionId)` per tick to read each client's latest input\n * and/or buffered snapshots.\n */\nexport type InputAPI<I = any> = (sessionId: string) => InputAccessor<I>;\n\n/** @internal */\nexport class InputBufferImpl<I = any> {\n private _items: I[] = [];\n private _lastSeq: number = -Infinity;\n private readonly _maxSize: number;\n private readonly _seqField: string | undefined;\n\n constructor(maxSize: number, seqField: string | undefined) {\n this._maxSize = maxSize;\n this._seqField = seqField;\n }\n\n push(snapshot: I): void {\n this._items.push(snapshot);\n if (this._items.length > this._maxSize) { this._items.shift(); }\n }\n\n /** Returns true if `value` hasn't been seen, and updates the last-seen marker. */\n accept(value: number): boolean {\n if (value <= this._lastSeq) { return false; }\n this._lastSeq = value;\n return true;\n }\n\n drain(): I[] {\n const out = this._items;\n this._items = [];\n return out;\n }\n\n peek(): I[] {\n return this._items.slice();\n }\n\n at(value: number): I | undefined {\n if (this._seqField === undefined) { return undefined; }\n for (let i = 0; i < this._items.length; i++) {\n if ((this._items[i] as any)[this._seqField] === value) { return this._items[i]; }\n }\n return undefined;\n }\n\n get size(): number {\n return this._items.length;\n }\n\n clear(): void {\n this._items.length = 0;\n this._lastSeq = -Infinity;\n }\n}\n\n/**\n * Default per-client accessor. Reads `_input` and `_inputBuffer` off the\n * client at access time \u2014 both are nullable until the room declares input\n * via `defineInput()`. Cached as `client._inputAccessor` at join, so\n * `room.input(sessionId)` is a Map lookup + property read.\n *\n * @internal\n */\nexport class InputAccessorImpl<I = any> implements InputAccessor<I> {\n private _client: ClientPrivate;\n constructor(client: ClientPrivate) { this._client = client; }\n get latest(): I | undefined { return this._client._input as I | undefined; }\n at(value: number): I | undefined { return this._client._inputBuffer?.at(value) as I | undefined; }\n drain(): I[] { return (this._client._inputBuffer?.drain() ?? []) as I[]; }\n peek(): I[] { return (this._client._inputBuffer?.peek() ?? []) as I[]; }\n get size(): number { return this._client._inputBuffer?.size ?? 0; }\n clear(): void { this._client._inputBuffer?.clear(); }\n}\n\n/**\n * Returned by `room.input(sessionId)` for unknown sessions and for rooms\n * that didn't call `defineInput()`.\n *\n * @internal\n */\nexport const NO_OP_INPUT_ACCESSOR: InputAccessor<any> = Object.freeze({\n latest: undefined,\n at: () => undefined,\n drain: () => [],\n peek: () => [],\n size: 0,\n clear: () => {},\n});\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4GO,IAAM,kBAAN,MAA+B;AAAA,EAMpC,YAAY,SAAiB,UAA8B;AAL3D,SAAQ,SAAc,CAAC;AACvB,SAAQ,WAAmB;AAKzB,SAAK,WAAW;AAChB,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,KAAK,UAAmB;AACtB,SAAK,OAAO,KAAK,QAAQ;AACzB,QAAI,KAAK,OAAO,SAAS,KAAK,UAAU;AAAE,WAAK,OAAO,MAAM;AAAA,IAAG;AAAA,EACjE;AAAA;AAAA,EAGA,OAAO,OAAwB;AAC7B,QAAI,SAAS,KAAK,UAAU;AAAE,aAAO;AAAA,IAAO;AAC5C,SAAK,WAAW;AAChB,WAAO;AAAA,EACT;AAAA,EAEA,QAAa;AACX,UAAM,MAAM,KAAK;AACjB,SAAK,SAAS,CAAC;AACf,WAAO;AAAA,EACT;AAAA,EAEA,OAAY;AACV,WAAO,KAAK,OAAO,MAAM;AAAA,EAC3B;AAAA,EAEA,GAAG,OAA8B;AAC/B,QAAI,KAAK,cAAc,QAAW;AAAE,aAAO;AAAA,IAAW;AACtD,aAAS,IAAI,GAAG,IAAI,KAAK,OAAO,QAAQ,KAAK;AAC3C,UAAK,KAAK,OAAO,CAAC,EAAU,KAAK,SAAS,MAAM,OAAO;AAAE,eAAO,KAAK,OAAO,CAAC;AAAA,MAAG;AAAA,IAClF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,OAAe;AACjB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAEA,QAAc;AACZ,SAAK,OAAO,SAAS;AACrB,SAAK,WAAW;AAAA,EAClB;AACF;AAUO,IAAM,oBAAN,MAA6D;AAAA,EAElE,YAAY,QAAuB;AAAE,SAAK,UAAU;AAAA,EAAQ;AAAA,EAC5D,IAAI,SAAwB;AAAE,WAAO,KAAK,QAAQ;AAAA,EAAyB;AAAA,EAC3E,GAAG,OAA8B;AAAE,WAAO,KAAK,QAAQ,cAAc,GAAG,KAAK;AAAA,EAAoB;AAAA,EACjG,QAAa;AAAE,WAAQ,KAAK,QAAQ,cAAc,MAAM,KAAK,CAAC;AAAA,EAAW;AAAA,EACzE,OAAY;AAAE,WAAQ,KAAK,QAAQ,cAAc,KAAK,KAAK,CAAC;AAAA,EAAW;AAAA,EACvE,IAAI,OAAe;AAAE,WAAO,KAAK,QAAQ,cAAc,QAAQ;AAAA,EAAG;AAAA,EAClE,QAAc;AAAE,SAAK,QAAQ,cAAc,MAAM;AAAA,EAAG;AACtD;AAQO,IAAM,uBAA2C,OAAO,OAAO;AAAA,EACpE,QAAQ;AAAA,EACR,IAAI,MAAM;AAAA,EACV,OAAO,MAAM,CAAC;AAAA,EACd,MAAM,MAAM,CAAC;AAAA,EACb,MAAM;AAAA,EACN,OAAO,MAAM;AAAA,EAAC;AAChB,CAAC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,136 @@
1
+ import type { ClientPrivate } from '../Transport.ts';
2
+ /**
3
+ * Names of fields on `I` whose values are `number` — used by
4
+ * `Room.defineInput()` to constrain `seqField` to actually-numeric fields
5
+ * on the input schema. Filters out booleans, strings, methods, etc.
6
+ */
7
+ export type NumericFieldsOf<I> = {
8
+ [K in keyof I]: I[K] extends number ? (K extends string ? K : never) : never;
9
+ }[keyof I];
10
+ /**
11
+ * Internal: input configuration captured by `Room.defineInput()`. The schema
12
+ * constructor is stored here so the runtime doesn't need to know it through
13
+ * the public `room.input` (which is now a callable accessor).
14
+ *
15
+ * @internal
16
+ */
17
+ export interface InputOptions {
18
+ /**
19
+ * Schema constructor used to allocate per-client input instances on join.
20
+ * Captured by `defineInput()` from its `type` argument.
21
+ *
22
+ * Typed loosely (`new () => any`) to sidestep type-identity issues across
23
+ * duplicate `@colyseus/schema` installs; the runtime calls
24
+ * `instance.clone()` and friends, which match by shape.
25
+ */
26
+ ctor: new () => any;
27
+ /**
28
+ * Name of a monotonically-increasing numeric field on the input schema used
29
+ * to order and dedupe incoming frames. When set, the framework:
30
+ * - Drops redundant frames (`input[seqField]` ≤ the last-seen value are
31
+ * discarded before they enter the buffer). Matches the unreliable-mode
32
+ * ring-redundancy pattern out of the box.
33
+ * - Powers `room.input(sessionId).at(value)` lookups.
34
+ *
35
+ * Despite the name, "seq" here is broader than an integer counter — any
36
+ * monotonic numeric field works:
37
+ * - **Sequence counter** (`"seq"`, `"tick"`, `"frame"`) — typical for
38
+ * lockstep / rollback netcode (Photon Quantum, GGPO).
39
+ * - **Timestamp** (`"timestamp"`, milliseconds or seconds) — useful for
40
+ * variable-rate clients, lag compensation, hit registration (Unreal CMC
41
+ * uses float-seconds timestamps via `FSavedMove_Character.TimeStamp`).
42
+ *
43
+ * Whichever you use, the field must increase monotonically across frames
44
+ * for dedupe to work.
45
+ */
46
+ seqField?: string;
47
+ /**
48
+ * > 0 enables per-client buffering of cloned snapshots — required for
49
+ * `room.input(sessionId).drain() / .peek() / .at()` to return populated
50
+ * data. Oldest drops on overflow. Set to `0` to disable (`.latest` still
51
+ * works).
52
+ */
53
+ bufferMaxSize: number;
54
+ }
55
+ /**
56
+ * Per-client input accessor returned by `room.input(sessionId)`. Combines the
57
+ * latest decoded instance with the (optional) snapshot ring buffer.
58
+ *
59
+ * - {@link latest} — the bound Schema instance, mutated in place by the
60
+ * decoder. Cheapest read; use when only the most recent state matters.
61
+ * - {@link drain} / {@link peek} / {@link at} — populated when
62
+ * `defineInput()` was called with `bufferMaxSize > 0` (default 32).
63
+ * Use for rollback netcode / lockstep where every frame matters.
64
+ *
65
+ * Returned for unknown sessionIds and rooms without `defineInput()` is a
66
+ * frozen no-op accessor (latest=undefined, drain/peek=[], at=undefined,
67
+ * size=0, clear=no-op).
68
+ */
69
+ export interface InputAccessor<I = any> {
70
+ /** Latest decoded input. `undefined` when unknown sessionId or no input declared. */
71
+ readonly latest: I | undefined;
72
+ /**
73
+ * Find the buffered snapshot whose `[seqField]` equals `value`. The field
74
+ * name is the Room's `defineInput()` `seqField`. Linear scan — cheap for
75
+ * typical buffer sizes; not intended for very large rings. Returns
76
+ * `undefined` when no match is buffered (or `seqField` isn't configured).
77
+ *
78
+ * Useful for tick-aligned retrieval (lockstep, rollback).
79
+ */
80
+ at(value: number): I | undefined;
81
+ /** Take everything buffered (oldest → newest) and clear. Snapshots are safe to retain. */
82
+ drain(): I[];
83
+ /** Read everything buffered without consuming. */
84
+ peek(): I[];
85
+ /** Number of snapshots currently buffered. */
86
+ readonly size: number;
87
+ /** Drop all buffered snapshots (also resets the dedupe tracker). */
88
+ clear(): void;
89
+ }
90
+ /**
91
+ * Callable returned by `Room.defineInput()`. Assign it to `this.input` and
92
+ * call `room.input(sessionId)` per tick to read each client's latest input
93
+ * and/or buffered snapshots.
94
+ */
95
+ export type InputAPI<I = any> = (sessionId: string) => InputAccessor<I>;
96
+ /** @internal */
97
+ export declare class InputBufferImpl<I = any> {
98
+ private _items;
99
+ private _lastSeq;
100
+ private readonly _maxSize;
101
+ private readonly _seqField;
102
+ constructor(maxSize: number, seqField: string | undefined);
103
+ push(snapshot: I): void;
104
+ /** Returns true if `value` hasn't been seen, and updates the last-seen marker. */
105
+ accept(value: number): boolean;
106
+ drain(): I[];
107
+ peek(): I[];
108
+ at(value: number): I | undefined;
109
+ get size(): number;
110
+ clear(): void;
111
+ }
112
+ /**
113
+ * Default per-client accessor. Reads `_input` and `_inputBuffer` off the
114
+ * client at access time — both are nullable until the room declares input
115
+ * via `defineInput()`. Cached as `client._inputAccessor` at join, so
116
+ * `room.input(sessionId)` is a Map lookup + property read.
117
+ *
118
+ * @internal
119
+ */
120
+ export declare class InputAccessorImpl<I = any> implements InputAccessor<I> {
121
+ private _client;
122
+ constructor(client: ClientPrivate);
123
+ get latest(): I | undefined;
124
+ at(value: number): I | undefined;
125
+ drain(): I[];
126
+ peek(): I[];
127
+ get size(): number;
128
+ clear(): void;
129
+ }
130
+ /**
131
+ * Returned by `room.input(sessionId)` for unknown sessions and for rooms
132
+ * that didn't call `defineInput()`.
133
+ *
134
+ * @internal
135
+ */
136
+ export declare const NO_OP_INPUT_ACCESSOR: InputAccessor<any>;
@@ -0,0 +1,86 @@
1
+ // packages/core/src/input/InputBuffer.ts
2
+ var InputBufferImpl = class {
3
+ constructor(maxSize, seqField) {
4
+ this._items = [];
5
+ this._lastSeq = -Infinity;
6
+ this._maxSize = maxSize;
7
+ this._seqField = seqField;
8
+ }
9
+ push(snapshot) {
10
+ this._items.push(snapshot);
11
+ if (this._items.length > this._maxSize) {
12
+ this._items.shift();
13
+ }
14
+ }
15
+ /** Returns true if `value` hasn't been seen, and updates the last-seen marker. */
16
+ accept(value) {
17
+ if (value <= this._lastSeq) {
18
+ return false;
19
+ }
20
+ this._lastSeq = value;
21
+ return true;
22
+ }
23
+ drain() {
24
+ const out = this._items;
25
+ this._items = [];
26
+ return out;
27
+ }
28
+ peek() {
29
+ return this._items.slice();
30
+ }
31
+ at(value) {
32
+ if (this._seqField === void 0) {
33
+ return void 0;
34
+ }
35
+ for (let i = 0; i < this._items.length; i++) {
36
+ if (this._items[i][this._seqField] === value) {
37
+ return this._items[i];
38
+ }
39
+ }
40
+ return void 0;
41
+ }
42
+ get size() {
43
+ return this._items.length;
44
+ }
45
+ clear() {
46
+ this._items.length = 0;
47
+ this._lastSeq = -Infinity;
48
+ }
49
+ };
50
+ var InputAccessorImpl = class {
51
+ constructor(client) {
52
+ this._client = client;
53
+ }
54
+ get latest() {
55
+ return this._client._input;
56
+ }
57
+ at(value) {
58
+ return this._client._inputBuffer?.at(value);
59
+ }
60
+ drain() {
61
+ return this._client._inputBuffer?.drain() ?? [];
62
+ }
63
+ peek() {
64
+ return this._client._inputBuffer?.peek() ?? [];
65
+ }
66
+ get size() {
67
+ return this._client._inputBuffer?.size ?? 0;
68
+ }
69
+ clear() {
70
+ this._client._inputBuffer?.clear();
71
+ }
72
+ };
73
+ var NO_OP_INPUT_ACCESSOR = Object.freeze({
74
+ latest: void 0,
75
+ at: () => void 0,
76
+ drain: () => [],
77
+ peek: () => [],
78
+ size: 0,
79
+ clear: () => {
80
+ }
81
+ });
82
+ export {
83
+ InputAccessorImpl,
84
+ InputBufferImpl,
85
+ NO_OP_INPUT_ACCESSOR
86
+ };
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/input/InputBuffer.ts"],
4
+ "sourcesContent": ["import type { ClientPrivate } from '../Transport.ts';\n\n/**\n * Names of fields on `I` whose values are `number` \u2014 used by\n * `Room.defineInput()` to constrain `seqField` to actually-numeric fields\n * on the input schema. Filters out booleans, strings, methods, etc.\n */\nexport type NumericFieldsOf<I> = {\n [K in keyof I]: I[K] extends number ? (K extends string ? K : never) : never;\n}[keyof I];\n\n/**\n * Internal: input configuration captured by `Room.defineInput()`. The schema\n * constructor is stored here so the runtime doesn't need to know it through\n * the public `room.input` (which is now a callable accessor).\n *\n * @internal\n */\nexport interface InputOptions {\n /**\n * Schema constructor used to allocate per-client input instances on join.\n * Captured by `defineInput()` from its `type` argument.\n *\n * Typed loosely (`new () => any`) to sidestep type-identity issues across\n * duplicate `@colyseus/schema` installs; the runtime calls\n * `instance.clone()` and friends, which match by shape.\n */\n ctor: new () => any;\n\n /**\n * Name of a monotonically-increasing numeric field on the input schema used\n * to order and dedupe incoming frames. When set, the framework:\n * - Drops redundant frames (`input[seqField]` \u2264 the last-seen value are\n * discarded before they enter the buffer). Matches the unreliable-mode\n * ring-redundancy pattern out of the box.\n * - Powers `room.input(sessionId).at(value)` lookups.\n *\n * Despite the name, \"seq\" here is broader than an integer counter \u2014 any\n * monotonic numeric field works:\n * - **Sequence counter** (`\"seq\"`, `\"tick\"`, `\"frame\"`) \u2014 typical for\n * lockstep / rollback netcode (Photon Quantum, GGPO).\n * - **Timestamp** (`\"timestamp\"`, milliseconds or seconds) \u2014 useful for\n * variable-rate clients, lag compensation, hit registration (Unreal CMC\n * uses float-seconds timestamps via `FSavedMove_Character.TimeStamp`).\n *\n * Whichever you use, the field must increase monotonically across frames\n * for dedupe to work.\n */\n seqField?: string;\n\n /**\n * > 0 enables per-client buffering of cloned snapshots \u2014 required for\n * `room.input(sessionId).drain() / .peek() / .at()` to return populated\n * data. Oldest drops on overflow. Set to `0` to disable (`.latest` still\n * works).\n */\n bufferMaxSize: number;\n}\n\n/**\n * Per-client input accessor returned by `room.input(sessionId)`. Combines the\n * latest decoded instance with the (optional) snapshot ring buffer.\n *\n * - {@link latest} \u2014 the bound Schema instance, mutated in place by the\n * decoder. Cheapest read; use when only the most recent state matters.\n * - {@link drain} / {@link peek} / {@link at} \u2014 populated when\n * `defineInput()` was called with `bufferMaxSize > 0` (default 32).\n * Use for rollback netcode / lockstep where every frame matters.\n *\n * Returned for unknown sessionIds and rooms without `defineInput()` is a\n * frozen no-op accessor (latest=undefined, drain/peek=[], at=undefined,\n * size=0, clear=no-op).\n */\nexport interface InputAccessor<I = any> {\n /** Latest decoded input. `undefined` when unknown sessionId or no input declared. */\n readonly latest: I | undefined;\n\n /**\n * Find the buffered snapshot whose `[seqField]` equals `value`. The field\n * name is the Room's `defineInput()` `seqField`. Linear scan \u2014 cheap for\n * typical buffer sizes; not intended for very large rings. Returns\n * `undefined` when no match is buffered (or `seqField` isn't configured).\n *\n * Useful for tick-aligned retrieval (lockstep, rollback).\n */\n at(value: number): I | undefined;\n\n /** Take everything buffered (oldest \u2192 newest) and clear. Snapshots are safe to retain. */\n drain(): I[];\n\n /** Read everything buffered without consuming. */\n peek(): I[];\n\n /** Number of snapshots currently buffered. */\n readonly size: number;\n\n /** Drop all buffered snapshots (also resets the dedupe tracker). */\n clear(): void;\n}\n\n/**\n * Callable returned by `Room.defineInput()`. Assign it to `this.input` and\n * call `room.input(sessionId)` per tick to read each client's latest input\n * and/or buffered snapshots.\n */\nexport type InputAPI<I = any> = (sessionId: string) => InputAccessor<I>;\n\n/** @internal */\nexport class InputBufferImpl<I = any> {\n private _items: I[] = [];\n private _lastSeq: number = -Infinity;\n private readonly _maxSize: number;\n private readonly _seqField: string | undefined;\n\n constructor(maxSize: number, seqField: string | undefined) {\n this._maxSize = maxSize;\n this._seqField = seqField;\n }\n\n push(snapshot: I): void {\n this._items.push(snapshot);\n if (this._items.length > this._maxSize) { this._items.shift(); }\n }\n\n /** Returns true if `value` hasn't been seen, and updates the last-seen marker. */\n accept(value: number): boolean {\n if (value <= this._lastSeq) { return false; }\n this._lastSeq = value;\n return true;\n }\n\n drain(): I[] {\n const out = this._items;\n this._items = [];\n return out;\n }\n\n peek(): I[] {\n return this._items.slice();\n }\n\n at(value: number): I | undefined {\n if (this._seqField === undefined) { return undefined; }\n for (let i = 0; i < this._items.length; i++) {\n if ((this._items[i] as any)[this._seqField] === value) { return this._items[i]; }\n }\n return undefined;\n }\n\n get size(): number {\n return this._items.length;\n }\n\n clear(): void {\n this._items.length = 0;\n this._lastSeq = -Infinity;\n }\n}\n\n/**\n * Default per-client accessor. Reads `_input` and `_inputBuffer` off the\n * client at access time \u2014 both are nullable until the room declares input\n * via `defineInput()`. Cached as `client._inputAccessor` at join, so\n * `room.input(sessionId)` is a Map lookup + property read.\n *\n * @internal\n */\nexport class InputAccessorImpl<I = any> implements InputAccessor<I> {\n private _client: ClientPrivate;\n constructor(client: ClientPrivate) { this._client = client; }\n get latest(): I | undefined { return this._client._input as I | undefined; }\n at(value: number): I | undefined { return this._client._inputBuffer?.at(value) as I | undefined; }\n drain(): I[] { return (this._client._inputBuffer?.drain() ?? []) as I[]; }\n peek(): I[] { return (this._client._inputBuffer?.peek() ?? []) as I[]; }\n get size(): number { return this._client._inputBuffer?.size ?? 0; }\n clear(): void { this._client._inputBuffer?.clear(); }\n}\n\n/**\n * Returned by `room.input(sessionId)` for unknown sessions and for rooms\n * that didn't call `defineInput()`.\n *\n * @internal\n */\nexport const NO_OP_INPUT_ACCESSOR: InputAccessor<any> = Object.freeze({\n latest: undefined,\n at: () => undefined,\n drain: () => [],\n peek: () => [],\n size: 0,\n clear: () => {},\n});\n"],
5
+ "mappings": ";AA4GO,IAAM,kBAAN,MAA+B;AAAA,EAMpC,YAAY,SAAiB,UAA8B;AAL3D,SAAQ,SAAc,CAAC;AACvB,SAAQ,WAAmB;AAKzB,SAAK,WAAW;AAChB,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,KAAK,UAAmB;AACtB,SAAK,OAAO,KAAK,QAAQ;AACzB,QAAI,KAAK,OAAO,SAAS,KAAK,UAAU;AAAE,WAAK,OAAO,MAAM;AAAA,IAAG;AAAA,EACjE;AAAA;AAAA,EAGA,OAAO,OAAwB;AAC7B,QAAI,SAAS,KAAK,UAAU;AAAE,aAAO;AAAA,IAAO;AAC5C,SAAK,WAAW;AAChB,WAAO;AAAA,EACT;AAAA,EAEA,QAAa;AACX,UAAM,MAAM,KAAK;AACjB,SAAK,SAAS,CAAC;AACf,WAAO;AAAA,EACT;AAAA,EAEA,OAAY;AACV,WAAO,KAAK,OAAO,MAAM;AAAA,EAC3B;AAAA,EAEA,GAAG,OAA8B;AAC/B,QAAI,KAAK,cAAc,QAAW;AAAE,aAAO;AAAA,IAAW;AACtD,aAAS,IAAI,GAAG,IAAI,KAAK,OAAO,QAAQ,KAAK;AAC3C,UAAK,KAAK,OAAO,CAAC,EAAU,KAAK,SAAS,MAAM,OAAO;AAAE,eAAO,KAAK,OAAO,CAAC;AAAA,MAAG;AAAA,IAClF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,OAAe;AACjB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAEA,QAAc;AACZ,SAAK,OAAO,SAAS;AACrB,SAAK,WAAW;AAAA,EAClB;AACF;AAUO,IAAM,oBAAN,MAA6D;AAAA,EAElE,YAAY,QAAuB;AAAE,SAAK,UAAU;AAAA,EAAQ;AAAA,EAC5D,IAAI,SAAwB;AAAE,WAAO,KAAK,QAAQ;AAAA,EAAyB;AAAA,EAC3E,GAAG,OAA8B;AAAE,WAAO,KAAK,QAAQ,cAAc,GAAG,KAAK;AAAA,EAAoB;AAAA,EACjG,QAAa;AAAE,WAAQ,KAAK,QAAQ,cAAc,MAAM,KAAK,CAAC;AAAA,EAAW;AAAA,EACzE,OAAY;AAAE,WAAQ,KAAK,QAAQ,cAAc,KAAK,KAAK,CAAC;AAAA,EAAW;AAAA,EACvE,IAAI,OAAe;AAAE,WAAO,KAAK,QAAQ,cAAc,QAAQ;AAAA,EAAG;AAAA,EAClE,QAAc;AAAE,SAAK,QAAQ,cAAc,MAAM;AAAA,EAAG;AACtD;AAQO,IAAM,uBAA2C,OAAO,OAAO;AAAA,EACpE,QAAQ;AAAA,EACR,IAAI,MAAM;AAAA,EACV,OAAO,MAAM,CAAC;AAAA,EACd,MAAM,MAAM,CAAC;AAAA,EACb,MAAM;AAAA,EACN,OAAO,MAAM;AAAA,EAAC;AAChB,CAAC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // packages/core/src/internal.ts
31
+ var internal_exports = {};
32
+ __export(internal_exports, {
33
+ USER_ROOMS_KEY_PREFIX: () => import_UserSessionIndex2.USER_ROOMS_KEY_PREFIX,
34
+ listUserSessions: () => import_UserSessionIndex2.listUserSessions,
35
+ listUserSessionsLive: () => listUserSessionsLive,
36
+ releaseRoomLeave: () => import_UserSessionIndex2.releaseRoomLeave,
37
+ releaseUserSession: () => import_UserSessionIndex2.releaseUserSession,
38
+ sweepRoomDispose: () => import_UserSessionIndex2.sweepRoomDispose,
39
+ trackRoomJoin: () => import_UserSessionIndex2.trackRoomJoin,
40
+ trackUserSession: () => import_UserSessionIndex2.trackUserSession,
41
+ userRoomsKey: () => import_UserSessionIndex2.userRoomsKey
42
+ });
43
+ module.exports = __toCommonJS(internal_exports);
44
+ var matchMaker = __toESM(require("./MatchMaker.cjs"), 1);
45
+ var import_UserSessionIndex = require("./utils/UserSessionIndex.cjs");
46
+ var import_UserSessionIndex2 = require("./utils/UserSessionIndex.cjs");
47
+ function listUserSessionsLive(userId, options) {
48
+ return (0, import_UserSessionIndex.listUserSessions)(matchMaker.presence, matchMaker.findRoomsByIds, userId, options);
49
+ }
50
+ // Annotate the CommonJS export names for ESM import in node:
51
+ 0 && (module.exports = {
52
+ USER_ROOMS_KEY_PREFIX,
53
+ listUserSessions,
54
+ listUserSessionsLive,
55
+ releaseRoomLeave,
56
+ releaseUserSession,
57
+ sweepRoomDispose,
58
+ trackRoomJoin,
59
+ trackUserSession,
60
+ userRoomsKey
61
+ });
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/internal.ts"],
4
+ "sourcesContent": ["/**\n * Framework-internal entry \u2014 symbols used by the bundled `colyseus`\n * plugins (track-user-sessions, unique-session) and the admin\n * backend, but NOT part of `@colyseus/core`'s public surface.\n *\n * Third parties should reach for `TrackUserSessionsPlugin` and its\n * `listUserSessions` static instead \u2014 the raw helpers below are\n * implementation details and can change between minor versions.\n *\n * Resolved via the `./*` wildcard in `packages/core/package.json`.\n *\n * @internal\n */\nimport * as matchMaker from './MatchMaker.ts';\nimport {\n listUserSessions,\n type ListUserSessionsOptions,\n type UserSessionInfo,\n} from './utils/UserSessionIndex.ts';\n\nexport {\n userRoomsKey,\n USER_ROOMS_KEY_PREFIX,\n trackUserSession,\n releaseUserSession,\n trackRoomJoin,\n releaseRoomLeave,\n sweepRoomDispose,\n listUserSessions,\n type UserRoomEntry,\n type UserSessionInfo,\n type ListUserSessionsOptions,\n} from './utils/UserSessionIndex.ts';\n\n/**\n * `listUserSessions` wired to the live `matchMaker` \u2014 what\n * `TrackUserSessionsPlugin.listUserSessions` and the admin backend\n * actually call. The pure `listUserSessions` is kept exported above\n * so unit tests can drive it with fake presence + findRooms.\n */\nexport function listUserSessionsLive(\n userId: string,\n options?: ListUserSessionsOptions,\n): Promise<UserSessionInfo[]> {\n return listUserSessions(matchMaker.presence, matchMaker.findRoomsByIds, userId, options);\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,iBAA4B;AAC5B,8BAIO;AAEP,IAAAA,2BAYO;AAQA,SAAS,qBACd,QACA,SAC4B;AAC5B,aAAO,0CAA4B,qBAAqB,2BAAgB,QAAQ,OAAO;AACzF;",
6
+ "names": ["import_UserSessionIndex"]
7
+ }
@@ -0,0 +1,9 @@
1
+ import { type ListUserSessionsOptions, type UserSessionInfo } from './utils/UserSessionIndex.ts';
2
+ export { userRoomsKey, USER_ROOMS_KEY_PREFIX, trackUserSession, releaseUserSession, trackRoomJoin, releaseRoomLeave, sweepRoomDispose, listUserSessions, type UserRoomEntry, type UserSessionInfo, type ListUserSessionsOptions, } from './utils/UserSessionIndex.ts';
3
+ /**
4
+ * `listUserSessions` wired to the live `matchMaker` — what
5
+ * `TrackUserSessionsPlugin.listUserSessions` and the admin backend
6
+ * actually call. The pure `listUserSessions` is kept exported above
7
+ * so unit tests can drive it with fake presence + findRooms.
8
+ */
9
+ export declare function listUserSessionsLive(userId: string, options?: ListUserSessionsOptions): Promise<UserSessionInfo[]>;
@@ -0,0 +1,29 @@
1
+ // packages/core/src/internal.ts
2
+ import * as matchMaker from "./MatchMaker.mjs";
3
+ import {
4
+ listUserSessions
5
+ } from "./utils/UserSessionIndex.mjs";
6
+ import {
7
+ userRoomsKey,
8
+ USER_ROOMS_KEY_PREFIX,
9
+ trackUserSession,
10
+ releaseUserSession,
11
+ trackRoomJoin,
12
+ releaseRoomLeave,
13
+ sweepRoomDispose,
14
+ listUserSessions as listUserSessions2
15
+ } from "./utils/UserSessionIndex.mjs";
16
+ function listUserSessionsLive(userId, options) {
17
+ return listUserSessions(matchMaker.presence, matchMaker.findRoomsByIds, userId, options);
18
+ }
19
+ export {
20
+ USER_ROOMS_KEY_PREFIX,
21
+ listUserSessions2 as listUserSessions,
22
+ listUserSessionsLive,
23
+ releaseRoomLeave,
24
+ releaseUserSession,
25
+ sweepRoomDispose,
26
+ trackRoomJoin,
27
+ trackUserSession,
28
+ userRoomsKey
29
+ };
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/internal.ts"],
4
+ "sourcesContent": ["/**\n * Framework-internal entry \u2014 symbols used by the bundled `colyseus`\n * plugins (track-user-sessions, unique-session) and the admin\n * backend, but NOT part of `@colyseus/core`'s public surface.\n *\n * Third parties should reach for `TrackUserSessionsPlugin` and its\n * `listUserSessions` static instead \u2014 the raw helpers below are\n * implementation details and can change between minor versions.\n *\n * Resolved via the `./*` wildcard in `packages/core/package.json`.\n *\n * @internal\n */\nimport * as matchMaker from './MatchMaker.ts';\nimport {\n listUserSessions,\n type ListUserSessionsOptions,\n type UserSessionInfo,\n} from './utils/UserSessionIndex.ts';\n\nexport {\n userRoomsKey,\n USER_ROOMS_KEY_PREFIX,\n trackUserSession,\n releaseUserSession,\n trackRoomJoin,\n releaseRoomLeave,\n sweepRoomDispose,\n listUserSessions,\n type UserRoomEntry,\n type UserSessionInfo,\n type ListUserSessionsOptions,\n} from './utils/UserSessionIndex.ts';\n\n/**\n * `listUserSessions` wired to the live `matchMaker` \u2014 what\n * `TrackUserSessionsPlugin.listUserSessions` and the admin backend\n * actually call. The pure `listUserSessions` is kept exported above\n * so unit tests can drive it with fake presence + findRooms.\n */\nexport function listUserSessionsLive(\n userId: string,\n options?: ListUserSessionsOptions,\n): Promise<UserSessionInfo[]> {\n return listUserSessions(matchMaker.presence, matchMaker.findRoomsByIds, userId, options);\n}\n"],
5
+ "mappings": ";AAaA,YAAY,gBAAgB;AAC5B;AAAA,EACE;AAAA,OAGK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAAA;AAAA,OAIK;AAQA,SAAS,qBACd,QACA,SAC4B;AAC5B,SAAO,iBAA4B,qBAAqB,2BAAgB,QAAQ,OAAO;AACzF;",
6
+ "names": ["listUserSessions"]
7
+ }
@@ -52,6 +52,19 @@ var LocalDriver = class {
52
52
  }
53
53
  return query;
54
54
  }
55
+ async findByIds(roomIds) {
56
+ const result = /* @__PURE__ */ new Map();
57
+ if (roomIds.length === 0) {
58
+ return result;
59
+ }
60
+ const wanted = new Set(roomIds);
61
+ for (const room of this.rooms) {
62
+ if (wanted.has(room.roomId)) {
63
+ result.set(room.roomId, room);
64
+ }
65
+ }
66
+ return result;
67
+ }
55
68
  update(room, operations) {
56
69
  if (operations.$set) {
57
70
  for (const field in operations.$set) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/matchmaker/LocalDriver/LocalDriver.ts"],
4
- "sourcesContent": ["import { debugMatchMaking } from '../../Debug.ts';\nimport type { IRoomCache, SortOptions, MatchMakerDriver } from '../driver.ts';\nimport { Query } from './Query.ts';\n\n// re-export\nexport type { IRoomCache, SortOptions, MatchMakerDriver };\n\nexport class LocalDriver implements MatchMakerDriver {\n public rooms: IRoomCache[] = [];\n\n public has(roomId: string) {\n return this.rooms.some((room) => room.roomId === roomId);\n }\n\n public query(conditions: Partial<IRoomCache>, sortOptions?: SortOptions) {\n const query = new Query<IRoomCache>(this.rooms, conditions);\n\n if (sortOptions) {\n query.sort(sortOptions);\n }\n\n return query.filter(conditions);\n }\n\n public cleanup(processId: string) {\n const cachedRooms = this.query({ processId });\n debugMatchMaking(\"removing stale rooms by processId %s (%s rooms found)\", processId, cachedRooms.length);\n\n cachedRooms.forEach((room) => this.remove(room.roomId));\n return Promise.resolve();\n }\n\n public findOne(conditions: Partial<IRoomCache>, sortOptions?: SortOptions) {\n const query = new Query<IRoomCache>(this.rooms, conditions);\n\n if (sortOptions) {\n query.sort(sortOptions);\n }\n\n return query as unknown as Promise<IRoomCache>;\n }\n\n public update(room: IRoomCache, operations: Partial<{ $set: Partial<IRoomCache>, $inc: Partial<IRoomCache> }>) {\n if (operations.$set) {\n for (const field in operations.$set) {\n if (operations.$set.hasOwnProperty(field)) {\n room[field] = operations.$set[field];\n }\n }\n }\n\n if (operations.$inc) {\n for (const field in operations.$inc) {\n if (operations.$inc.hasOwnProperty(field)) {\n room[field] += operations.$inc[field];\n }\n }\n }\n\n return true;\n }\n\n public persist(room: IRoomCache, create: boolean = false) {\n // if (this.rooms.indexOf(room) !== -1) {\n // // already in the list\n // return true;\n // }\n\n if (!create) { return false; }\n\n // add to the list\n this.rooms.push(room);\n\n return true;\n }\n\n public remove(roomId: string) {\n const roomIndex = this.rooms.findIndex((room) => room.roomId === roomId);\n if (roomIndex !== -1) {\n this.rooms.splice(roomIndex, 1);\n return true;\n }\n return false;\n }\n\n public clear() {\n this.rooms = [];\n }\n\n public shutdown() {\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAiC;AAEjC,mBAAsB;AAKf,IAAM,cAAN,MAA8C;AAAA,EAA9C;AACL,SAAO,QAAsB,CAAC;AAAA;AAAA,EAEvB,IAAI,QAAgB;AACzB,WAAO,KAAK,MAAM,KAAK,CAAC,SAAS,KAAK,WAAW,MAAM;AAAA,EACzD;AAAA,EAEO,MAAM,YAAiC,aAA2B;AACvE,UAAM,QAAQ,IAAI,mBAAkB,KAAK,OAAO,UAAU;AAE1D,QAAI,aAAa;AACf,YAAM,KAAK,WAAW;AAAA,IACxB;AAEA,WAAO,MAAM,OAAO,UAAU;AAAA,EAChC;AAAA,EAEO,QAAQ,WAAmB;AAChC,UAAM,cAAc,KAAK,MAAM,EAAE,UAAU,CAAC;AAC5C,uCAAiB,yDAAyD,WAAW,YAAY,MAAM;AAEvG,gBAAY,QAAQ,CAAC,SAAS,KAAK,OAAO,KAAK,MAAM,CAAC;AACtD,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEO,QAAQ,YAAiC,aAA2B;AACzE,UAAM,QAAQ,IAAI,mBAAkB,KAAK,OAAO,UAAU;AAE1D,QAAI,aAAa;AACf,YAAM,KAAK,WAAW;AAAA,IACxB;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,OAAO,MAAkB,YAA+E;AAC7G,QAAI,WAAW,MAAM;AACnB,iBAAW,SAAS,WAAW,MAAM;AACnC,YAAI,WAAW,KAAK,eAAe,KAAK,GAAG;AACzC,eAAK,KAAK,IAAI,WAAW,KAAK,KAAK;AAAA,QACrC;AAAA,MACF;AAAA,IACF;AAEA,QAAI,WAAW,MAAM;AACnB,iBAAW,SAAS,WAAW,MAAM;AACnC,YAAI,WAAW,KAAK,eAAe,KAAK,GAAG;AACzC,eAAK,KAAK,KAAK,WAAW,KAAK,KAAK;AAAA,QACtC;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,QAAQ,MAAkB,SAAkB,OAAO;AAMxD,QAAI,CAAC,QAAQ;AAAE,aAAO;AAAA,IAAO;AAG7B,SAAK,MAAM,KAAK,IAAI;AAEpB,WAAO;AAAA,EACT;AAAA,EAEO,OAAO,QAAgB;AAC5B,UAAM,YAAY,KAAK,MAAM,UAAU,CAAC,SAAS,KAAK,WAAW,MAAM;AACvE,QAAI,cAAc,IAAI;AACpB,WAAK,MAAM,OAAO,WAAW,CAAC;AAC9B,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EAEO,QAAQ;AACb,SAAK,QAAQ,CAAC;AAAA,EAChB;AAAA,EAEO,WAAW;AAAA,EAClB;AACF;",
4
+ "sourcesContent": ["import { debugMatchMaking } from '../../Debug.ts';\nimport type { IRoomCache, SortOptions, MatchMakerDriver } from '../driver.ts';\nimport { Query } from './Query.ts';\n\n// re-export\nexport type { IRoomCache, SortOptions, MatchMakerDriver };\n\nexport class LocalDriver implements MatchMakerDriver {\n public rooms: IRoomCache[] = [];\n\n public has(roomId: string) {\n return this.rooms.some((room) => room.roomId === roomId);\n }\n\n public query(conditions: Partial<IRoomCache>, sortOptions?: SortOptions) {\n const query = new Query<IRoomCache>(this.rooms, conditions);\n\n if (sortOptions) {\n query.sort(sortOptions);\n }\n\n return query.filter(conditions);\n }\n\n public cleanup(processId: string) {\n const cachedRooms = this.query({ processId });\n debugMatchMaking(\"removing stale rooms by processId %s (%s rooms found)\", processId, cachedRooms.length);\n\n cachedRooms.forEach((room) => this.remove(room.roomId));\n return Promise.resolve();\n }\n\n public findOne(conditions: Partial<IRoomCache>, sortOptions?: SortOptions) {\n const query = new Query<IRoomCache>(this.rooms, conditions);\n\n if (sortOptions) {\n query.sort(sortOptions);\n }\n\n return query as unknown as Promise<IRoomCache>;\n }\n\n public async findByIds(roomIds: string[]): Promise<Map<string, IRoomCache>> {\n const result = new Map<string, IRoomCache>();\n if (roomIds.length === 0) { return result; }\n const wanted = new Set(roomIds);\n for (const room of this.rooms) {\n if (wanted.has(room.roomId)) { result.set(room.roomId, room); }\n }\n return result;\n }\n\n public update(room: IRoomCache, operations: Partial<{ $set: Partial<IRoomCache>, $inc: Partial<IRoomCache> }>) {\n if (operations.$set) {\n for (const field in operations.$set) {\n if (operations.$set.hasOwnProperty(field)) {\n room[field] = operations.$set[field];\n }\n }\n }\n\n if (operations.$inc) {\n for (const field in operations.$inc) {\n if (operations.$inc.hasOwnProperty(field)) {\n room[field] += operations.$inc[field];\n }\n }\n }\n\n return true;\n }\n\n public persist(room: IRoomCache, create: boolean = false) {\n // if (this.rooms.indexOf(room) !== -1) {\n // // already in the list\n // return true;\n // }\n\n if (!create) { return false; }\n\n // add to the list\n this.rooms.push(room);\n\n return true;\n }\n\n public remove(roomId: string) {\n const roomIndex = this.rooms.findIndex((room) => room.roomId === roomId);\n if (roomIndex !== -1) {\n this.rooms.splice(roomIndex, 1);\n return true;\n }\n return false;\n }\n\n public clear() {\n this.rooms = [];\n }\n\n public shutdown() {\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAiC;AAEjC,mBAAsB;AAKf,IAAM,cAAN,MAA8C;AAAA,EAA9C;AACL,SAAO,QAAsB,CAAC;AAAA;AAAA,EAEvB,IAAI,QAAgB;AACzB,WAAO,KAAK,MAAM,KAAK,CAAC,SAAS,KAAK,WAAW,MAAM;AAAA,EACzD;AAAA,EAEO,MAAM,YAAiC,aAA2B;AACvE,UAAM,QAAQ,IAAI,mBAAkB,KAAK,OAAO,UAAU;AAE1D,QAAI,aAAa;AACf,YAAM,KAAK,WAAW;AAAA,IACxB;AAEA,WAAO,MAAM,OAAO,UAAU;AAAA,EAChC;AAAA,EAEO,QAAQ,WAAmB;AAChC,UAAM,cAAc,KAAK,MAAM,EAAE,UAAU,CAAC;AAC5C,uCAAiB,yDAAyD,WAAW,YAAY,MAAM;AAEvG,gBAAY,QAAQ,CAAC,SAAS,KAAK,OAAO,KAAK,MAAM,CAAC;AACtD,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEO,QAAQ,YAAiC,aAA2B;AACzE,UAAM,QAAQ,IAAI,mBAAkB,KAAK,OAAO,UAAU;AAE1D,QAAI,aAAa;AACf,YAAM,KAAK,WAAW;AAAA,IACxB;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAa,UAAU,SAAqD;AAC1E,UAAM,SAAS,oBAAI,IAAwB;AAC3C,QAAI,QAAQ,WAAW,GAAG;AAAE,aAAO;AAAA,IAAQ;AAC3C,UAAM,SAAS,IAAI,IAAI,OAAO;AAC9B,eAAW,QAAQ,KAAK,OAAO;AAC7B,UAAI,OAAO,IAAI,KAAK,MAAM,GAAG;AAAE,eAAO,IAAI,KAAK,QAAQ,IAAI;AAAA,MAAG;AAAA,IAChE;AACA,WAAO;AAAA,EACT;AAAA,EAEO,OAAO,MAAkB,YAA+E;AAC7G,QAAI,WAAW,MAAM;AACnB,iBAAW,SAAS,WAAW,MAAM;AACnC,YAAI,WAAW,KAAK,eAAe,KAAK,GAAG;AACzC,eAAK,KAAK,IAAI,WAAW,KAAK,KAAK;AAAA,QACrC;AAAA,MACF;AAAA,IACF;AAEA,QAAI,WAAW,MAAM;AACnB,iBAAW,SAAS,WAAW,MAAM;AACnC,YAAI,WAAW,KAAK,eAAe,KAAK,GAAG;AACzC,eAAK,KAAK,KAAK,WAAW,KAAK,KAAK;AAAA,QACtC;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,QAAQ,MAAkB,SAAkB,OAAO;AAMxD,QAAI,CAAC,QAAQ;AAAE,aAAO;AAAA,IAAO;AAG7B,SAAK,MAAM,KAAK,IAAI;AAEpB,WAAO;AAAA,EACT;AAAA,EAEO,OAAO,QAAgB;AAC5B,UAAM,YAAY,KAAK,MAAM,UAAU,CAAC,SAAS,KAAK,WAAW,MAAM;AACvE,QAAI,cAAc,IAAI;AACpB,WAAK,MAAM,OAAO,WAAW,CAAC;AAC9B,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EAEO,QAAQ;AACb,SAAK,QAAQ,CAAC;AAAA,EAChB;AAAA,EAEO,WAAW;AAAA,EAClB;AACF;",
6
6
  "names": []
7
7
  }
@@ -6,6 +6,7 @@ export declare class LocalDriver implements MatchMakerDriver {
6
6
  query(conditions: Partial<IRoomCache>, sortOptions?: SortOptions): IRoomCache<any>[];
7
7
  cleanup(processId: string): Promise<void>;
8
8
  findOne(conditions: Partial<IRoomCache>, sortOptions?: SortOptions): Promise<IRoomCache>;
9
+ findByIds(roomIds: string[]): Promise<Map<string, IRoomCache>>;
9
10
  update(room: IRoomCache, operations: Partial<{
10
11
  $set: Partial<IRoomCache>;
11
12
  $inc: Partial<IRoomCache>;