@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/Server.mjs CHANGED
@@ -5,13 +5,15 @@ import * as matchMaker from "./MatchMaker.mjs";
5
5
  import { RegisteredHandler } from "./matchmaker/RegisteredHandler.mjs";
6
6
  import { Room } from "./Room.mjs";
7
7
  import { Deferred, registerGracefulShutdown, dynamicImport } from "./utils/Utils.mjs";
8
+ import { LocalPresence } from "./presence/LocalPresence.mjs";
9
+ import { LocalDriver } from "./matchmaker/LocalDriver/LocalDriver.mjs";
8
10
  import { setTransport } from "./Transport.mjs";
9
11
  import { logger, setLogger } from "./Logger.mjs";
10
12
  import { setDevMode, isDevMode } from "./utils/DevMode.mjs";
11
- import { bindRouterToTransport } from "./router/index.mjs";
13
+ import { bindRouterToTransport, createRouter } from "./router/index.mjs";
12
14
  import "@colyseus/shared-types";
13
15
  import { getDefaultRouter } from "./router/default_routes.mjs";
14
- var Server = class {
16
+ var Server = class _Server {
15
17
  constructor(options = {}) {
16
18
  this._onTransportReady = new Deferred();
17
19
  this._originalRoomOnMessage = null;
@@ -22,18 +24,18 @@ var Server = class {
22
24
  greet: greet2 = true
23
25
  } = options;
24
26
  setDevMode(options.devMode === true);
27
+ this.presence = options.presence || new LocalPresence();
28
+ this.driver = options.driver || new LocalDriver();
25
29
  this.options = options;
26
30
  this.greet = greet2;
31
+ _Server.current = this;
27
32
  this.attach(options);
28
33
  matchMaker.setup(
29
- options.presence,
30
- options.driver,
34
+ this.presence,
35
+ this.driver,
31
36
  options.publicAddress,
32
37
  options.selectProcessIdToCreateRoom
33
- ).then(() => {
34
- this.presence = matchMaker.presence;
35
- this.driver = matchMaker.driver;
36
- });
38
+ );
37
39
  if (gracefullyShutdown2) {
38
40
  registerGracefulShutdown((err) => this.gracefullyShutdown(true, err));
39
41
  }
@@ -43,10 +45,6 @@ var Server = class {
43
45
  }
44
46
  async attach(options) {
45
47
  this.transport = options.transport || await this.getDefaultTransport(options);
46
- if (options.express && this.transport.getExpressApp) {
47
- const expressApp = await this.transport.getExpressApp();
48
- await options.express(expressApp);
49
- }
50
48
  this._onTransportReady.resolve(this.transport);
51
49
  }
52
50
  /**
@@ -58,8 +56,20 @@ var Server = class {
58
56
  * @param listeningListener
59
57
  */
60
58
  async listen(port, hostname, backlog, listeningListener) {
61
- if (this.options.beforeListen) {
62
- await this.options.beforeListen();
59
+ const { beforeListen, database, express } = this.options;
60
+ if (beforeListen) {
61
+ await beforeListen();
62
+ }
63
+ if (database) {
64
+ await database.boot();
65
+ }
66
+ await this._applyRouterDefaults();
67
+ if (express) {
68
+ await this._onTransportReady;
69
+ if (this.transport.getExpressApp) {
70
+ const expressApp = await this.transport.getExpressApp();
71
+ await express(expressApp);
72
+ }
63
73
  }
64
74
  if (process.env.COLYSEUS_CLOUD !== void 0) {
65
75
  if (typeof hostname === "number") {
@@ -124,8 +134,8 @@ var Server = class {
124
134
  await this.onBeforeShutdownCallback();
125
135
  await matchMaker.gracefullyShutdown();
126
136
  this.transport.shutdown();
127
- this.presence?.shutdown();
128
- await this.driver?.shutdown();
137
+ this.presence.shutdown();
138
+ await this.driver.shutdown();
129
139
  await this.onShutdownCallback();
130
140
  } catch (e) {
131
141
  debugAndPrintError(`error during shutdown: ${e}`);
@@ -166,6 +176,30 @@ var Server = class {
166
176
  onBeforeShutdown(callback) {
167
177
  this.onBeforeShutdownCallback = callback;
168
178
  }
179
+ // Extend the user's router with framework-contributed endpoints. An explicit
180
+ // `auth` option wins over the database's `applyRouterDefaults` so a non-DB
181
+ // setup can still auto-mount @colyseus/auth, and a DB user can opt out.
182
+ async _applyRouterDefaults() {
183
+ const { auth, database } = this.options;
184
+ const wantsAuth = auth !== void 0 && auth !== false;
185
+ const wantsDatabase = auth === void 0 && !!database?.applyRouterDefaults;
186
+ if (!wantsAuth && !wantsDatabase) {
187
+ return;
188
+ }
189
+ this.router ??= createRouter({});
190
+ if (wantsAuth) {
191
+ const authMod = await dynamicImport("@colyseus/auth").catch(() => void 0);
192
+ const endpointsFn = authMod?.auth?.endpoints ?? authMod?.default?.auth?.endpoints;
193
+ if (typeof endpointsFn === "function") {
194
+ this.router = this.router.extend(endpointsFn(auth));
195
+ }
196
+ } else {
197
+ const updated = await database.applyRouterDefaults(this.router);
198
+ if (updated) {
199
+ this.router = updated;
200
+ }
201
+ }
202
+ }
169
203
  async getDefaultTransport(options) {
170
204
  try {
171
205
  const module = await dynamicImport("@colyseus/ws-transport");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/Server.ts"],
4
- "sourcesContent": ["import { greet } from \"@colyseus/greeting-banner\";\nimport type express from 'express';\n\nimport { debugAndPrintError } from './Debug.ts';\nimport * as matchMaker from './MatchMaker.ts';\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler.ts';\n\nimport { type OnCreateOptions, Room } from './Room.ts';\nimport { Deferred, registerGracefulShutdown, dynamicImport, type Type } from './utils/Utils.ts';\n\nimport type { Presence } from \"./presence/Presence.ts\";\n\nimport { setTransport, Transport } from './Transport.ts';\nimport { logger, setLogger } from './Logger.ts';\nimport { setDevMode, isDevMode } from './utils/DevMode.ts';\nimport { type Router, bindRouterToTransport } from './router/index.ts';\nimport { type SDKTypes as SharedSDKTypes } from '@colyseus/shared-types';\nimport { getDefaultRouter } from './router/default_routes.ts';\n\nexport type ServerOptions = {\n publicAddress?: string,\n presence?: Presence,\n driver?: matchMaker.MatchMakerDriver,\n transport?: Transport,\n gracefullyShutdown?: boolean,\n logger?: any;\n\n /**\n * Optional callback to execute before the server listens.\n * This is useful for example to connect into a database or other services before the server listens.\n */\n beforeListen?: () => Promise<void> | void,\n\n /**\n * Optional callback to configure Express routes.\n * When provided, the transport layer will initialize an Express-compatible app\n * and pass it to this callback for custom route configuration.\n *\n * For uWebSockets transport, this uses the uwebsockets-express module.\n */\n express?: (app: express.Application) => Promise<void> | void,\n\n /**\n * Custom function to determine which process should handle room creation.\n * Default: assign new rooms the process with least amount of rooms created\n */\n selectProcessIdToCreateRoom?: matchMaker.SelectProcessIdCallback;\n\n /**\n * Whether this process is running as a standalone match-maker or not. (default: false)\n * When enabled, this process will not spawn rooms and will only be responsible for matchmaking.\n */\n isStandaloneMatchMaker?: boolean; \n\n /**\n * If enabled, rooms are going to be restored in the server-side upon restart,\n * clients are going to automatically re-connect when server reboots.\n *\n * Beware of \"schema mismatch\" issues. When updating Schema structures and\n * reloading existing data, you may see \"schema mismatch\" errors in the\n * client-side.\n *\n * (This operation is costly and should not be used in a production\n * environment)\n */\n devMode?: boolean,\n\n /**\n * Display greeting message on server start.\n * Default: true\n */\n greet?: boolean,\n};\n\n/**\n * Exposed types for the client-side SDK.\n * Re-exported from @colyseus/shared-types with specific type constraints.\n */\nexport interface SDKTypes<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n> extends SharedSDKTypes<RoomTypes, Routes> {}\n\nexport class Server<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n> implements SDKTypes<RoomTypes, Routes> {\n '~rooms': RoomTypes;\n '~routes': Routes;\n\n public transport: Transport;\n public router: Routes;\n public options: ServerOptions;\n\n protected presence: Presence;\n protected driver: matchMaker.MatchMakerDriver;\n\n protected port: number | string;\n protected greet: boolean;\n\n protected _onTransportReady = new Deferred<Transport>();\n\n private _originalRoomOnMessage: typeof Room.prototype['_onMessage'] | null = null;\n\n constructor(options: ServerOptions = {}) {\n const {\n gracefullyShutdown = true,\n greet = true\n } = options;\n\n setDevMode(options.devMode === true);\n\n this.options = options;\n this.greet = greet;\n\n this.attach(options);\n\n // Pass options.presence/driver through as-is (possibly undefined).\n // matchMaker.setup() falls back to getDefaultPresence/getDefaultDriver,\n // which auto-select RedisPresence/RedisDriver on Colyseus Cloud.\n matchMaker.setup(\n options.presence,\n options.driver,\n options.publicAddress,\n options.selectProcessIdToCreateRoom,\n ).then(() => {\n this.presence = matchMaker.presence;\n this.driver = matchMaker.driver;\n });\n\n if (gracefullyShutdown) {\n registerGracefulShutdown((err) => this.gracefullyShutdown(true, err));\n }\n\n if (options.logger) {\n setLogger(options.logger);\n }\n }\n\n public async attach(options: ServerOptions) {\n this.transport = options.transport || await this.getDefaultTransport(options);\n\n // Initialize Express if callback is provided\n if (options.express && this.transport.getExpressApp) {\n const expressApp = await this.transport.getExpressApp();\n await options.express(expressApp);\n }\n\n // Resolve the promise when the transport is ready\n this._onTransportReady.resolve(this.transport);\n }\n\n /**\n * Bind the server into the port specified.\n *\n * @param port - Port number or Unix socket path\n * @param hostname\n * @param backlog\n * @param listeningListener\n */\n public async listen(port: number | string, hostname?: string, backlog?: number, listeningListener?: Function) {\n if (this.options.beforeListen) {\n await this.options.beforeListen();\n }\n\n //\n // if Colyseus Cloud is detected, use @colyseus/tools to listen\n //\n if (process.env.COLYSEUS_CLOUD !== undefined ) {\n if (typeof(hostname) === \"number\") {\n //\n // workaround, @colyseus/tools calls server.listen() again with the port as a string\n //\n hostname = undefined;\n\n } else {\n try {\n return (await dynamicImport(\"@colyseus/tools\")).listen(this);\n } catch (error) {\n const err = new Error(\"Please install @colyseus/tools to be able to host on Colyseus Cloud.\");\n err.cause = error;\n throw err;\n }\n }\n }\n\n //\n // otherwise, listen on the port directly\n //\n this.port = port;\n\n //\n // Make sure matchmaker is ready before accepting connections\n // (isDevMode: matchmaker may take extra milliseconds to restore the rooms)\n //\n await matchMaker.accept(this.options.isStandaloneMatchMaker);\n\n /**\n * Greetings!\n */\n if (this.greet) {\n greet();\n }\n\n // Wait for the transport to be ready\n await this._onTransportReady;\n\n return new Promise<void>((resolve, reject) => {\n // TODO: refactor me!\n // set transport globally, to be used by matchmaking route\n setTransport(this.transport);\n\n this.transport.listen(port, hostname, backlog, (err) => {\n if (this.transport.server) {\n this.transport.server.on('error', (err) => reject(err));\n }\n\n // default router is used if no router is provided\n if (!this.router) {\n this.router = getDefaultRouter() as unknown as Routes;\n\n } else {\n // make sure default routes are included\n // https://github.com/Bekacru/better-call/pull/67\n this.router = this.router.extend({ ...getDefaultRouter().endpoints }) as unknown as Routes;\n }\n\n bindRouterToTransport(this.transport, this.router, this.options.express !== undefined);\n\n if (listeningListener) {\n listeningListener(err);\n }\n\n if (err) {\n reject(err);\n\n } else {\n resolve();\n }\n });\n });\n }\n\n /**\n * Define a new type of room for matchmaking.\n *\n * @param name public room identifier for match-making.\n * @param roomClass Room class definition\n * @param defaultOptions default options for `onCreate`\n */\n public define<T extends Type<Room>>(\n roomClass: T,\n defaultOptions?: OnCreateOptions<T>,\n ): RegisteredHandler\n public define<T extends Type<Room>>(\n name: string,\n roomClass: T,\n defaultOptions?: OnCreateOptions<T>,\n ): RegisteredHandler\n public define<T extends Type<Room>>(\n nameOrHandler: string | T,\n handlerOrOptions: T | OnCreateOptions<T>,\n defaultOptions?: OnCreateOptions<T>,\n ): RegisteredHandler {\n const name = (typeof(nameOrHandler) === \"string\")\n ? nameOrHandler\n : nameOrHandler.name;\n\n const roomClass = (typeof(nameOrHandler) === \"string\")\n ? handlerOrOptions\n : nameOrHandler;\n\n const options = (typeof(nameOrHandler) === \"string\")\n ? defaultOptions\n : handlerOrOptions;\n\n return matchMaker.defineRoomType(name, roomClass, options);\n }\n\n /**\n * Remove a room definition from matchmaking.\n * This method does not destroy any room. It only dissallows matchmaking\n */\n public removeRoomType(name: string): void {\n matchMaker.removeRoomType(name);\n }\n\n public async gracefullyShutdown(exit: boolean = true, err?: Error) {\n if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {\n return;\n }\n\n try {\n // custom \"before shutdown\" method\n await this.onBeforeShutdownCallback();\n\n // this is going to lock all rooms and wait for them to be disposed\n await matchMaker.gracefullyShutdown();\n\n this.transport.shutdown();\n this.presence?.shutdown();\n await this.driver?.shutdown();\n\n // custom \"after shutdown\" method\n await this.onShutdownCallback();\n\n } catch (e) {\n debugAndPrintError(`error during shutdown: ${e}`);\n\n } finally {\n if (exit) {\n process.exit((err && !isDevMode) ? 1 : 0);\n }\n }\n }\n\n /**\n * Add simulated latency between client and server.\n * @param milliseconds round trip latency in milliseconds.\n */\n public simulateLatency(milliseconds: number) {\n if (milliseconds > 0) {\n logger.warn(`\uD83D\uDCF6\uFE0F\u2757 Colyseus latency simulation enabled \u2192 ${milliseconds}ms latency for round trip.`);\n } else {\n logger.warn(`\uD83D\uDCF6\uFE0F\u2757 Colyseus latency simulation disabled.`);\n }\n\n const halfwayMS = (milliseconds / 2);\n this.transport.simulateLatency(halfwayMS);\n\n if (this._originalRoomOnMessage == null) {\n this._originalRoomOnMessage = Room.prototype['_onMessage'];\n }\n\n const originalOnMessage = this._originalRoomOnMessage;\n\n Room.prototype['_onMessage'] = milliseconds <= Number.EPSILON ? originalOnMessage : function (this: Room, client, buffer) {\n // uWebSockets.js: duplicate buffer because it is cleared at native layer before the timeout.\n const cachedBuffer = Buffer.from(buffer);\n setTimeout(() => originalOnMessage.call(this, client, cachedBuffer), halfwayMS);\n };\n }\n\n /**\n * Register a callback that is going to be executed before the server shuts down.\n * @param callback\n */\n public onShutdown(callback: () => void | Promise<any>) {\n this.onShutdownCallback = callback;\n }\n\n public onBeforeShutdown(callback: () => void | Promise<any>) {\n this.onBeforeShutdownCallback = callback;\n }\n\n protected async getDefaultTransport(options: any): Promise<Transport> {\n try {\n const module = await dynamicImport('@colyseus/ws-transport');\n const WebSocketTransport = module.WebSocketTransport;\n return new WebSocketTransport(options);\n\n } catch (error) {\n this._onTransportReady.reject(error);\n throw new Error(\"Please provide a 'transport' layer. Default transport not set.\");\n }\n }\n\n protected onShutdownCallback: () => void | Promise<any> =\n () => Promise.resolve()\n\n protected onBeforeShutdownCallback: () => void | Promise<any> =\n () => Promise.resolve()\n}\n\nexport type RoomDefinitions = Record<string, RegisteredHandler | Type<Room>>;\n\nfunction isRegisteredHandler(value: RegisteredHandler | Type<Room>): value is RegisteredHandler {\n return value instanceof RegisteredHandler || (\n typeof(value) === \"object\" &&\n value !== null &&\n 'klass' in (value as object)\n );\n}\n\nexport function registerRoomDefinitions<T extends RoomDefinitions>(rooms: T): string[] {\n const roomNames: string[] = [];\n\n for (const [name, value] of Object.entries(rooms)) {\n if (isRegisteredHandler(value)) {\n value.name = name;\n matchMaker.addRoomType(value);\n\n } else {\n matchMaker.defineRoomType(name, value);\n }\n\n roomNames.push(name);\n }\n\n return roomNames;\n}\n\nexport function unregisterRoomDefinitions(roomNames: Iterable<string>) {\n for (const roomName of roomNames) {\n matchMaker.removeRoomType(roomName);\n }\n}\n\nexport type DefineServerOptions<\n T extends Record<string, RegisteredHandler>,\n R extends Router\n> = ServerOptions & {\n rooms: T,\n routes?: R,\n};\n\nexport function defineServer<\n T extends Record<string, RegisteredHandler>,\n R extends Router\n>(\n options: DefineServerOptions<T, R>,\n): Server<T, R> {\n const { rooms, routes, ...serverOptions } = options;\n\n if (isDevMode) {\n // In dev mode, the Vite plugin manages Server/matchMaker lifecycle.\n // Return a config-only object \u2014 no Server instance, no matchMaker.setup().\n return {\n options: serverOptions,\n router: routes,\n '~rooms': rooms,\n } as unknown as Server<T, R>;\n }\n\n const server = new Server<T, R>(serverOptions);\n server.router = routes;\n\n registerRoomDefinitions(rooms);\n\n return server;\n}\n\nexport function defineRoom<T extends Type<Room>>(\n roomKlass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n): RegisteredHandler<InstanceType<T>> {\n return new RegisteredHandler(roomKlass, defaultOptions) as unknown as RegisteredHandler<InstanceType<T>>;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { greet } from \"@colyseus/greeting-banner\";\nimport type express from 'express';\n\nimport { debugAndPrintError } from './Debug.ts';\nimport * as matchMaker from './MatchMaker.ts';\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler.ts';\n\nimport { type OnCreateOptions, Room } from './Room.ts';\nimport { Deferred, registerGracefulShutdown, dynamicImport, type Type } from './utils/Utils.ts';\n\nimport type { Presence } from \"./presence/Presence.ts\";\nimport { LocalPresence } from './presence/LocalPresence.ts';\nimport { LocalDriver } from './matchmaker/LocalDriver/LocalDriver.ts';\n\nimport { setTransport, Transport } from './Transport.ts';\nimport { logger, setLogger } from './Logger.ts';\nimport { setDevMode, isDevMode } from './utils/DevMode.ts';\nimport { type Router, bindRouterToTransport, createRouter } from './router/index.ts';\nimport { type SDKTypes as SharedSDKTypes } from '@colyseus/shared-types';\nimport { getDefaultRouter } from './router/default_routes.ts';\n\nexport type ServerOptions = {\n publicAddress?: string,\n presence?: Presence,\n driver?: matchMaker.MatchMakerDriver,\n transport?: Transport,\n gracefullyShutdown?: boolean,\n logger?: any;\n\n /**\n * Optional callback to execute before the server listens.\n * This is useful for example to connect into a database or other services before the server listens.\n */\n beforeListen?: () => Promise<void> | void,\n\n /**\n * Booted before `matchMaker.accept()`. Structural so `@colyseus/core` keeps\n * no runtime dep on `@colyseus/database` \u2014 any `{ boot(): Promise<void> }`\n * works. The optional `applyRouterDefaults` is invoked after boot with the\n * user's router so the database can contribute endpoints (e.g. auth routes).\n */\n database?: {\n boot(): Promise<void>;\n applyRouterDefaults?(router: Router): Router | Promise<Router>;\n },\n\n /**\n * Mount `@colyseus/auth` routes into the router. Pass an options object\n * (forwarded to `auth.endpoints(...)`) to wire it explicitly \u2014 useful when\n * `database` is not in use. `false` disables auto-mounting even if a\n * `database` is present and would have provided defaults.\n */\n auth?: false | {\n settings?: Record<string, any>;\n oauth?: boolean | { cookieSecret?: string };\n prefix?: string;\n },\n\n /**\n * Optional callback to configure Express routes.\n * When provided, the transport layer will initialize an Express-compatible app\n * and pass it to this callback for custom route configuration.\n *\n * For uWebSockets transport, this uses the uwebsockets-express module.\n */\n express?: (app: express.Application) => Promise<void> | void,\n\n /**\n * Custom function to determine which process should handle room creation.\n * Default: assign new rooms the process with least amount of rooms created\n */\n selectProcessIdToCreateRoom?: matchMaker.SelectProcessIdCallback;\n\n /**\n * Whether this process is running as a standalone match-maker or not. (default: false)\n * When enabled, this process will not spawn rooms and will only be responsible for matchmaking.\n */\n isStandaloneMatchMaker?: boolean; \n\n /**\n * If enabled, rooms are going to be restored in the server-side upon restart,\n * clients are going to automatically re-connect when server reboots.\n *\n * Beware of \"schema mismatch\" issues. When updating Schema structures and\n * reloading existing data, you may see \"schema mismatch\" errors in the\n * client-side.\n *\n * (This operation is costly and should not be used in a production\n * environment)\n */\n devMode?: boolean,\n\n /**\n * Display greeting message on server start.\n * Default: true\n */\n greet?: boolean,\n};\n\n/**\n * Exposed types for the client-side SDK.\n * Re-exported from @colyseus/shared-types with specific type constraints.\n */\nexport interface SDKTypes<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n> extends SharedSDKTypes<RoomTypes, Routes> {}\n\nexport class Server<\n RoomTypes extends Record<string, RegisteredHandler> = any,\n Routes extends Router = any\n> implements SDKTypes<RoomTypes, Routes> {\n '~rooms': RoomTypes;\n '~routes': Routes;\n\n public transport: Transport;\n public router: Routes;\n public options: ServerOptions;\n\n protected presence: Presence;\n protected driver: matchMaker.MatchMakerDriver;\n\n protected port: number | string;\n protected greet: boolean;\n\n protected _onTransportReady = new Deferred<Transport>();\n\n private _originalRoomOnMessage: typeof Room.prototype['_onMessage'] | null = null;\n\n // Implicit default for callers that omit explicit Server reference \u2014 e.g.\n // `playground()` reads `Server.current.router.endpoints` at request time.\n // Last-construction wins; multi-server setups should reference instances\n // explicitly.\n static current: Server<any, any> | undefined;\n\n constructor(options: ServerOptions = {}) {\n const {\n gracefullyShutdown = true,\n greet = true\n } = options;\n\n setDevMode(options.devMode === true);\n\n this.presence = options.presence || new LocalPresence();\n this.driver = options.driver || new LocalDriver();\n this.options = options;\n this.greet = greet;\n\n (Server as { current: Server<any, any> | undefined }).current = this as Server<any, any>;\n\n this.attach(options);\n\n matchMaker.setup(\n this.presence,\n this.driver,\n options.publicAddress,\n options.selectProcessIdToCreateRoom,\n );\n\n if (gracefullyShutdown) {\n registerGracefulShutdown((err) => this.gracefullyShutdown(true, err));\n }\n\n if (options.logger) {\n setLogger(options.logger);\n }\n }\n\n public async attach(options: ServerOptions) {\n this.transport = options.transport || await this.getDefaultTransport(options);\n // `options.express` runs in `listen()` after `database.boot()` so user\n // code reading `database.auth.settings` etc. finds services instantiated.\n this._onTransportReady.resolve(this.transport);\n }\n\n /**\n * Bind the server into the port specified.\n *\n * @param port - Port number or Unix socket path\n * @param hostname\n * @param backlog\n * @param listeningListener\n */\n public async listen(port: number | string, hostname?: string, backlog?: number, listeningListener?: Function) {\n const { beforeListen, database, express } = this.options;\n\n if (beforeListen) { await beforeListen(); }\n if (database) { await database.boot(); }\n\n await this._applyRouterDefaults();\n\n if (express) {\n await this._onTransportReady;\n if (this.transport.getExpressApp) {\n const expressApp = await this.transport.getExpressApp();\n await express(expressApp);\n }\n }\n\n //\n // if Colyseus Cloud is detected, use @colyseus/tools to listen\n //\n if (process.env.COLYSEUS_CLOUD !== undefined ) {\n if (typeof(hostname) === \"number\") {\n //\n // workaround, @colyseus/tools calls server.listen() again with the port as a string\n //\n hostname = undefined;\n\n } else {\n try {\n return (await dynamicImport(\"@colyseus/tools\")).listen(this);\n } catch (error) {\n const err = new Error(\"Please install @colyseus/tools to be able to host on Colyseus Cloud.\");\n err.cause = error;\n throw err;\n }\n }\n }\n\n //\n // otherwise, listen on the port directly\n //\n this.port = port;\n\n //\n // Make sure matchmaker is ready before accepting connections\n // (isDevMode: matchmaker may take extra milliseconds to restore the rooms)\n //\n await matchMaker.accept(this.options.isStandaloneMatchMaker);\n\n /**\n * Greetings!\n */\n if (this.greet) {\n greet();\n }\n\n // Wait for the transport to be ready\n await this._onTransportReady;\n\n return new Promise<void>((resolve, reject) => {\n // TODO: refactor me!\n // set transport globally, to be used by matchmaking route\n setTransport(this.transport);\n\n this.transport.listen(port, hostname, backlog, (err) => {\n if (this.transport.server) {\n this.transport.server.on('error', (err) => reject(err));\n }\n\n // default router is used if no router is provided\n if (!this.router) {\n this.router = getDefaultRouter() as unknown as Routes;\n\n } else {\n // make sure default routes are included\n // https://github.com/Bekacru/better-call/pull/67\n this.router = this.router.extend({ ...getDefaultRouter().endpoints }) as unknown as Routes;\n }\n\n bindRouterToTransport(this.transport, this.router, this.options.express !== undefined);\n\n if (listeningListener) {\n listeningListener(err);\n }\n\n if (err) {\n reject(err);\n\n } else {\n resolve();\n }\n });\n });\n }\n\n /**\n * Define a new type of room for matchmaking.\n *\n * @param name public room identifier for match-making.\n * @param roomClass Room class definition\n * @param defaultOptions default options for `onCreate`\n */\n public define<T extends Type<Room>>(\n roomClass: T,\n defaultOptions?: OnCreateOptions<T>,\n ): RegisteredHandler\n public define<T extends Type<Room>>(\n name: string,\n roomClass: T,\n defaultOptions?: OnCreateOptions<T>,\n ): RegisteredHandler\n public define<T extends Type<Room>>(\n nameOrHandler: string | T,\n handlerOrOptions: T | OnCreateOptions<T>,\n defaultOptions?: OnCreateOptions<T>,\n ): RegisteredHandler {\n const name = (typeof(nameOrHandler) === \"string\")\n ? nameOrHandler\n : nameOrHandler.name;\n\n const roomClass = (typeof(nameOrHandler) === \"string\")\n ? handlerOrOptions\n : nameOrHandler;\n\n const options = (typeof(nameOrHandler) === \"string\")\n ? defaultOptions\n : handlerOrOptions;\n\n return matchMaker.defineRoomType(name, roomClass, options);\n }\n\n /**\n * Remove a room definition from matchmaking.\n * This method does not destroy any room. It only dissallows matchmaking\n */\n public removeRoomType(name: string): void {\n matchMaker.removeRoomType(name);\n }\n\n public async gracefullyShutdown(exit: boolean = true, err?: Error) {\n if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {\n return;\n }\n\n try {\n // custom \"before shutdown\" method\n await this.onBeforeShutdownCallback();\n\n // this is going to lock all rooms and wait for them to be disposed\n await matchMaker.gracefullyShutdown();\n\n this.transport.shutdown();\n this.presence.shutdown();\n await this.driver.shutdown();\n\n // custom \"after shutdown\" method\n await this.onShutdownCallback();\n\n } catch (e) {\n debugAndPrintError(`error during shutdown: ${e}`);\n\n } finally {\n if (exit) {\n process.exit((err && !isDevMode) ? 1 : 0);\n }\n }\n }\n\n /**\n * Add simulated latency between client and server.\n * @param milliseconds round trip latency in milliseconds.\n */\n public simulateLatency(milliseconds: number) {\n if (milliseconds > 0) {\n logger.warn(`\uD83D\uDCF6\uFE0F\u2757 Colyseus latency simulation enabled \u2192 ${milliseconds}ms latency for round trip.`);\n } else {\n logger.warn(`\uD83D\uDCF6\uFE0F\u2757 Colyseus latency simulation disabled.`);\n }\n\n const halfwayMS = (milliseconds / 2);\n this.transport.simulateLatency(halfwayMS);\n\n if (this._originalRoomOnMessage == null) {\n this._originalRoomOnMessage = Room.prototype['_onMessage'];\n }\n\n const originalOnMessage = this._originalRoomOnMessage;\n\n Room.prototype['_onMessage'] = milliseconds <= Number.EPSILON ? originalOnMessage : function (this: Room, client, buffer) {\n // uWebSockets.js: duplicate buffer because it is cleared at native layer before the timeout.\n const cachedBuffer = Buffer.from(buffer);\n setTimeout(() => originalOnMessage.call(this, client, cachedBuffer), halfwayMS);\n };\n }\n\n /**\n * Register a callback that is going to be executed before the server shuts down.\n * @param callback\n */\n public onShutdown(callback: () => void | Promise<any>) {\n this.onShutdownCallback = callback;\n }\n\n public onBeforeShutdown(callback: () => void | Promise<any>) {\n this.onBeforeShutdownCallback = callback;\n }\n\n // Extend the user's router with framework-contributed endpoints. An explicit\n // `auth` option wins over the database's `applyRouterDefaults` so a non-DB\n // setup can still auto-mount @colyseus/auth, and a DB user can opt out.\n private async _applyRouterDefaults(): Promise<void> {\n const { auth, database } = this.options;\n const wantsAuth = auth !== undefined && auth !== false;\n const wantsDatabase = auth === undefined && !!database?.applyRouterDefaults;\n if (!wantsAuth && !wantsDatabase) { return; }\n\n // Boot an empty router if the user didn't pass `routes` \u2014 the framework's\n // default routes get layered on later in the `transport.listen()` callback.\n this.router ??= createRouter({}) as unknown as Routes;\n\n if (wantsAuth) {\n const authMod: any = await dynamicImport('@colyseus/auth').catch(() => undefined);\n const endpointsFn = authMod?.auth?.endpoints ?? authMod?.default?.auth?.endpoints;\n if (typeof endpointsFn === 'function') {\n this.router = (this.router as Router).extend(endpointsFn(auth)) as Routes;\n }\n } else {\n const updated = await database!.applyRouterDefaults!(this.router as Router);\n if (updated) { this.router = updated as Routes; }\n }\n }\n\n protected async getDefaultTransport(options: any): Promise<Transport> {\n try {\n const module = await dynamicImport('@colyseus/ws-transport');\n const WebSocketTransport = module.WebSocketTransport;\n return new WebSocketTransport(options);\n\n } catch (error) {\n this._onTransportReady.reject(error);\n throw new Error(\"Please provide a 'transport' layer. Default transport not set.\");\n }\n }\n\n protected onShutdownCallback: () => void | Promise<any> =\n () => Promise.resolve()\n\n protected onBeforeShutdownCallback: () => void | Promise<any> =\n () => Promise.resolve()\n}\n\nexport type RoomDefinitions = Record<string, RegisteredHandler | Type<Room>>;\n\nfunction isRegisteredHandler(value: RegisteredHandler | Type<Room>): value is RegisteredHandler {\n return value instanceof RegisteredHandler || (\n typeof(value) === \"object\" &&\n value !== null &&\n 'klass' in (value as object)\n );\n}\n\nexport function registerRoomDefinitions<T extends RoomDefinitions>(rooms: T): string[] {\n const roomNames: string[] = [];\n\n for (const [name, value] of Object.entries(rooms)) {\n if (isRegisteredHandler(value)) {\n value.name = name;\n matchMaker.addRoomType(value);\n\n } else {\n matchMaker.defineRoomType(name, value);\n }\n\n roomNames.push(name);\n }\n\n return roomNames;\n}\n\nexport function unregisterRoomDefinitions(roomNames: Iterable<string>) {\n for (const roomName of roomNames) {\n matchMaker.removeRoomType(roomName);\n }\n}\n\nexport type DefineServerOptions<\n T extends Record<string, RegisteredHandler>,\n R extends Router\n> = ServerOptions & {\n rooms: T,\n routes?: R,\n};\n\nexport function defineServer<\n T extends Record<string, RegisteredHandler>,\n R extends Router\n>(\n options: DefineServerOptions<T, R>,\n): Server<T, R> {\n const { rooms, routes, ...serverOptions } = options;\n\n if (isDevMode) {\n // In dev mode, the Vite plugin manages Server/matchMaker lifecycle.\n // Return a config-only object \u2014 no Server instance, no matchMaker.setup().\n return {\n options: serverOptions,\n router: routes,\n '~rooms': rooms,\n } as unknown as Server<T, R>;\n }\n\n const server = new Server<T, R>(serverOptions);\n server.router = routes;\n\n registerRoomDefinitions(rooms);\n\n return server;\n}\n\nexport function defineRoom<T extends Type<Room>>(\n roomKlass: T,\n defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n): RegisteredHandler<InstanceType<T>> {\n return new RegisteredHandler(roomKlass, defaultOptions) as unknown as RegisteredHandler<InstanceType<T>>;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["gracefullyShutdown", "greet", "err"]
7
7
  }
@@ -53,11 +53,47 @@ var ClientState = {
53
53
  CLOSED: 5
54
54
  };
55
55
  var ClientArray = class extends Array {
56
+ constructor() {
57
+ super(...arguments);
58
+ /**
59
+ * Secondary index for O(1) lookup by sessionId. Kept in sync by the
60
+ * mutating methods overridden below. Direct index assignment
61
+ * (`arr[i] = client`) and `arr.length = 0` bypass this index — use
62
+ * `push` / `splice` / `delete` / `pop` / `shift` / `unshift` instead.
63
+ */
64
+ this._byId = /* @__PURE__ */ new Map();
65
+ }
56
66
  getById(sessionId) {
57
- return this.find((client) => client.sessionId === sessionId);
67
+ return this._byId.get(sessionId);
58
68
  }
59
69
  delete(client) {
60
- return (0, import_Utils.spliceOne)(this, this.indexOf(client));
70
+ const removed = (0, import_Utils.spliceOne)(this, this.indexOf(client));
71
+ if (removed) this._byId.delete(client.sessionId);
72
+ return removed;
73
+ }
74
+ push(...items) {
75
+ for (let i = 0; i < items.length; i++) this._byId.set(items[i].sessionId, items[i]);
76
+ return super.push(...items);
77
+ }
78
+ pop() {
79
+ const removed = super.pop();
80
+ if (removed !== void 0) this._byId.delete(removed.sessionId);
81
+ return removed;
82
+ }
83
+ shift() {
84
+ const removed = super.shift();
85
+ if (removed !== void 0) this._byId.delete(removed.sessionId);
86
+ return removed;
87
+ }
88
+ unshift(...items) {
89
+ for (let i = 0; i < items.length; i++) this._byId.set(items[i].sessionId, items[i]);
90
+ return super.unshift(...items);
91
+ }
92
+ splice(start, deleteCount, ...items) {
93
+ const removed = deleteCount === void 0 ? super.splice(start) : super.splice(start, deleteCount, ...items);
94
+ for (let i = 0; i < removed.length; i++) this._byId.delete(removed[i].sessionId);
95
+ for (let i = 0; i < items.length; i++) this._byId.set(items[i].sessionId, items[i]);
96
+ return removed;
61
97
  }
62
98
  };
63
99
  async function connectClientToRoom(room, client, authContext, connectionOptions) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/Transport.ts"],
4
- "sourcesContent": ["import * as http from 'http';\nimport * as https from 'https';\n\nimport type { Router } from '@colyseus/better-call';\n\nimport { ErrorCode } from '@colyseus/shared-types';\nimport { StateView } from '@colyseus/schema';\n\nimport { EventEmitter } from 'events';\nimport { spliceOne } from './utils/Utils.ts';\nimport { ServerError } from './errors/ServerError.ts';\n\nimport type { Room } from './Room.ts';\n\nlet _transport: Transport | undefined;\nexport function setTransport(transport: Transport) { _transport = transport; }\nexport function getTransport() { return _transport; }\n\nexport abstract class Transport {\n public protocol?: string;\n public server?: http.Server | https.Server;\n\n public abstract listen(port?: number | string, hostname?: string, backlog?: number, listeningListener?: Function): this;\n public abstract shutdown(): void;\n\n public abstract simulateLatency(milliseconds: number): void;\n\n /**\n * Returns an Express-compatible application for HTTP route handling.\n * For uWebSockets transport, this uses the uwebsockets-express module.\n * This method is called lazily only when an express callback is provided in server options.\n */\n public getExpressApp?(): Promise<import('express').Application> | import('express').Application | undefined;\n\n /**\n * Binds a router to the transport.\n * Some transports may have a custom way to bind a router to the transport.\n * (uWebSocketsTransport)\n */\n public bindRouter?(router: Router): void;\n}\n\nexport type AuthContext = {\n token?: string,\n headers: Headers,\n ip: string | string[];\n // FIXME: each transport may have its own specific properties.\n // \"req\" only applies to WebSocketTransport.\n req?: any;\n};\n\nexport interface ISendOptions {\n afterNextPatch?: boolean;\n}\n\nexport const ClientState = {\n JOINING: 0,\n JOINED: 1,\n RECONNECTING: 2,\n RECONNECTED: 3,\n LEAVING: 4,\n CLOSED: 5\n} as const;\nexport type ClientState = (typeof ClientState)[keyof typeof ClientState];\n\n// Helper types to extract properties from the Client type parameter\ntype ExtractClientUserData<T> = T extends { userData: infer U } ? U : T;\ntype ExtractClientAuth<T> = T extends { auth: infer A } ? A : any;\ntype ExtractClientMessages<T> = T extends { messages: infer M } ? M : any;\n\n// Helper type to make message required when the message type demands it\nexport type MessageArgs<M, Options> =\n unknown extends M ? [message?: M, options?: Options] : // Handle 'any' type (backwards compatibility)\n [M] extends [never] ? [message?: M, options?: Options] :\n [M] extends [void] ? [message?: M, options?: Options] :\n [M] extends [undefined] ? [message?: M, options?: Options] :\n undefined extends M ? [message?: M, options?: Options] :\n [message: M, options?: Options];\n\n/**\n * The client instance from the server-side is responsible for the transport layer between the server and the client.\n * It should not be confused with the Client from the client-side SDK, as they have completely different purposes!\n * You operate on client instances from `this.clients`, `Room#onJoin()`, `Room#onLeave()` and `Room#onMessage()`.\n *\n * - This is the raw WebSocket connection coming from the `ws` package. There are more methods available which aren't\n * encouraged to use along with Colyseus.\n */\nexport interface Client<T extends { userData?: any, auth?: any, messages?: Record<string | number, any> } = any> {\n '~messages': ExtractClientMessages<T>;\n\n ref: EventEmitter;\n\n /**\n * @deprecated use `sessionId` instead.\n */\n id: string;\n\n /**\n * Unique id per session.\n */\n sessionId: string; // TODO: remove sessionId on version 1.0.0\n\n /**\n * Connection state\n */\n state: ClientState;\n\n /**\n * Optional: when using `@view()` decorator in your state properties, this will be the view instance for this client.\n */\n view?: StateView;\n\n /**\n * User-defined data can be attached to the Client instance through this variable.\n * - Can be used to store custom data about the client's connection. userData is not synchronized with the client,\n * and should be used only to keep player-specific with its connection.\n */\n userData?: ExtractClientUserData<T>;\n\n /**\n * auth data provided by your `onAuth`\n */\n auth?: ExtractClientAuth<T>;\n\n /**\n * Reconnection token used to re-join the room after onLeave + allowReconnection().\n *\n * IMPORTANT:\n * This is not the full reconnection token the client provides for the server.\n * The format provided by .reconnect() from the client-side must follow: \"${roomId}:${reconnectionToken}\"\n */\n reconnectionToken: string;\n\n // TODO: move these to ClientPrivate\n raw(data: Uint8Array | Buffer, options?: ISendOptions, cb?: (err?: Error) => void): void;\n enqueueRaw(data: Uint8Array | Buffer, options?: ISendOptions): void;\n\n /**\n * Send a type of message to the client. Messages are encoded with MsgPack and can hold any\n * JSON-serializable data structure.\n *\n * @param type String or Number identifier the client SDK will use to receive this message\n * @param message Message payload. (automatically encoded with msgpack.)\n * @param options\n */\n send<K extends keyof this['~messages']>(\n type: K,\n ...args: MessageArgs<this['~messages'][K], ISendOptions>\n ): void;\n\n /**\n * Send raw bytes to this specific client.\n *\n * @param type String or Number identifier the client SDK will use to receive this message\n * @param bytes Raw byte array payload\n * @param options\n */\n sendBytes(type: string | number, bytes: Buffer | Uint8Array, options?: ISendOptions): void;\n\n /**\n * Disconnect this client from the room.\n *\n * @param code Custom close code. Default value is 1000.\n * @param data\n * @see [Leave room](https://docs.colyseus.io/room#leave-room)\n */\n leave(code?: number, data?: string): void;\n\n /**\n * @deprecated Use .leave() instead.\n */\n close(code?: number, data?: string): void;\n\n /**\n * Triggers `onError` with specified code to the client-side.\n *\n * @param code\n * @param message\n */\n error(code: number, message?: string): void;\n}\n\n/**\n * Private properties of the Client instance.\n * Only accessible internally by the framework, should not be encouraged/auto-completed for the user.\n *\n * TODO: refactor this.\n * @private\n */\nexport interface ClientPrivate {\n readyState: number; // TODO: remove readyState on version 1.0.0. Use only \"state\" instead.\n _enqueuedMessages?: any[];\n _afterNextPatchQueue: Array<[string | number | Client, ArrayLike<any>]>;\n _joinedAt: number; // \"elapsedTime\" when the client joined the room.\n\n /**\n * Used for rate limiting via maxMessagesPerSecond.\n */\n _numMessagesLastSecond?: number;\n _lastMessageTime?: number;\n}\n\nexport class ClientArray<C extends Client = Client> extends Array<C> {\n public getById(sessionId: string): C | undefined {\n return this.find((client) => client.sessionId === sessionId);\n }\n\n public delete(client: C): boolean {\n return spliceOne(this, this.indexOf(client));\n }\n}\n\n/**\n * Shared internal method to connect a Client into a Room.\n * Validates seat reservation and joins the client to the room.\n *\n * @remarks\n * **\u26A0\uFE0F This is an internal API and not intended for end-user use.**\n *\n * @internal\n */\nexport async function connectClientToRoom(\n room: Room | undefined,\n client: Client & ClientPrivate,\n authContext: AuthContext,\n connectionOptions: {\n reconnectionToken?: string;\n skipHandshake?: boolean;\n },\n): Promise<void> {\n if (!room || !room.hasReservedSeat(client.sessionId, connectionOptions.reconnectionToken)) {\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, 'seat reservation expired.');\n }\n\n await room['_onJoin'](client, authContext, connectionOptions);\n}"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAAsB;AACtB,YAAuB;AAIvB,0BAA0B;AAC1B,oBAA0B;AAE1B,oBAA6B;AAC7B,mBAA0B;AAC1B,yBAA4B;AAI5B,IAAI;AACG,SAAS,aAAa,WAAsB;AAAE,eAAa;AAAW;AACtE,SAAS,eAAe;AAAE,SAAO;AAAY;AAE7C,IAAe,YAAf,MAAyB;AAsBhC;AAeO,IAAM,cAAc;AAAA,EACzB,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,aAAa;AAAA,EACb,SAAS;AAAA,EACT,QAAQ;AACV;AA4IO,IAAM,cAAN,cAAqD,MAAS;AAAA,EAC5D,QAAQ,WAAkC;AAC/C,WAAO,KAAK,KAAK,CAAC,WAAW,OAAO,cAAc,SAAS;AAAA,EAC7D;AAAA,EAEO,OAAO,QAAoB;AAChC,eAAO,wBAAU,MAAM,KAAK,QAAQ,MAAM,CAAC;AAAA,EAC7C;AACF;AAWA,eAAsB,oBACpB,MACA,QACA,aACA,mBAIe;AACf,MAAI,CAAC,QAAQ,CAAC,KAAK,gBAAgB,OAAO,WAAW,kBAAkB,iBAAiB,GAAG;AACzF,UAAM,IAAI,+BAAY,8BAAU,mBAAmB,2BAA2B;AAAA,EAChF;AAEA,QAAM,KAAK,SAAS,EAAE,QAAQ,aAAa,iBAAiB;AAC9D;",
4
+ "sourcesContent": ["import * as http from 'http';\nimport * as https from 'https';\n\nimport type { Router } from '@colyseus/better-call';\n\nimport { ErrorCode } from '@colyseus/shared-types';\nimport { StateView } from '@colyseus/schema';\nimport type { InputDecoder } from '@colyseus/schema/input';\n\nimport { EventEmitter } from 'events';\nimport { spliceOne } from './utils/Utils.ts';\nimport { ServerError } from './errors/ServerError.ts';\n\nimport type { Room } from './Room.ts';\n\nlet _transport: Transport | undefined;\nexport function setTransport(transport: Transport) { _transport = transport; }\nexport function getTransport() { return _transport; }\n\nexport abstract class Transport {\n public protocol?: string;\n public server?: http.Server | https.Server;\n\n public abstract listen(port?: number | string, hostname?: string, backlog?: number, listeningListener?: Function): this;\n public abstract shutdown(): void;\n\n public abstract simulateLatency(milliseconds: number): void;\n\n /**\n * Returns an Express-compatible application for HTTP route handling.\n * For uWebSockets transport, this uses the uwebsockets-express module.\n * This method is called lazily only when an express callback is provided in server options.\n */\n public getExpressApp?(): Promise<import('express').Application> | import('express').Application | undefined;\n\n /**\n * Binds a router to the transport.\n * Some transports may have a custom way to bind a router to the transport.\n * (uWebSocketsTransport)\n */\n public bindRouter?(router: Router): void;\n}\n\nexport type AuthContext = {\n token?: string,\n headers: Headers,\n ip: string | string[];\n // FIXME: each transport may have its own specific properties.\n // \"req\" only applies to WebSocketTransport.\n req?: any;\n};\n\nexport interface ISendOptions {\n afterNextPatch?: boolean;\n}\n\nexport const ClientState = {\n JOINING: 0,\n JOINED: 1,\n RECONNECTING: 2,\n RECONNECTED: 3,\n LEAVING: 4,\n CLOSED: 5\n} as const;\nexport type ClientState = (typeof ClientState)[keyof typeof ClientState];\n\n// Helper types to extract properties from the Client type parameter\ntype ExtractClientUserData<T> = T extends { userData: infer U } ? U : T;\ntype ExtractClientAuth<T> = T extends { auth: infer A } ? A : any;\ntype ExtractClientMessages<T> = T extends { messages: infer M } ? M : any;\n\n// Helper type to make message required when the message type demands it\nexport type MessageArgs<M, Options> =\n unknown extends M ? [message?: M, options?: Options] : // Handle 'any' type (backwards compatibility)\n [M] extends [never] ? [message?: M, options?: Options] :\n [M] extends [void] ? [message?: M, options?: Options] :\n [M] extends [undefined] ? [message?: M, options?: Options] :\n undefined extends M ? [message?: M, options?: Options] :\n [message: M, options?: Options];\n\n/**\n * The client instance from the server-side is responsible for the transport layer between the server and the client.\n * It should not be confused with the Client from the client-side SDK, as they have completely different purposes!\n * You operate on client instances from `this.clients`, `Room#onJoin()`, `Room#onLeave()` and `Room#onMessage()`.\n *\n * - This is the raw WebSocket connection coming from the `ws` package. There are more methods available which aren't\n * encouraged to use along with Colyseus.\n */\nexport interface Client<T extends { userData?: any, auth?: any, messages?: Record<string | number, any> } = any> {\n '~messages': ExtractClientMessages<T>;\n\n ref: EventEmitter;\n\n /**\n * Unique id per session.\n */\n sessionId: string;\n\n /**\n * Connection state\n */\n state: ClientState;\n\n /**\n * Optional: when using `@view()` decorator in your state properties, this will be the view instance for this client.\n */\n view?: StateView;\n\n /**\n * User-defined data can be attached to the Client instance through this variable.\n * - Can be used to store custom data about the client's connection. userData is not synchronized with the client,\n * and should be used only to keep player-specific with its connection.\n */\n userData?: ExtractClientUserData<T>;\n\n /**\n * auth data provided by your `onAuth`\n */\n auth?: ExtractClientAuth<T>;\n\n /**\n * Reconnection token used to re-join the room after onLeave + allowReconnection().\n *\n * IMPORTANT:\n * This is not the full reconnection token the client provides for the server.\n * The format provided by .reconnect() from the client-side must follow: \"${roomId}:${reconnectionToken}\"\n */\n reconnectionToken: string;\n\n // TODO: move these to ClientPrivate\n raw(data: Uint8Array | Buffer, options?: ISendOptions, cb?: (err?: Error) => void): void;\n enqueueRaw(data: Uint8Array | Buffer, options?: ISendOptions): void;\n\n /**\n * Send a type of message to the client. Messages are encoded with MsgPack and can hold any\n * JSON-serializable data structure.\n *\n * @param type String or Number identifier the client SDK will use to receive this message\n * @param message Message payload. (automatically encoded with msgpack.)\n * @param options\n */\n send<K extends keyof this['~messages']>(\n type: K,\n ...args: MessageArgs<this['~messages'][K], ISendOptions>\n ): void;\n\n /**\n * Send raw bytes to this specific client.\n *\n * @param type String or Number identifier the client SDK will use to receive this message\n * @param bytes Raw byte array payload\n * @param options\n */\n sendBytes(type: string | number, bytes: Buffer | Uint8Array, options?: ISendOptions): void;\n\n /**\n * Disconnect this client from the room.\n *\n * @param code Custom close code. Default value is 1000.\n * @param data\n * @see [Leave room](https://docs.colyseus.io/room#leave-room)\n */\n leave(code?: number, data?: string): void;\n\n /**\n * @deprecated Use .leave() instead.\n */\n close(code?: number, data?: string): void;\n\n /**\n * Triggers `onError` with specified code to the client-side.\n *\n * @param code\n * @param message\n */\n error(code: number, message?: string): void;\n}\n\n/**\n * Private properties of the Client instance.\n * Only accessible internally by the framework, should not be encouraged/auto-completed for the user.\n *\n * TODO: refactor this.\n * @private\n */\nexport interface ClientPrivate {\n readyState: number; // TODO: remove readyState on version 1.0.0. Use only \"state\" instead.\n _enqueuedMessages?: any[];\n _afterNextPatchQueue: Array<[string | number | Client, ArrayLike<any>]>;\n _joinedAt: number; // \"elapsedTime\" when the client joined the room.\n\n /**\n * Used for rate limiting via maxMessagesPerSecond.\n */\n _numMessagesLastSecond?: number;\n _lastMessageTime?: number;\n\n /**\n * Per-client input Schema instance, allocated on join when the Room\n * declares `input`. Mutated in-place by {@link _inputDecoder} on each\n * incoming ROOM_INPUT_* packet.\n *\n * Typed loosely (`any`) so duplicate `@colyseus/schema` installs don't\n * trigger type-identity errors against user-defined input classes.\n */\n _input?: any;\n _inputDecoder?: InputDecoder;\n\n /**\n * Per-client buffer of cloned input snapshots, allocated on join when\n * `Room.inputOptions.bufferMaxSize > 0`. Populated on each decoded frame.\n */\n _inputBuffer?: import('./input/InputBuffer.ts').InputBufferImpl;\n\n /**\n * Cached per-client accessor returned by `room.input(sessionId)`. Built\n * once at join (when the Room called `defineInput()`), so the public API\n * call is a Map lookup + property read with no per-call allocation.\n */\n _inputAccessor?: import('./input/InputBuffer.ts').InputAccessor;\n\n /**\n * Used for rate limiting ROOM_INPUT_* packets via maxInputsPerSecond,\n * independent of maxMessagesPerSecond.\n */\n _numInputsLastSecond?: number;\n _lastInputTime?: number;\n}\n\nexport class ClientArray<C extends Client = Client> extends Array<C> {\n /**\n * Secondary index for O(1) lookup by sessionId. Kept in sync by the\n * mutating methods overridden below. Direct index assignment\n * (`arr[i] = client`) and `arr.length = 0` bypass this index \u2014 use\n * `push` / `splice` / `delete` / `pop` / `shift` / `unshift` instead.\n */\n private _byId: Map<string, C> = new Map();\n\n public getById(sessionId: string): C | undefined {\n return this._byId.get(sessionId);\n }\n\n public delete(client: C): boolean {\n const removed = spliceOne(this, this.indexOf(client));\n if (removed) this._byId.delete(client.sessionId);\n return removed;\n }\n\n public push(...items: C[]): number {\n for (let i = 0; i < items.length; i++) this._byId.set(items[i].sessionId, items[i]);\n return super.push(...items);\n }\n\n public pop(): C | undefined {\n const removed = super.pop();\n if (removed !== undefined) this._byId.delete(removed.sessionId);\n return removed;\n }\n\n public shift(): C | undefined {\n const removed = super.shift();\n if (removed !== undefined) this._byId.delete(removed.sessionId);\n return removed;\n }\n\n public unshift(...items: C[]): number {\n for (let i = 0; i < items.length; i++) this._byId.set(items[i].sessionId, items[i]);\n return super.unshift(...items);\n }\n\n public splice(start: number, deleteCount?: number, ...items: C[]): C[] {\n const removed = (deleteCount === undefined)\n ? super.splice(start)\n : super.splice(start, deleteCount, ...items);\n for (let i = 0; i < removed.length; i++) this._byId.delete(removed[i].sessionId);\n for (let i = 0; i < items.length; i++) this._byId.set(items[i].sessionId, items[i]);\n return removed;\n }\n}\n\n/**\n * Shared internal method to connect a Client into a Room.\n * Validates seat reservation and joins the client to the room.\n *\n * @remarks\n * **\u26A0\uFE0F This is an internal API and not intended for end-user use.**\n *\n * @internal\n */\nexport async function connectClientToRoom(\n room: Room | undefined,\n client: Client & ClientPrivate,\n authContext: AuthContext,\n connectionOptions: {\n reconnectionToken?: string;\n skipHandshake?: boolean;\n },\n): Promise<void> {\n if (!room || !room.hasReservedSeat(client.sessionId, connectionOptions.reconnectionToken)) {\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, 'seat reservation expired.');\n }\n\n await room['_onJoin'](client, authContext, connectionOptions);\n}"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAAsB;AACtB,YAAuB;AAIvB,0BAA0B;AAC1B,oBAA0B;AAG1B,oBAA6B;AAC7B,mBAA0B;AAC1B,yBAA4B;AAI5B,IAAI;AACG,SAAS,aAAa,WAAsB;AAAE,eAAa;AAAW;AACtE,SAAS,eAAe;AAAE,SAAO;AAAY;AAE7C,IAAe,YAAf,MAAyB;AAsBhC;AAeO,IAAM,cAAc;AAAA,EACzB,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,aAAa;AAAA,EACb,SAAS;AAAA,EACT,QAAQ;AACV;AAsKO,IAAM,cAAN,cAAqD,MAAS;AAAA,EAA9D;AAAA;AAOL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAQ,QAAwB,oBAAI,IAAI;AAAA;AAAA,EAEjC,QAAQ,WAAkC;AAC/C,WAAO,KAAK,MAAM,IAAI,SAAS;AAAA,EACjC;AAAA,EAEO,OAAO,QAAoB;AAChC,UAAM,cAAU,wBAAU,MAAM,KAAK,QAAQ,MAAM,CAAC;AACpD,QAAI,QAAS,MAAK,MAAM,OAAO,OAAO,SAAS;AAC/C,WAAO;AAAA,EACT;AAAA,EAEO,QAAQ,OAAoB;AACjC,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,MAAK,MAAM,IAAI,MAAM,CAAC,EAAE,WAAW,MAAM,CAAC,CAAC;AAClF,WAAO,MAAM,KAAK,GAAG,KAAK;AAAA,EAC5B;AAAA,EAEO,MAAqB;AAC1B,UAAM,UAAU,MAAM,IAAI;AAC1B,QAAI,YAAY,OAAW,MAAK,MAAM,OAAO,QAAQ,SAAS;AAC9D,WAAO;AAAA,EACT;AAAA,EAEO,QAAuB;AAC5B,UAAM,UAAU,MAAM,MAAM;AAC5B,QAAI,YAAY,OAAW,MAAK,MAAM,OAAO,QAAQ,SAAS;AAC9D,WAAO;AAAA,EACT;AAAA,EAEO,WAAW,OAAoB;AACpC,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,MAAK,MAAM,IAAI,MAAM,CAAC,EAAE,WAAW,MAAM,CAAC,CAAC;AAClF,WAAO,MAAM,QAAQ,GAAG,KAAK;AAAA,EAC/B;AAAA,EAEO,OAAO,OAAe,gBAAyB,OAAiB;AACrE,UAAM,UAAW,gBAAgB,SAC7B,MAAM,OAAO,KAAK,IAClB,MAAM,OAAO,OAAO,aAAa,GAAG,KAAK;AAC7C,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,IAAK,MAAK,MAAM,OAAO,QAAQ,CAAC,EAAE,SAAS;AAC/E,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,MAAK,MAAM,IAAI,MAAM,CAAC,EAAE,WAAW,MAAM,CAAC,CAAC;AAClF,WAAO;AAAA,EACT;AACF;AAWA,eAAsB,oBACpB,MACA,QACA,aACA,mBAIe;AACf,MAAI,CAAC,QAAQ,CAAC,KAAK,gBAAgB,OAAO,WAAW,kBAAkB,iBAAiB,GAAG;AACzF,UAAM,IAAI,+BAAY,8BAAU,mBAAmB,2BAA2B;AAAA,EAChF;AAEA,QAAM,KAAK,SAAS,EAAE,QAAQ,aAAa,iBAAiB;AAC9D;",
6
6
  "names": []
7
7
  }
@@ -2,6 +2,7 @@ import * as http from 'http';
2
2
  import * as https from 'https';
3
3
  import type { Router } from '@colyseus/better-call';
4
4
  import { StateView } from '@colyseus/schema';
5
+ import type { InputDecoder } from '@colyseus/schema/input';
5
6
  import { EventEmitter } from 'events';
6
7
  import type { Room } from './Room.ts';
7
8
  export declare function setTransport(transport: Transport): void;
@@ -77,10 +78,6 @@ export interface Client<T extends {
77
78
  } = any> {
78
79
  '~messages': ExtractClientMessages<T>;
79
80
  ref: EventEmitter;
80
- /**
81
- * @deprecated use `sessionId` instead.
82
- */
83
- id: string;
84
81
  /**
85
82
  * Unique id per session.
86
83
  */
@@ -167,10 +164,49 @@ export interface ClientPrivate {
167
164
  */
168
165
  _numMessagesLastSecond?: number;
169
166
  _lastMessageTime?: number;
167
+ /**
168
+ * Per-client input Schema instance, allocated on join when the Room
169
+ * declares `input`. Mutated in-place by {@link _inputDecoder} on each
170
+ * incoming ROOM_INPUT_* packet.
171
+ *
172
+ * Typed loosely (`any`) so duplicate `@colyseus/schema` installs don't
173
+ * trigger type-identity errors against user-defined input classes.
174
+ */
175
+ _input?: any;
176
+ _inputDecoder?: InputDecoder;
177
+ /**
178
+ * Per-client buffer of cloned input snapshots, allocated on join when
179
+ * `Room.inputOptions.bufferMaxSize > 0`. Populated on each decoded frame.
180
+ */
181
+ _inputBuffer?: import('./input/InputBuffer.ts').InputBufferImpl;
182
+ /**
183
+ * Cached per-client accessor returned by `room.input(sessionId)`. Built
184
+ * once at join (when the Room called `defineInput()`), so the public API
185
+ * call is a Map lookup + property read with no per-call allocation.
186
+ */
187
+ _inputAccessor?: import('./input/InputBuffer.ts').InputAccessor;
188
+ /**
189
+ * Used for rate limiting ROOM_INPUT_* packets via maxInputsPerSecond,
190
+ * independent of maxMessagesPerSecond.
191
+ */
192
+ _numInputsLastSecond?: number;
193
+ _lastInputTime?: number;
170
194
  }
171
195
  export declare class ClientArray<C extends Client = Client> extends Array<C> {
196
+ /**
197
+ * Secondary index for O(1) lookup by sessionId. Kept in sync by the
198
+ * mutating methods overridden below. Direct index assignment
199
+ * (`arr[i] = client`) and `arr.length = 0` bypass this index — use
200
+ * `push` / `splice` / `delete` / `pop` / `shift` / `unshift` instead.
201
+ */
202
+ private _byId;
172
203
  getById(sessionId: string): C | undefined;
173
204
  delete(client: C): boolean;
205
+ push(...items: C[]): number;
206
+ pop(): C | undefined;
207
+ shift(): C | undefined;
208
+ unshift(...items: C[]): number;
209
+ splice(start: number, deleteCount?: number, ...items: C[]): C[];
174
210
  }
175
211
  /**
176
212
  * Shared internal method to connect a Client into a Room.
@@ -24,11 +24,47 @@ var ClientState = {
24
24
  CLOSED: 5
25
25
  };
26
26
  var ClientArray = class extends Array {
27
+ constructor() {
28
+ super(...arguments);
29
+ /**
30
+ * Secondary index for O(1) lookup by sessionId. Kept in sync by the
31
+ * mutating methods overridden below. Direct index assignment
32
+ * (`arr[i] = client`) and `arr.length = 0` bypass this index — use
33
+ * `push` / `splice` / `delete` / `pop` / `shift` / `unshift` instead.
34
+ */
35
+ this._byId = /* @__PURE__ */ new Map();
36
+ }
27
37
  getById(sessionId) {
28
- return this.find((client) => client.sessionId === sessionId);
38
+ return this._byId.get(sessionId);
29
39
  }
30
40
  delete(client) {
31
- return spliceOne(this, this.indexOf(client));
41
+ const removed = spliceOne(this, this.indexOf(client));
42
+ if (removed) this._byId.delete(client.sessionId);
43
+ return removed;
44
+ }
45
+ push(...items) {
46
+ for (let i = 0; i < items.length; i++) this._byId.set(items[i].sessionId, items[i]);
47
+ return super.push(...items);
48
+ }
49
+ pop() {
50
+ const removed = super.pop();
51
+ if (removed !== void 0) this._byId.delete(removed.sessionId);
52
+ return removed;
53
+ }
54
+ shift() {
55
+ const removed = super.shift();
56
+ if (removed !== void 0) this._byId.delete(removed.sessionId);
57
+ return removed;
58
+ }
59
+ unshift(...items) {
60
+ for (let i = 0; i < items.length; i++) this._byId.set(items[i].sessionId, items[i]);
61
+ return super.unshift(...items);
62
+ }
63
+ splice(start, deleteCount, ...items) {
64
+ const removed = deleteCount === void 0 ? super.splice(start) : super.splice(start, deleteCount, ...items);
65
+ for (let i = 0; i < removed.length; i++) this._byId.delete(removed[i].sessionId);
66
+ for (let i = 0; i < items.length; i++) this._byId.set(items[i].sessionId, items[i]);
67
+ return removed;
32
68
  }
33
69
  };
34
70
  async function connectClientToRoom(room, client, authContext, connectionOptions) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/Transport.ts"],
4
- "sourcesContent": ["import * as http from 'http';\nimport * as https from 'https';\n\nimport type { Router } from '@colyseus/better-call';\n\nimport { ErrorCode } from '@colyseus/shared-types';\nimport { StateView } from '@colyseus/schema';\n\nimport { EventEmitter } from 'events';\nimport { spliceOne } from './utils/Utils.ts';\nimport { ServerError } from './errors/ServerError.ts';\n\nimport type { Room } from './Room.ts';\n\nlet _transport: Transport | undefined;\nexport function setTransport(transport: Transport) { _transport = transport; }\nexport function getTransport() { return _transport; }\n\nexport abstract class Transport {\n public protocol?: string;\n public server?: http.Server | https.Server;\n\n public abstract listen(port?: number | string, hostname?: string, backlog?: number, listeningListener?: Function): this;\n public abstract shutdown(): void;\n\n public abstract simulateLatency(milliseconds: number): void;\n\n /**\n * Returns an Express-compatible application for HTTP route handling.\n * For uWebSockets transport, this uses the uwebsockets-express module.\n * This method is called lazily only when an express callback is provided in server options.\n */\n public getExpressApp?(): Promise<import('express').Application> | import('express').Application | undefined;\n\n /**\n * Binds a router to the transport.\n * Some transports may have a custom way to bind a router to the transport.\n * (uWebSocketsTransport)\n */\n public bindRouter?(router: Router): void;\n}\n\nexport type AuthContext = {\n token?: string,\n headers: Headers,\n ip: string | string[];\n // FIXME: each transport may have its own specific properties.\n // \"req\" only applies to WebSocketTransport.\n req?: any;\n};\n\nexport interface ISendOptions {\n afterNextPatch?: boolean;\n}\n\nexport const ClientState = {\n JOINING: 0,\n JOINED: 1,\n RECONNECTING: 2,\n RECONNECTED: 3,\n LEAVING: 4,\n CLOSED: 5\n} as const;\nexport type ClientState = (typeof ClientState)[keyof typeof ClientState];\n\n// Helper types to extract properties from the Client type parameter\ntype ExtractClientUserData<T> = T extends { userData: infer U } ? U : T;\ntype ExtractClientAuth<T> = T extends { auth: infer A } ? A : any;\ntype ExtractClientMessages<T> = T extends { messages: infer M } ? M : any;\n\n// Helper type to make message required when the message type demands it\nexport type MessageArgs<M, Options> =\n unknown extends M ? [message?: M, options?: Options] : // Handle 'any' type (backwards compatibility)\n [M] extends [never] ? [message?: M, options?: Options] :\n [M] extends [void] ? [message?: M, options?: Options] :\n [M] extends [undefined] ? [message?: M, options?: Options] :\n undefined extends M ? [message?: M, options?: Options] :\n [message: M, options?: Options];\n\n/**\n * The client instance from the server-side is responsible for the transport layer between the server and the client.\n * It should not be confused with the Client from the client-side SDK, as they have completely different purposes!\n * You operate on client instances from `this.clients`, `Room#onJoin()`, `Room#onLeave()` and `Room#onMessage()`.\n *\n * - This is the raw WebSocket connection coming from the `ws` package. There are more methods available which aren't\n * encouraged to use along with Colyseus.\n */\nexport interface Client<T extends { userData?: any, auth?: any, messages?: Record<string | number, any> } = any> {\n '~messages': ExtractClientMessages<T>;\n\n ref: EventEmitter;\n\n /**\n * @deprecated use `sessionId` instead.\n */\n id: string;\n\n /**\n * Unique id per session.\n */\n sessionId: string; // TODO: remove sessionId on version 1.0.0\n\n /**\n * Connection state\n */\n state: ClientState;\n\n /**\n * Optional: when using `@view()` decorator in your state properties, this will be the view instance for this client.\n */\n view?: StateView;\n\n /**\n * User-defined data can be attached to the Client instance through this variable.\n * - Can be used to store custom data about the client's connection. userData is not synchronized with the client,\n * and should be used only to keep player-specific with its connection.\n */\n userData?: ExtractClientUserData<T>;\n\n /**\n * auth data provided by your `onAuth`\n */\n auth?: ExtractClientAuth<T>;\n\n /**\n * Reconnection token used to re-join the room after onLeave + allowReconnection().\n *\n * IMPORTANT:\n * This is not the full reconnection token the client provides for the server.\n * The format provided by .reconnect() from the client-side must follow: \"${roomId}:${reconnectionToken}\"\n */\n reconnectionToken: string;\n\n // TODO: move these to ClientPrivate\n raw(data: Uint8Array | Buffer, options?: ISendOptions, cb?: (err?: Error) => void): void;\n enqueueRaw(data: Uint8Array | Buffer, options?: ISendOptions): void;\n\n /**\n * Send a type of message to the client. Messages are encoded with MsgPack and can hold any\n * JSON-serializable data structure.\n *\n * @param type String or Number identifier the client SDK will use to receive this message\n * @param message Message payload. (automatically encoded with msgpack.)\n * @param options\n */\n send<K extends keyof this['~messages']>(\n type: K,\n ...args: MessageArgs<this['~messages'][K], ISendOptions>\n ): void;\n\n /**\n * Send raw bytes to this specific client.\n *\n * @param type String or Number identifier the client SDK will use to receive this message\n * @param bytes Raw byte array payload\n * @param options\n */\n sendBytes(type: string | number, bytes: Buffer | Uint8Array, options?: ISendOptions): void;\n\n /**\n * Disconnect this client from the room.\n *\n * @param code Custom close code. Default value is 1000.\n * @param data\n * @see [Leave room](https://docs.colyseus.io/room#leave-room)\n */\n leave(code?: number, data?: string): void;\n\n /**\n * @deprecated Use .leave() instead.\n */\n close(code?: number, data?: string): void;\n\n /**\n * Triggers `onError` with specified code to the client-side.\n *\n * @param code\n * @param message\n */\n error(code: number, message?: string): void;\n}\n\n/**\n * Private properties of the Client instance.\n * Only accessible internally by the framework, should not be encouraged/auto-completed for the user.\n *\n * TODO: refactor this.\n * @private\n */\nexport interface ClientPrivate {\n readyState: number; // TODO: remove readyState on version 1.0.0. Use only \"state\" instead.\n _enqueuedMessages?: any[];\n _afterNextPatchQueue: Array<[string | number | Client, ArrayLike<any>]>;\n _joinedAt: number; // \"elapsedTime\" when the client joined the room.\n\n /**\n * Used for rate limiting via maxMessagesPerSecond.\n */\n _numMessagesLastSecond?: number;\n _lastMessageTime?: number;\n}\n\nexport class ClientArray<C extends Client = Client> extends Array<C> {\n public getById(sessionId: string): C | undefined {\n return this.find((client) => client.sessionId === sessionId);\n }\n\n public delete(client: C): boolean {\n return spliceOne(this, this.indexOf(client));\n }\n}\n\n/**\n * Shared internal method to connect a Client into a Room.\n * Validates seat reservation and joins the client to the room.\n *\n * @remarks\n * **\u26A0\uFE0F This is an internal API and not intended for end-user use.**\n *\n * @internal\n */\nexport async function connectClientToRoom(\n room: Room | undefined,\n client: Client & ClientPrivate,\n authContext: AuthContext,\n connectionOptions: {\n reconnectionToken?: string;\n skipHandshake?: boolean;\n },\n): Promise<void> {\n if (!room || !room.hasReservedSeat(client.sessionId, connectionOptions.reconnectionToken)) {\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, 'seat reservation expired.');\n }\n\n await room['_onJoin'](client, authContext, connectionOptions);\n}"],
5
- "mappings": ";AAAA,OAAsB;AACtB,OAAuB;AAIvB,SAAS,iBAAiB;AAC1B,OAA0B;AAE1B,OAA6B;AAC7B,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAI5B,IAAI;AACG,SAAS,aAAa,WAAsB;AAAE,eAAa;AAAW;AACtE,SAAS,eAAe;AAAE,SAAO;AAAY;AAE7C,IAAe,YAAf,MAAyB;AAsBhC;AAeO,IAAM,cAAc;AAAA,EACzB,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,aAAa;AAAA,EACb,SAAS;AAAA,EACT,QAAQ;AACV;AA4IO,IAAM,cAAN,cAAqD,MAAS;AAAA,EAC5D,QAAQ,WAAkC;AAC/C,WAAO,KAAK,KAAK,CAAC,WAAW,OAAO,cAAc,SAAS;AAAA,EAC7D;AAAA,EAEO,OAAO,QAAoB;AAChC,WAAO,UAAU,MAAM,KAAK,QAAQ,MAAM,CAAC;AAAA,EAC7C;AACF;AAWA,eAAsB,oBACpB,MACA,QACA,aACA,mBAIe;AACf,MAAI,CAAC,QAAQ,CAAC,KAAK,gBAAgB,OAAO,WAAW,kBAAkB,iBAAiB,GAAG;AACzF,UAAM,IAAI,YAAY,UAAU,mBAAmB,2BAA2B;AAAA,EAChF;AAEA,QAAM,KAAK,SAAS,EAAE,QAAQ,aAAa,iBAAiB;AAC9D;",
4
+ "sourcesContent": ["import * as http from 'http';\nimport * as https from 'https';\n\nimport type { Router } from '@colyseus/better-call';\n\nimport { ErrorCode } from '@colyseus/shared-types';\nimport { StateView } from '@colyseus/schema';\nimport type { InputDecoder } from '@colyseus/schema/input';\n\nimport { EventEmitter } from 'events';\nimport { spliceOne } from './utils/Utils.ts';\nimport { ServerError } from './errors/ServerError.ts';\n\nimport type { Room } from './Room.ts';\n\nlet _transport: Transport | undefined;\nexport function setTransport(transport: Transport) { _transport = transport; }\nexport function getTransport() { return _transport; }\n\nexport abstract class Transport {\n public protocol?: string;\n public server?: http.Server | https.Server;\n\n public abstract listen(port?: number | string, hostname?: string, backlog?: number, listeningListener?: Function): this;\n public abstract shutdown(): void;\n\n public abstract simulateLatency(milliseconds: number): void;\n\n /**\n * Returns an Express-compatible application for HTTP route handling.\n * For uWebSockets transport, this uses the uwebsockets-express module.\n * This method is called lazily only when an express callback is provided in server options.\n */\n public getExpressApp?(): Promise<import('express').Application> | import('express').Application | undefined;\n\n /**\n * Binds a router to the transport.\n * Some transports may have a custom way to bind a router to the transport.\n * (uWebSocketsTransport)\n */\n public bindRouter?(router: Router): void;\n}\n\nexport type AuthContext = {\n token?: string,\n headers: Headers,\n ip: string | string[];\n // FIXME: each transport may have its own specific properties.\n // \"req\" only applies to WebSocketTransport.\n req?: any;\n};\n\nexport interface ISendOptions {\n afterNextPatch?: boolean;\n}\n\nexport const ClientState = {\n JOINING: 0,\n JOINED: 1,\n RECONNECTING: 2,\n RECONNECTED: 3,\n LEAVING: 4,\n CLOSED: 5\n} as const;\nexport type ClientState = (typeof ClientState)[keyof typeof ClientState];\n\n// Helper types to extract properties from the Client type parameter\ntype ExtractClientUserData<T> = T extends { userData: infer U } ? U : T;\ntype ExtractClientAuth<T> = T extends { auth: infer A } ? A : any;\ntype ExtractClientMessages<T> = T extends { messages: infer M } ? M : any;\n\n// Helper type to make message required when the message type demands it\nexport type MessageArgs<M, Options> =\n unknown extends M ? [message?: M, options?: Options] : // Handle 'any' type (backwards compatibility)\n [M] extends [never] ? [message?: M, options?: Options] :\n [M] extends [void] ? [message?: M, options?: Options] :\n [M] extends [undefined] ? [message?: M, options?: Options] :\n undefined extends M ? [message?: M, options?: Options] :\n [message: M, options?: Options];\n\n/**\n * The client instance from the server-side is responsible for the transport layer between the server and the client.\n * It should not be confused with the Client from the client-side SDK, as they have completely different purposes!\n * You operate on client instances from `this.clients`, `Room#onJoin()`, `Room#onLeave()` and `Room#onMessage()`.\n *\n * - This is the raw WebSocket connection coming from the `ws` package. There are more methods available which aren't\n * encouraged to use along with Colyseus.\n */\nexport interface Client<T extends { userData?: any, auth?: any, messages?: Record<string | number, any> } = any> {\n '~messages': ExtractClientMessages<T>;\n\n ref: EventEmitter;\n\n /**\n * Unique id per session.\n */\n sessionId: string;\n\n /**\n * Connection state\n */\n state: ClientState;\n\n /**\n * Optional: when using `@view()` decorator in your state properties, this will be the view instance for this client.\n */\n view?: StateView;\n\n /**\n * User-defined data can be attached to the Client instance through this variable.\n * - Can be used to store custom data about the client's connection. userData is not synchronized with the client,\n * and should be used only to keep player-specific with its connection.\n */\n userData?: ExtractClientUserData<T>;\n\n /**\n * auth data provided by your `onAuth`\n */\n auth?: ExtractClientAuth<T>;\n\n /**\n * Reconnection token used to re-join the room after onLeave + allowReconnection().\n *\n * IMPORTANT:\n * This is not the full reconnection token the client provides for the server.\n * The format provided by .reconnect() from the client-side must follow: \"${roomId}:${reconnectionToken}\"\n */\n reconnectionToken: string;\n\n // TODO: move these to ClientPrivate\n raw(data: Uint8Array | Buffer, options?: ISendOptions, cb?: (err?: Error) => void): void;\n enqueueRaw(data: Uint8Array | Buffer, options?: ISendOptions): void;\n\n /**\n * Send a type of message to the client. Messages are encoded with MsgPack and can hold any\n * JSON-serializable data structure.\n *\n * @param type String or Number identifier the client SDK will use to receive this message\n * @param message Message payload. (automatically encoded with msgpack.)\n * @param options\n */\n send<K extends keyof this['~messages']>(\n type: K,\n ...args: MessageArgs<this['~messages'][K], ISendOptions>\n ): void;\n\n /**\n * Send raw bytes to this specific client.\n *\n * @param type String or Number identifier the client SDK will use to receive this message\n * @param bytes Raw byte array payload\n * @param options\n */\n sendBytes(type: string | number, bytes: Buffer | Uint8Array, options?: ISendOptions): void;\n\n /**\n * Disconnect this client from the room.\n *\n * @param code Custom close code. Default value is 1000.\n * @param data\n * @see [Leave room](https://docs.colyseus.io/room#leave-room)\n */\n leave(code?: number, data?: string): void;\n\n /**\n * @deprecated Use .leave() instead.\n */\n close(code?: number, data?: string): void;\n\n /**\n * Triggers `onError` with specified code to the client-side.\n *\n * @param code\n * @param message\n */\n error(code: number, message?: string): void;\n}\n\n/**\n * Private properties of the Client instance.\n * Only accessible internally by the framework, should not be encouraged/auto-completed for the user.\n *\n * TODO: refactor this.\n * @private\n */\nexport interface ClientPrivate {\n readyState: number; // TODO: remove readyState on version 1.0.0. Use only \"state\" instead.\n _enqueuedMessages?: any[];\n _afterNextPatchQueue: Array<[string | number | Client, ArrayLike<any>]>;\n _joinedAt: number; // \"elapsedTime\" when the client joined the room.\n\n /**\n * Used for rate limiting via maxMessagesPerSecond.\n */\n _numMessagesLastSecond?: number;\n _lastMessageTime?: number;\n\n /**\n * Per-client input Schema instance, allocated on join when the Room\n * declares `input`. Mutated in-place by {@link _inputDecoder} on each\n * incoming ROOM_INPUT_* packet.\n *\n * Typed loosely (`any`) so duplicate `@colyseus/schema` installs don't\n * trigger type-identity errors against user-defined input classes.\n */\n _input?: any;\n _inputDecoder?: InputDecoder;\n\n /**\n * Per-client buffer of cloned input snapshots, allocated on join when\n * `Room.inputOptions.bufferMaxSize > 0`. Populated on each decoded frame.\n */\n _inputBuffer?: import('./input/InputBuffer.ts').InputBufferImpl;\n\n /**\n * Cached per-client accessor returned by `room.input(sessionId)`. Built\n * once at join (when the Room called `defineInput()`), so the public API\n * call is a Map lookup + property read with no per-call allocation.\n */\n _inputAccessor?: import('./input/InputBuffer.ts').InputAccessor;\n\n /**\n * Used for rate limiting ROOM_INPUT_* packets via maxInputsPerSecond,\n * independent of maxMessagesPerSecond.\n */\n _numInputsLastSecond?: number;\n _lastInputTime?: number;\n}\n\nexport class ClientArray<C extends Client = Client> extends Array<C> {\n /**\n * Secondary index for O(1) lookup by sessionId. Kept in sync by the\n * mutating methods overridden below. Direct index assignment\n * (`arr[i] = client`) and `arr.length = 0` bypass this index \u2014 use\n * `push` / `splice` / `delete` / `pop` / `shift` / `unshift` instead.\n */\n private _byId: Map<string, C> = new Map();\n\n public getById(sessionId: string): C | undefined {\n return this._byId.get(sessionId);\n }\n\n public delete(client: C): boolean {\n const removed = spliceOne(this, this.indexOf(client));\n if (removed) this._byId.delete(client.sessionId);\n return removed;\n }\n\n public push(...items: C[]): number {\n for (let i = 0; i < items.length; i++) this._byId.set(items[i].sessionId, items[i]);\n return super.push(...items);\n }\n\n public pop(): C | undefined {\n const removed = super.pop();\n if (removed !== undefined) this._byId.delete(removed.sessionId);\n return removed;\n }\n\n public shift(): C | undefined {\n const removed = super.shift();\n if (removed !== undefined) this._byId.delete(removed.sessionId);\n return removed;\n }\n\n public unshift(...items: C[]): number {\n for (let i = 0; i < items.length; i++) this._byId.set(items[i].sessionId, items[i]);\n return super.unshift(...items);\n }\n\n public splice(start: number, deleteCount?: number, ...items: C[]): C[] {\n const removed = (deleteCount === undefined)\n ? super.splice(start)\n : super.splice(start, deleteCount, ...items);\n for (let i = 0; i < removed.length; i++) this._byId.delete(removed[i].sessionId);\n for (let i = 0; i < items.length; i++) this._byId.set(items[i].sessionId, items[i]);\n return removed;\n }\n}\n\n/**\n * Shared internal method to connect a Client into a Room.\n * Validates seat reservation and joins the client to the room.\n *\n * @remarks\n * **\u26A0\uFE0F This is an internal API and not intended for end-user use.**\n *\n * @internal\n */\nexport async function connectClientToRoom(\n room: Room | undefined,\n client: Client & ClientPrivate,\n authContext: AuthContext,\n connectionOptions: {\n reconnectionToken?: string;\n skipHandshake?: boolean;\n },\n): Promise<void> {\n if (!room || !room.hasReservedSeat(client.sessionId, connectionOptions.reconnectionToken)) {\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, 'seat reservation expired.');\n }\n\n await room['_onJoin'](client, authContext, connectionOptions);\n}"],
5
+ "mappings": ";AAAA,OAAsB;AACtB,OAAuB;AAIvB,SAAS,iBAAiB;AAC1B,OAA0B;AAG1B,OAA6B;AAC7B,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAI5B,IAAI;AACG,SAAS,aAAa,WAAsB;AAAE,eAAa;AAAW;AACtE,SAAS,eAAe;AAAE,SAAO;AAAY;AAE7C,IAAe,YAAf,MAAyB;AAsBhC;AAeO,IAAM,cAAc;AAAA,EACzB,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,aAAa;AAAA,EACb,SAAS;AAAA,EACT,QAAQ;AACV;AAsKO,IAAM,cAAN,cAAqD,MAAS;AAAA,EAA9D;AAAA;AAOL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAQ,QAAwB,oBAAI,IAAI;AAAA;AAAA,EAEjC,QAAQ,WAAkC;AAC/C,WAAO,KAAK,MAAM,IAAI,SAAS;AAAA,EACjC;AAAA,EAEO,OAAO,QAAoB;AAChC,UAAM,UAAU,UAAU,MAAM,KAAK,QAAQ,MAAM,CAAC;AACpD,QAAI,QAAS,MAAK,MAAM,OAAO,OAAO,SAAS;AAC/C,WAAO;AAAA,EACT;AAAA,EAEO,QAAQ,OAAoB;AACjC,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,MAAK,MAAM,IAAI,MAAM,CAAC,EAAE,WAAW,MAAM,CAAC,CAAC;AAClF,WAAO,MAAM,KAAK,GAAG,KAAK;AAAA,EAC5B;AAAA,EAEO,MAAqB;AAC1B,UAAM,UAAU,MAAM,IAAI;AAC1B,QAAI,YAAY,OAAW,MAAK,MAAM,OAAO,QAAQ,SAAS;AAC9D,WAAO;AAAA,EACT;AAAA,EAEO,QAAuB;AAC5B,UAAM,UAAU,MAAM,MAAM;AAC5B,QAAI,YAAY,OAAW,MAAK,MAAM,OAAO,QAAQ,SAAS;AAC9D,WAAO;AAAA,EACT;AAAA,EAEO,WAAW,OAAoB;AACpC,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,MAAK,MAAM,IAAI,MAAM,CAAC,EAAE,WAAW,MAAM,CAAC,CAAC;AAClF,WAAO,MAAM,QAAQ,GAAG,KAAK;AAAA,EAC/B;AAAA,EAEO,OAAO,OAAe,gBAAyB,OAAiB;AACrE,UAAM,UAAW,gBAAgB,SAC7B,MAAM,OAAO,KAAK,IAClB,MAAM,OAAO,OAAO,aAAa,GAAG,KAAK;AAC7C,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,IAAK,MAAK,MAAM,OAAO,QAAQ,CAAC,EAAE,SAAS;AAC/E,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,MAAK,MAAM,IAAI,MAAM,CAAC,EAAE,WAAW,MAAM,CAAC,CAAC;AAClF,WAAO;AAAA,EACT;AACF;AAWA,eAAsB,oBACpB,MACA,QACA,aACA,mBAIe;AACf,MAAI,CAAC,QAAQ,CAAC,KAAK,gBAAgB,OAAO,WAAW,kBAAkB,iBAAiB,GAAG;AACzF,UAAM,IAAI,YAAY,UAAU,mBAAmB,2BAA2B;AAAA,EAChF;AAEA,QAAM,KAAK,SAAS,EAAE,QAAQ,aAAa,iBAAiB;AAC9D;",
6
6
  "names": []
7
7
  }
package/build/index.cjs CHANGED
@@ -52,13 +52,15 @@ __export(index_exports, {
52
52
  RelayRoom: () => import_RelayRoom.RelayRoom,
53
53
  Room: () => import_Room.Room,
54
54
  RoomInternalState: () => import_Room.RoomInternalState,
55
+ RoomPlugin: () => import_RoomPlugin.RoomPlugin,
55
56
  SchemaSerializer: () => import_SchemaSerializer.SchemaSerializer,
56
57
  Server: () => import_Server.Server,
57
58
  ServerError: () => import_ServerError.ServerError,
58
59
  SimulationIntervalException: () => import_RoomExceptions.SimulationIntervalException,
59
60
  TimedEventException: () => import_RoomExceptions.TimedEventException,
60
61
  Transport: () => import_Transport.Transport,
61
- __globalEndpoints: () => import_router.__globalEndpoints,
62
+ attachToTestRoom: () => import_RoomPlugin.attachToTestRoom,
63
+ basicAuth: () => import_router.basicAuth,
62
64
  connectClientToRoom: () => import_Transport.connectClientToRoom,
63
65
  createEndpoint: () => import_router.createEndpoint,
64
66
  createInternalContext: () => import_router.createInternalContext,
@@ -73,8 +75,10 @@ __export(index_exports, {
73
75
  debugMessage: () => import_Debug.debugMessage,
74
76
  debugPatch: () => import_Debug.debugPatch,
75
77
  debugPresence: () => import_Debug.debugPresence,
78
+ definePlugins: () => import_RoomPlugin.definePlugins,
76
79
  defineRoom: () => import_Server.defineRoom,
77
80
  defineServer: () => import_Server.defineServer,
81
+ dualModeEndpoints: () => import_router.dualModeEndpoints,
78
82
  dynamicImport: () => import_Utils.dynamicImport,
79
83
  generateId: () => import_Utils.generateId,
80
84
  getBearerToken: () => import_Utils.getBearerToken,
@@ -100,6 +104,7 @@ var import_timer = require("@colyseus/timer");
100
104
  var import_shared_types = require("@colyseus/shared-types");
101
105
  var import_Server = require("./Server.cjs");
102
106
  var import_Room = require("./Room.cjs");
107
+ var import_RoomPlugin = require("./RoomPlugin.cjs");
103
108
  var import_Protocol = require("./Protocol.cjs");
104
109
  var import_RegisteredHandler = require("./matchmaker/RegisteredHandler.cjs");
105
110
  var import_ServerError = require("./errors/ServerError.cjs");
@@ -146,13 +151,15 @@ var import_Logger = require("./Logger.cjs");
146
151
  RelayRoom,
147
152
  Room,
148
153
  RoomInternalState,
154
+ RoomPlugin,
149
155
  SchemaSerializer,
150
156
  Server,
151
157
  ServerError,
152
158
  SimulationIntervalException,
153
159
  TimedEventException,
154
160
  Transport,
155
- __globalEndpoints,
161
+ attachToTestRoom,
162
+ basicAuth,
156
163
  connectClientToRoom,
157
164
  createEndpoint,
158
165
  createInternalContext,
@@ -167,8 +174,10 @@ var import_Logger = require("./Logger.cjs");
167
174
  debugMessage,
168
175
  debugPatch,
169
176
  debugPresence,
177
+ definePlugins,
170
178
  defineRoom,
171
179
  defineServer,
180
+ dualModeEndpoints,
172
181
  dynamicImport,
173
182
  generateId,
174
183
  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;AAAA;AAAA;AAAA;AAAA,4BAAAA;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;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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA6C;AAG7C,0BAOO;AAGP,oBAA8J;AAC9J,kBAAiM;AACjM,sBAAgC;AAChC,+BAAkC;AAClC,yBAA4B;AAE5B,4BAWO;AAGP,iBAA4B;AAE5B,mBAA4C;AAC5C,kBAAgD;AAGhD,0BAAc,qDAvCd;AAwCA,oBAAoC;AAGpC,uBAA+I;AAG/I,sBAA8B;AAC9B,2BAA8B;AAG9B,wBAAgC;AAChC,8BAAiC;AAIjC,mBAA+E;AAC/E,qBAAsC;AAGtC,iBAA6C;AAG7C,mBASO;AAGP,uBAA0B;AAC1B,uBAA0B;AAC1B,uBAA8G;AAG9G,oBAcO;AAGP,oBAAuB;",
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;AAAA;AAAA;AAAA;AAAA,4BAAAA;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;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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA6C;AAG7C,0BAOO;AAGP,oBAA8J;AAC9J,kBAAiM;AACjM,wBAGO;AACP,sBAAgC;AAChC,+BAAkC;AAClC,yBAA4B;AAE5B,4BAWO;AAGP,iBAA4B;AAE5B,mBAA4C;AAC5C,kBAAgD;AAGhD,0BAAc,qDA3Cd;AA4CA,oBAAoC;AAGpC,uBAA+I;AAG/I,sBAA8B;AAC9B,2BAA8B;AAG9B,wBAAgC;AAChC,8BAAiC;AAIjC,mBAA+E;AAC/E,qBAAsC;AAGtC,iBAA6C;AAG7C,mBASO;AAGP,uBAA0B;AAC1B,uBAA0B;AAC1B,uBAA8G;AAG9G,oBAmBO;AAGP,oBAAuB;",
6
6
  "names": ["Clock"]
7
7
  }
package/build/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import { ClockTimer as Clock, Delayed } from '@colyseus/timer';
2
2
  export { Protocol, ErrorCode, CloseCode, type InferState, type ExtractRoomMessages, type ExtractRoomClientMessages, } from '@colyseus/shared-types';
3
3
  export { Server, defineRoom, defineServer, registerRoomDefinitions, unregisterRoomDefinitions, type RoomDefinitions, type ServerOptions, type SDKTypes } from './Server.ts';
4
4
  export { Room, room, RoomInternalState, validate, type RoomOptions, type MessageHandlerWithFormat, type Messages, type ExtractRoomState, type ExtractRoomMetadata, type ExtractRoomClient } from './Room.ts';
5
+ export { RoomPlugin, definePlugins, attachToTestRoom, type RoomPluginOrder, type PluginDependencies, type RoomPluginClass, } from './RoomPlugin.ts';
5
6
  export { getMessageBytes } from './Protocol.ts';
6
7
  export { RegisteredHandler } from './matchmaker/RegisteredHandler.ts';
7
8
  export { ServerError } from './errors/ServerError.ts';
@@ -25,5 +26,5 @@ export { debugMatchMaking, debugMessage, debugPatch, debugError, debugConnection
25
26
  export { LobbyRoom } from './rooms/LobbyRoom.ts';
26
27
  export { RelayRoom } from './rooms/RelayRoom.ts';
27
28
  export { QueueRoom, type QueueOptions, type QueueMatchGroup, type QueueMatchTeam, type QueueClientData } from './rooms/QueueRoom.ts';
28
- export { createEndpoint, createInternalContext, createMiddleware, createRouter, toNodeHandler, __globalEndpoints, type Router, type RouterConfig, type Endpoint, type EndpointHandler, type EndpointOptions, type EndpointContext, type StrictEndpoint, } from './router/index.ts';
29
+ export { createEndpoint, createInternalContext, createMiddleware, createRouter, basicAuth, type BasicAuthOptions, toNodeHandler, dualModeEndpoints, type Router, type RouterConfig, type Endpoint, type EndpointHandler, type EndpointOptions, type EndpointContext, type StrictEndpoint, type ExpressMiddleware, type NodeHandler, type DualModeHelpers, } from './router/index.ts';
29
30
  export { logger } from './Logger.ts';