@colyseus/core 0.18.4 → 0.18.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/Debug.cjs +1 -0
- package/build/Debug.cjs.map +1 -1
- package/build/IPC.cjs +1 -0
- package/build/IPC.cjs.map +1 -1
- package/build/Logger.cjs +1 -0
- package/build/Logger.cjs.map +1 -1
- package/build/MatchMaker.cjs +11 -3
- package/build/MatchMaker.cjs.map +2 -2
- package/build/MatchMaker.mjs +10 -3
- package/build/MatchMaker.mjs.map +2 -2
- package/build/Protocol.cjs +1 -0
- package/build/Protocol.cjs.map +1 -1
- package/build/Rewind.cjs +1 -0
- package/build/Rewind.cjs.map +1 -1
- package/build/Room.cjs +102 -0
- package/build/Room.cjs.map +2 -2
- package/build/Room.d.ts +57 -0
- package/build/Room.mjs +101 -0
- package/build/Room.mjs.map +2 -2
- package/build/RoomMessages.cjs +1 -0
- package/build/RoomMessages.cjs.map +1 -1
- package/build/RoomPlugin.cjs +1 -0
- package/build/RoomPlugin.cjs.map +1 -1
- package/build/Server.cjs +1 -0
- package/build/Server.cjs.map +1 -1
- package/build/Stats.cjs +1 -0
- package/build/Stats.cjs.map +1 -1
- package/build/Transport.cjs +39 -0
- package/build/Transport.cjs.map +2 -2
- package/build/Transport.d.ts +66 -1
- package/build/Transport.mjs +37 -1
- package/build/Transport.mjs.map +2 -2
- package/build/errors/RoomExceptions.cjs +1 -0
- package/build/errors/RoomExceptions.cjs.map +1 -1
- package/build/errors/SeatReservationError.cjs +1 -0
- package/build/errors/SeatReservationError.cjs.map +1 -1
- package/build/errors/ServerError.cjs +1 -0
- package/build/errors/ServerError.cjs.map +1 -1
- package/build/index.cjs +5 -0
- package/build/index.cjs.map +2 -2
- package/build/index.d.ts +1 -1
- package/build/index.mjs +3 -1
- package/build/index.mjs.map +2 -2
- package/build/input/InputBuffer.cjs +1 -0
- package/build/input/InputBuffer.cjs.map +1 -1
- package/build/input/RoomInput.cjs +64 -3
- package/build/input/RoomInput.cjs.map +2 -2
- package/build/input/RoomInput.d.ts +16 -2
- package/build/input/RoomInput.mjs +63 -3
- package/build/input/RoomInput.mjs.map +2 -2
- package/build/input/types.cjs +1 -0
- package/build/input/types.cjs.map +1 -1
- package/build/internal.cjs +1 -0
- package/build/internal.cjs.map +1 -1
- package/build/matchmaker/Lobby.cjs +1 -0
- package/build/matchmaker/Lobby.cjs.map +1 -1
- package/build/matchmaker/LocalDriver/LocalDriver.cjs +1 -0
- package/build/matchmaker/LocalDriver/LocalDriver.cjs.map +1 -1
- package/build/matchmaker/LocalDriver/Query.cjs +1 -0
- package/build/matchmaker/LocalDriver/Query.cjs.map +1 -1
- package/build/matchmaker/RegisteredHandler.cjs +1 -0
- package/build/matchmaker/RegisteredHandler.cjs.map +1 -1
- package/build/matchmaker/controller.cjs +1 -0
- package/build/matchmaker/controller.cjs.map +1 -1
- package/build/matchmaker/driver.cjs +1 -0
- package/build/matchmaker/driver.cjs.map +2 -2
- package/build/matchmaker/driver.d.ts +4 -2
- package/build/matchmaker/driver.mjs.map +1 -1
- package/build/presence/LocalPresence.cjs +1 -0
- package/build/presence/LocalPresence.cjs.map +1 -1
- package/build/presence/Presence.cjs +1 -0
- package/build/presence/Presence.cjs.map +1 -1
- package/build/rooms/LobbyRoom.cjs +1 -0
- package/build/rooms/LobbyRoom.cjs.map +1 -1
- package/build/rooms/QueueRoom.cjs +1 -0
- package/build/rooms/QueueRoom.cjs.map +1 -1
- package/build/rooms/RelayRoom.cjs +1 -0
- package/build/rooms/RelayRoom.cjs.map +1 -1
- package/build/router/default_routes.cjs +2 -7
- package/build/router/default_routes.cjs.map +2 -2
- package/build/router/default_routes.mjs +2 -8
- package/build/router/default_routes.mjs.map +2 -2
- package/build/router/index.cjs +1 -0
- package/build/router/index.cjs.map +1 -1
- package/build/router/node.cjs +1 -0
- package/build/router/node.cjs.map +1 -1
- package/build/serializer/NoneSerializer.cjs +1 -0
- package/build/serializer/NoneSerializer.cjs.map +1 -1
- package/build/serializer/SchemaSerializer.cjs +98 -0
- package/build/serializer/SchemaSerializer.cjs.map +2 -2
- package/build/serializer/SchemaSerializer.d.ts +25 -0
- package/build/serializer/SchemaSerializer.mjs +98 -1
- package/build/serializer/SchemaSerializer.mjs.map +2 -2
- package/build/serializer/Serializer.cjs +1 -0
- package/build/serializer/Serializer.cjs.map +2 -2
- package/build/serializer/Serializer.d.ts +15 -0
- package/build/utils/DevMode.cjs +1 -0
- package/build/utils/DevMode.cjs.map +1 -1
- package/build/utils/Env.cjs +1 -0
- package/build/utils/Env.cjs.map +1 -1
- package/build/utils/StandardSchema.cjs +1 -0
- package/build/utils/StandardSchema.cjs.map +1 -1
- package/build/utils/UserSessionIndex.cjs +1 -0
- package/build/utils/UserSessionIndex.cjs.map +1 -1
- package/build/utils/Utils.cjs +1 -0
- package/build/utils/Utils.cjs.map +1 -1
- package/build/utils/nanoevents.cjs +1 -0
- package/build/utils/nanoevents.cjs.map +1 -1
- package/package.json +6 -6
- package/src/MatchMaker.ts +20 -3
- package/src/Room.ts +122 -0
- package/src/Transport.ts +132 -4
- package/src/index.ts +1 -1
- package/src/input/RoomInput.ts +76 -3
- package/src/matchmaker/driver.ts +4 -2
- package/src/router/default_routes.ts +2 -8
- package/src/serializer/SchemaSerializer.ts +146 -1
- package/src/serializer/Serializer.ts +17 -0
package/build/Transport.mjs.map
CHANGED
|
@@ -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';\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 /** Self-signed cert SHA-256 hash (byte array), surfaced to clients in the\n * matchmake response so a WebTransport client can pin it via\n * `serverCertificateHashes`. Set by transports that generate their own cert\n * (h3). Undefined for transports using a CA-trusted cert. */\n public fingerprint?: number[];\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 _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/types.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 /**\n * `performance.now()` recorded when the most recent ROOM_INPUT_* packet\n * from this client was received. Receive-side diagnostic only \u2014 NOT on the\n * wire: the {@link ProtocolModifier.TIMED} state prefix acks the seq of the\n * last input CONSUMED into the state (the input buffer's `ackSeq`).\n *\n * `0` until the client has sent its first input.\n */\n _lastInputReceivedAt?: number;\n\n /**\n * Monotonic count of *reliable* inputs successfully received from this\n * client. Receive-time counter \u2014 it LEADS the state by inputs still\n * buffered; what the TIMED prefix acks is the CONSUMED seq (the input\n * buffer's `ackSeq`), not this. Stays at the default `0` until the client\n * sends its first reliable input.\n *\n * Only ROOM_INPUT_RELIABLE bumps this \u2014 unreliable's redundant-ring\n * pattern would double-count.\n */\n _receivedInputCount?: number;\n\n /**\n * Running baseline for the DELTA-CODED lag-comp stamp on ROOM_INPUT_RELIABLE\n * frames (the {@link ProtocolModifier.TIMED} prefix). Each frame carries only\n * the signed change from the previous stamp; this accumulates them back into\n * the absolute timeline value. Zeroed on (re)connect alongside the SDK's own\n * baseline so the first delta after a reset is absolute. `0` until allocated.\n */\n _reckonBaseline?: number;\n\n /**\n * @internal Per-client raw frames staged to ride out right AFTER this client's\n * next state patch \u2014 per-client `afterNextPatch` messages. Lazily allocated.\n * Pushed by {@link enqueueClientRaw} (the `afterNextPatch` path), flushed as\n * standalone frames after the patch by {@link Room._flushPendingClientFrames}.\n * Room-level `broadcast` `afterNextPatch` uses the Room's own queue instead, not\n * this buffer.\n */\n _pendingFrames?: Uint8Array[];\n\n /**\n * @internal Back-reference to the Room's \"clients with staged frames\" list,\n * shared by reference at join. {@link enqueueClientRaw} pushes the client here\n * on its first staged frame of a cycle, so the after-patch flush iterates just\n * those clients rather than scanning every client.\n */\n _pendingFrameClients?: Array<Client & ClientPrivate>;\n}\n\n/**\n * The framework-level send path shared by every transport's `enqueueRaw` \u2014 the\n * single source of truth so each transport implements only the wire-level `raw`.\n * Routes a raw frame by where it should go:\n *\n * - `afterNextPatch` \u2192 stage onto the per-client {@link ClientPrivate._pendingFrames}\n * buffer, sent as a standalone frame right AFTER the next state patch; a\n * no-allocation push into a reused array. The client announces itself to the\n * Room's {@link ClientPrivate._pendingFrameClients} list on its first staged\n * frame of a cycle.\n * - before JOIN \u2192 buffer in `_enqueuedMessages` until the JOIN_ROOM handshake flushes.\n * - otherwise \u2192 send now via the transport's `raw`.\n *\n * @internal\n */\nexport function enqueueClientRaw(\n client: Client & ClientPrivate,\n data: Uint8Array | Buffer,\n options?: ISendOptions,\n): void {\n if (options?.afterNextPatch) {\n let frames = client._pendingFrames;\n if (frames === undefined) { frames = client._pendingFrames = []; }\n if (frames.length === 0) { client._pendingFrameClients?.push(client); } // first frame this cycle\n frames.push(data);\n return;\n }\n if (client.state !== ClientState.JOINED) {\n // During `onJoin` / `onReconnect` the client can't register onMessage\n // handlers yet \u2014 buffer until JOIN_ROOM has been sent.\n client._enqueuedMessages?.push(data);\n return;\n }\n client.raw(data, options);\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 /** The client for `sessionId`, or `undefined` \u2014 O(1). The canonical per-session\n * lookup (mirrors `room.inputs.get(sessionId)`). */\n public get(sessionId: string): C | undefined {\n return this._byId.get(sessionId);\n }\n\n /** @deprecated Use {@link get}. */\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;
|
|
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 { debugAndPrintError } from './Debug.ts';\nimport { getBearerToken, 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 /** Self-signed cert SHA-256 hash (byte array), surfaced to clients in the\n * matchmake response so a WebTransport client can pin it via\n * `serverCertificateHashes`. Set by transports that generate their own cert\n * (h3). Undefined for transports using a CA-trusted cert. */\n public fingerprint?: number[];\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\n/**\n * Intercepts an incoming WebSocket upgrade request, before the handshake.\n *\n * Return a `Response` to answer the request instead of upgrading it. Return\n * nothing to upgrade as usual. The handler may be async, and the handshake waits\n * for it to resolve.\n *\n * `context` is the same shape `onAuth()` receives, read-only here: mutating it\n * does not carry over to `onAuth()`.\n *\n * Not supported by `H3Transport`: WebTransport has no upgrade handshake.\n *\n * @example\n * ```typescript\n * new uWebSocketsTransport({\n * beforeUpgrade: async (request, context) => {\n * if (await isBanned(context.ip)) {\n * return new Response(null, { status: 403 });\n * }\n * }\n * });\n * ```\n */\nexport type BeforeUpgradeHandler = (\n request: Request,\n context: Readonly<AuthContext>,\n) => Response | void | Promise<Response | void>;\n\n/**\n * Invokes a `beforeUpgrade` handler, resolving with the `Response` to send\n * instead of upgrading, or `undefined` to proceed with the upgrade.\n *\n * Every transport goes through here, so a handler written against one keeps\n * working on the others. Never rejects: uWebSockets.js aborts the process on an\n * upgrade handler that yields without responding, and on the other transports a\n * raw socket left behind leaks a connection.\n *\n * @internal\n */\nexport async function runBeforeUpgrade(\n handler: BeforeUpgradeHandler,\n url: string, // path, optionally including the query string\n context: AuthContext,\n): Promise<Response | undefined> {\n let request: Request;\n\n try {\n const host = context.headers.get('host') || 'localhost';\n request = new Request(`http://${host}${url}`, { headers: context.headers });\n\n } catch (e: any) {\n // a `Host` header that isn't a valid authority fails to parse as a URL\n debugAndPrintError(e);\n return new Response(null, { status: 400 });\n }\n\n try {\n return (await handler(request, context)) ?? undefined;\n\n } catch (e: any) {\n debugAndPrintError(e);\n return new Response(null, { status: 500 });\n }\n}\n\n/** Headers as the transport has them: uWebSockets.js and Node give a plain record. */\ntype RawHeaders = Headers | Record<string, string | undefined>;\n\nconst readHeader = (headers: RawHeaders, name: string) =>\n (headers instanceof Headers) ? headers.get(name) : headers[name];\n\n/**\n * Builds the context passed to `beforeUpgrade` and `onAuth`.\n *\n * Every transport goes through here, so the context is identical everywhere,\n * down to how the client address is resolved. `headers` is materialized on\n * first read: a connection nobody inspects pays nothing for the conversion.\n *\n * @internal\n */\nexport function createAuthContext(options: {\n headers: RawHeaders,\n token?: string | null,\n remoteAddress?: string,\n req?: any,\n}): AuthContext {\n const source = options.headers;\n let headers: Headers | undefined;\n\n return {\n token: options.token ?? getBearerToken(readHeader(source, 'authorization')),\n ip: resolveClientIp(source, options.remoteAddress),\n req: options.req,\n get headers() {\n return headers ??= (source instanceof Headers)\n ? source\n : new Headers(source as Record<string, string>);\n },\n };\n}\n\n/**\n * A single address, resolved the same way on every transport: `x-forwarded-for`\n * carries the whole proxy chain, and only its first entry is the client.\n */\nfunction resolveClientIp(headers: RawHeaders, remoteAddress?: string): string | undefined {\n // an empty header counts as absent\n const firstHop = (name: string) => readHeader(headers, name)?.split(',')[0].trim() || undefined;\n\n return (\n firstHop('x-real-ip') ??\n firstHop('x-forwarded-for') ??\n firstHop('x-client-ip') ??\n (remoteAddress || undefined)\n );\n}\n\nexport type AuthContext = {\n token?: string,\n /** Undefined when no proxy header carries it and the transport has no peer address. */\n ip: string | undefined;\n headers: Headers,\n /** Only set on the HTTP matchmaking request, where it is the `Request` itself. */\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 raw bytes over the transport's UNRELIABLE channel \u2014 no delivery,\n * ordering, or duplication guarantee. Used for `@unreliable` state patches.\n *\n * Absent on transports with no datagram channel (every WebSocket transport).\n * Its presence IS the capability check \u2014 callers feature-detect rather than\n * reading a separate flag, and skip clients that can't receive.\n */\n rawUnreliable?(data: Uint8Array | Buffer, options?: ISendOptions, cb?: (err?: Error) => void): 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 _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/types.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 /**\n * `performance.now()` recorded when the most recent ROOM_INPUT_* packet\n * from this client was received. Receive-side diagnostic only \u2014 NOT on the\n * wire: the {@link ProtocolModifier.TIMED} state prefix acks the seq of the\n * last input CONSUMED into the state (the input buffer's `ackSeq`).\n *\n * `0` until the client has sent its first input.\n */\n _lastInputReceivedAt?: number;\n\n /**\n * Monotonic count of *reliable* inputs successfully received from this\n * client. Receive-time counter \u2014 it LEADS the state by inputs still\n * buffered; what the TIMED prefix acks is the CONSUMED seq (the input\n * buffer's `ackSeq`), not this. Stays at the default `0` until the client\n * sends its first reliable input.\n *\n * Only ROOM_INPUT_RELIABLE bumps this \u2014 unreliable's redundant-ring\n * pattern would double-count.\n */\n _receivedInputCount?: number;\n\n /**\n * Running baseline for the DELTA-CODED lag-comp stamp on ROOM_INPUT_RELIABLE\n * frames (the {@link ProtocolModifier.TIMED} prefix). Each frame carries only\n * the signed change from the previous stamp; this accumulates them back into\n * the absolute timeline value. Zeroed on (re)connect alongside the SDK's own\n * baseline so the first delta after a reset is absolute. `0` until allocated.\n */\n _reckonBaseline?: number;\n\n /**\n * @internal Per-client raw frames staged to ride out right AFTER this client's\n * next state patch \u2014 per-client `afterNextPatch` messages. Lazily allocated.\n * Pushed by {@link enqueueClientRaw} (the `afterNextPatch` path), flushed as\n * standalone frames after the patch by {@link Room._flushPendingClientFrames}.\n * Room-level `broadcast` `afterNextPatch` uses the Room's own queue instead, not\n * this buffer.\n */\n _pendingFrames?: Uint8Array[];\n\n /**\n * @internal Back-reference to the Room's \"clients with staged frames\" list,\n * shared by reference at join. {@link enqueueClientRaw} pushes the client here\n * on its first staged frame of a cycle, so the after-patch flush iterates just\n * those clients rather than scanning every client.\n */\n _pendingFrameClients?: Array<Client & ClientPrivate>;\n}\n\n/**\n * The framework-level send path shared by every transport's `enqueueRaw` \u2014 the\n * single source of truth so each transport implements only the wire-level `raw`.\n * Routes a raw frame by where it should go:\n *\n * - `afterNextPatch` \u2192 stage onto the per-client {@link ClientPrivate._pendingFrames}\n * buffer, sent as a standalone frame right AFTER the next state patch; a\n * no-allocation push into a reused array. The client announces itself to the\n * Room's {@link ClientPrivate._pendingFrameClients} list on its first staged\n * frame of a cycle.\n * - before JOIN \u2192 buffer in `_enqueuedMessages` until the JOIN_ROOM handshake flushes.\n * - otherwise \u2192 send now via the transport's `raw`.\n *\n * @internal\n */\nexport function enqueueClientRaw(\n client: Client & ClientPrivate,\n data: Uint8Array | Buffer,\n options?: ISendOptions,\n): void {\n if (options?.afterNextPatch) {\n let frames = client._pendingFrames;\n if (frames === undefined) { frames = client._pendingFrames = []; }\n if (frames.length === 0) { client._pendingFrameClients?.push(client); } // first frame this cycle\n frames.push(data);\n return;\n }\n if (client.state !== ClientState.JOINED) {\n // During `onJoin` / `onReconnect` the client can't register onMessage\n // handlers yet \u2014 buffer until JOIN_ROOM has been sent.\n client._enqueuedMessages?.push(data);\n return;\n }\n client.raw(data, options);\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 /** The client for `sessionId`, or `undefined` \u2014 O(1). The canonical per-session\n * lookup (mirrors `room.inputs.get(sessionId)`). */\n public get(sessionId: string): C | undefined {\n return this._byId.get(sessionId);\n }\n\n /** @deprecated Use {@link get}. */\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": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/errors/RoomExceptions.ts"],
|
|
4
4
|
"sourcesContent": ["import type { ExtractMessageType } from '@colyseus/shared-types';\nimport type { Room } from '../Room.ts';\n\nexport type RoomMethodName = 'onCreate'\n | 'onAuth'\n | 'onJoin'\n | 'onLeave'\n | 'onDrop'\n | 'onReconnect'\n | 'onDispose'\n | 'onMessage'\n | 'setTimestep'\n | 'setFixedTimestep'\n | 'setInterval'\n | 'setTimeout';\n\nexport type RoomException<R extends Room = Room> =\n OnCreateException<R> |\n OnAuthException<R> |\n OnJoinException<R> |\n OnLeaveException<R> |\n OnDropException<R> |\n OnReconnectException<R> |\n OnDisposeException |\n OnMessageException<R> |\n TimestepException |\n TimedEventException;\n\nexport class OnCreateException<R extends Room = Room> extends Error {\n options: Parameters<NonNullable<R['onCreate']>>[0];\n constructor(\n cause: Error,\n message: string,\n options: Parameters<NonNullable<R['onCreate']>>[0],\n ) {\n super(message, { cause });\n this.name = 'OnCreateException';\n this.options = options;\n }\n}\n\nexport class OnAuthException<R extends Room = Room> extends Error {\n client: Parameters<R['onAuth']>[0];\n options: Parameters<R['onAuth']>[1];\n constructor(\n cause: Error,\n message: string,\n client: Parameters<R['onAuth']>[0],\n options: Parameters<R['onAuth']>[1],\n ) {\n super(message, { cause });\n this.name = 'OnAuthException';\n this.client = client;\n this.options = options;\n }\n}\n\nexport class OnJoinException<R extends Room = Room> extends Error {\n client: Parameters<NonNullable<R['onJoin']>>[0];\n options: Parameters<NonNullable<R['onJoin']>>[1];\n auth: Parameters<NonNullable<R['onJoin']>>[2];\n constructor(\n cause: Error,\n message: string,\n client: Parameters<NonNullable<R['onJoin']>>[0],\n options: Parameters<NonNullable<R['onJoin']>>[1],\n auth: Parameters<NonNullable<R['onJoin']>>[2],\n ) {\n super(message, { cause });\n this.name = 'OnJoinException';\n this.client = client;\n this.options = options;\n this.auth = auth;\n }\n}\n\nexport class OnLeaveException<R extends Room = Room> extends Error {\n client: Parameters<NonNullable<R['onLeave']>>[0];\n consented: Parameters<NonNullable<R['onLeave']>>[1];\n constructor(\n cause: Error,\n message: string,\n client: Parameters<NonNullable<R['onLeave']>>[0],\n consented: Parameters<NonNullable<R['onLeave']>>[1],\n ) {\n super(message, { cause });\n this.name = 'OnLeaveException';\n this.client = client;\n this.consented = consented;\n }\n}\n\nexport class OnDropException<R extends Room = Room> extends Error {\n client: Parameters<NonNullable<R['onDrop']>>[0];\n code: Parameters<NonNullable<R['onDrop']>>[1];\n constructor(\n cause: Error,\n message: string,\n client: Parameters<NonNullable<R['onDrop']>>[0],\n code: Parameters<NonNullable<R['onDrop']>>[1],\n ) {\n super(message, { cause });\n this.name = 'OnDropException';\n this.client = client;\n this.code = code;\n }\n}\n\nexport class OnReconnectException<R extends Room = Room> extends Error {\n client: Parameters<NonNullable<R['onReconnect']>>[0];\n constructor(\n cause: Error,\n message: string,\n client: Parameters<NonNullable<R['onReconnect']>>[0],\n ) {\n super(message, { cause });\n this.name = 'OnReconnectException';\n this.client = client;\n }\n}\n\nexport class OnDisposeException extends Error {\n constructor(\n cause: Error,\n message: string,\n ) {\n super(message, { cause });\n this.name = 'OnDisposeException';\n }\n}\n\nexport class OnMessageException<R extends Room, MessageType extends keyof R['messages'] = keyof R['messages']> extends Error {\n client: R['~client'];\n payload: ExtractMessageType<R['messages'][MessageType]>;\n type: MessageType;\n constructor(\n cause: Error,\n message: string,\n client: R['~client'],\n payload: ExtractMessageType<R['messages'][MessageType]>,\n type: MessageType,\n ) {\n super(message, { cause });\n this.name = 'OnMessageException';\n this.client = client;\n this.payload = payload;\n this.type = type;\n }\n\n public isType<T extends keyof R['messages']>(type: T): this is OnMessageException<R, T> {\n return (this.type as string) === type;\n }\n}\n\n/** Thrown when a {@link Room.setTimestep} or {@link Room.setFixedTimestep} tick\n * callback throws (or rejects). Reported to `onUncaughtException` with the\n * originating method as `methodName` (`'setTimestep'` / `'setFixedTimestep'`). */\nexport class TimestepException extends Error {\n constructor(\n cause: Error,\n message: string,\n ) {\n super(message, { cause });\n this.name = 'TimestepException';\n }\n}\n\n/** \n * @deprecated Renamed to {@link TimestepException} (it now covers both\n * `setTimestep` and `setFixedTimestep`). Kept as an alias for backwards\n * compatibility \u2014 `instanceof` checks against either name still match. \n * \n * TODO: remove this on 1.0\n */\nexport const SimulationIntervalException = TimestepException;\nexport type SimulationIntervalException = TimestepException;\n\nexport class TimedEventException extends Error {\n public args: any[];\n constructor(\n cause: Error,\n message: string,\n ...args: any[]\n ) {\n super(message, { cause });\n this.name = 'TimedEventException';\n this.args = args;\n }\n}"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BO,IAAM,oBAAN,cAAuD,MAAM;AAAA,EAElE,YACE,OACA,SACA,SACA;AACA,UAAM,SAAS,EAAE,MAAM,CAAC;AACxB,SAAK,OAAO;AACZ,SAAK,UAAU;AAAA,EACjB;AACF;AAEO,IAAM,kBAAN,cAAqD,MAAM;AAAA,EAGhE,YACE,OACA,SACA,QACA,SACA;AACA,UAAM,SAAS,EAAE,MAAM,CAAC;AACxB,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,UAAU;AAAA,EACjB;AACF;AAEO,IAAM,kBAAN,cAAqD,MAAM;AAAA,EAIhE,YACE,OACA,SACA,QACA,SACA,MACA;AACA,UAAM,SAAS,EAAE,MAAM,CAAC;AACxB,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,UAAU;AACf,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,mBAAN,cAAsD,MAAM;AAAA,EAGjE,YACE,OACA,SACA,QACA,WACA;AACA,UAAM,SAAS,EAAE,MAAM,CAAC;AACxB,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,YAAY;AAAA,EACnB;AACF;AAEO,IAAM,kBAAN,cAAqD,MAAM;AAAA,EAGhE,YACE,OACA,SACA,QACA,MACA;AACA,UAAM,SAAS,EAAE,MAAM,CAAC;AACxB,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,uBAAN,cAA0D,MAAM;AAAA,EAErE,YACE,OACA,SACA,QACA;AACA,UAAM,SAAS,EAAE,MAAM,CAAC;AACxB,SAAK,OAAO;AACZ,SAAK,SAAS;AAAA,EAChB;AACF;AAEO,IAAM,qBAAN,cAAiC,MAAM;AAAA,EAC5C,YACE,OACA,SACA;AACA,UAAM,SAAS,EAAE,MAAM,CAAC;AACxB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,qBAAN,cAAgH,MAAM;AAAA,EAI3H,YACE,OACA,SACA,QACA,SACA,MACA;AACA,UAAM,SAAS,EAAE,MAAM,CAAC;AACxB,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,UAAU;AACf,SAAK,OAAO;AAAA,EACd;AAAA,EAEO,OAAsC,MAA2C;AACtF,WAAQ,KAAK,SAAoB;AAAA,EACnC;AACF;AAKO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAC3C,YACE,OACA,SACA;AACA,UAAM,SAAS,EAAE,MAAM,CAAC;AACxB,SAAK,OAAO;AAAA,EACd;AACF;AASO,IAAM,8BAA8B;AAGpC,IAAM,sBAAN,cAAkC,MAAM;AAAA,EAE7C,YACE,OACA,YACG,MACH;AACA,UAAM,SAAS,EAAE,MAAM,CAAC;AACxB,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/errors/SeatReservationError.ts"],
|
|
4
4
|
"sourcesContent": ["export class SeatReservationError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\n"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,IAAM,uBAAN,cAAmC,MAAM;AAAA,EAC9C,YAAY,SAAiB;AAC3B,UAAM,OAAO;AAAA,EACf;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/errors/ServerError.ts"],
|
|
4
4
|
"sourcesContent": ["import { ErrorCode } from '@colyseus/shared-types';\n\nexport class ServerError extends Error {\n public code: number;\n\n constructor(code: number = ErrorCode.MATCHMAKE_UNHANDLED, message?: string, options?: ErrorOptions) {\n super(message, options);\n\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ServerError);\n }\n\n this.name = 'ServerError';\n this.code = code;\n }\n}\n"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAA0B;AAEnB,IAAM,cAAN,MAAM,qBAAoB,MAAM;AAAA,EAGrC,YAAY,OAAe,8BAAU,qBAAqB,SAAkB,SAAwB;AAClG,UAAM,SAAS,OAAO;AAGtB,QAAI,MAAM,mBAAmB;AAC3B,YAAM,kBAAkB,MAAM,YAAW;AAAA,IAC3C;AAEA,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/index.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const __cjsImportMetaUrl = require('node:url').pathToFileURL(__filename).href;
|
|
1
2
|
"use strict";
|
|
2
3
|
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
@@ -69,6 +70,7 @@ __export(index_exports, {
|
|
|
69
70
|
basicAuth: () => import_router.basicAuth,
|
|
70
71
|
compileSanitizer: () => import_InputBuffer.compileSanitizer,
|
|
71
72
|
connectClientToRoom: () => import_Transport.connectClientToRoom,
|
|
73
|
+
createAuthContext: () => import_Transport.createAuthContext,
|
|
72
74
|
createEndpoint: () => import_router.createEndpoint,
|
|
73
75
|
createInternalContext: () => import_router.createInternalContext,
|
|
74
76
|
createMiddleware: () => import_router.createMiddleware,
|
|
@@ -97,6 +99,7 @@ __export(index_exports, {
|
|
|
97
99
|
matchMaker: () => matchMaker,
|
|
98
100
|
registerRoomDefinitions: () => import_Server.registerRoomDefinitions,
|
|
99
101
|
requestFromIPC: () => import_IPC.requestFromIPC,
|
|
102
|
+
runBeforeUpgrade: () => import_Transport.runBeforeUpgrade,
|
|
100
103
|
setDevMode: () => import_DevMode.setDevMode,
|
|
101
104
|
spliceOne: () => import_Utils.spliceOne,
|
|
102
105
|
subscribeIPC: () => import_IPC.subscribeIPC,
|
|
@@ -178,6 +181,7 @@ var import_Logger = require("./Logger.cjs");
|
|
|
178
181
|
basicAuth,
|
|
179
182
|
compileSanitizer,
|
|
180
183
|
connectClientToRoom,
|
|
184
|
+
createAuthContext,
|
|
181
185
|
createEndpoint,
|
|
182
186
|
createInternalContext,
|
|
183
187
|
createMiddleware,
|
|
@@ -206,6 +210,7 @@ var import_Logger = require("./Logger.cjs");
|
|
|
206
210
|
matchMaker,
|
|
207
211
|
registerRoomDefinitions,
|
|
208
212
|
requestFromIPC,
|
|
213
|
+
runBeforeUpgrade,
|
|
209
214
|
setDevMode,
|
|
210
215
|
spliceOne,
|
|
211
216
|
subscribeIPC,
|
package/build/index.cjs.map
CHANGED
|
@@ -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 ProtocolModifier,\n ErrorCode,\n CloseCode,\n ResponseStatus,\n type InferState,\n type ExtractRoomMessages,\n type ExtractRoomClientMessages,\n type MessageContext,\n type Rejection,\n type Resolution,\n type ExtractRejectReason,\n type ExtractResponseType,\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, RoomInternalState, validate, type RoomOptions, type DefineInputOptions, type SimulationCallback, type FixedTimestepCallback, type StepContext, type MessageHandlerWithFormat, type Messages, type ExtractRoomState, type ExtractRoomMetadata, type ExtractRoomClient } from './Room.ts';\nexport { InputBufferImpl, compileSanitizer } from './input/InputBuffer.ts';\nexport { type InputAccessor, type InputAPI, type NormalizedInputOptions, type ConsumeOptions, type IdleInput, type IdleContext, type SanitizeInput, type NumericFieldsOf } from './input/types.ts';\nexport { Rewind, RewindView, type RewindOptions, type RewindMode } from './Rewind.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 TimestepException,\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, enqueueClientRaw } 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": "
|
|
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 ProtocolModifier,\n ErrorCode,\n CloseCode,\n ResponseStatus,\n type InferState,\n type ExtractRoomMessages,\n type ExtractRoomClientMessages,\n type MessageContext,\n type Rejection,\n type Resolution,\n type ExtractRejectReason,\n type ExtractResponseType,\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, RoomInternalState, validate, type RoomOptions, type DefineInputOptions, type SimulationCallback, type FixedTimestepCallback, type StepContext, type MessageHandlerWithFormat, type Messages, type ExtractRoomState, type ExtractRoomMetadata, type ExtractRoomClient } from './Room.ts';\nexport { InputBufferImpl, compileSanitizer } from './input/InputBuffer.ts';\nexport { type InputAccessor, type InputAPI, type NormalizedInputOptions, type ConsumeOptions, type IdleInput, type IdleContext, type SanitizeInput, type NumericFieldsOf } from './input/types.ts';\nexport { Rewind, RewindView, type RewindOptions, type RewindMode } from './Rewind.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 TimestepException,\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, type BeforeUpgradeHandler, runBeforeUpgrade, createAuthContext, connectClientToRoom, enqueueClientRaw } 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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA6C;AAG7C,0BAcO;AAGP,oBAA8J;AAC9J,kBAA2R;AAC3R,yBAAkD;AAClD,mBAAgL;AAChL,oBAAwE;AACxE,wBAGO;AACP,sBAAgC;AAChC,+BAAkC;AAClC,yBAA4B;AAE5B,4BAYO;AAGP,iBAA4B;AAE5B,mBAA4C;AAC5C,kBAAgD;AAGhD,0BAAc,qDAtDd;AAuDA,oBAAoC;AAGpC,uBAAiO;AAGjO,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
|
@@ -16,7 +16,7 @@ export { updateLobby, subscribeLobby } from './matchmaker/Lobby.ts';
|
|
|
16
16
|
export { createNodeMatchmakingMiddleware } from './router/node.ts';
|
|
17
17
|
export * from './matchmaker/LocalDriver/LocalDriver.ts';
|
|
18
18
|
export { initializeRoomCache } from './matchmaker/driver.ts';
|
|
19
|
-
export { type Client, type ClientPrivate, type AuthContext, ClientState, ClientArray, Transport, type ISendOptions, connectClientToRoom, enqueueClientRaw } from './Transport.ts';
|
|
19
|
+
export { type Client, type ClientPrivate, type AuthContext, ClientState, ClientArray, Transport, type ISendOptions, type BeforeUpgradeHandler, runBeforeUpgrade, createAuthContext, connectClientToRoom, enqueueClientRaw } from './Transport.ts';
|
|
20
20
|
export { type Presence } from './presence/Presence.ts';
|
|
21
21
|
export { LocalPresence } from './presence/LocalPresence.ts';
|
|
22
22
|
export { type Serializer } from './serializer/Serializer.ts';
|
package/build/index.mjs
CHANGED
|
@@ -36,7 +36,7 @@ import { updateLobby, subscribeLobby } from "./matchmaker/Lobby.mjs";
|
|
|
36
36
|
import { createNodeMatchmakingMiddleware } from "./router/node.mjs";
|
|
37
37
|
export * from "./matchmaker/LocalDriver/LocalDriver.mjs";
|
|
38
38
|
import { initializeRoomCache } from "./matchmaker/driver.mjs";
|
|
39
|
-
import { ClientState, ClientArray, Transport, connectClientToRoom, enqueueClientRaw } from "./Transport.mjs";
|
|
39
|
+
import { ClientState, ClientArray, Transport, runBeforeUpgrade, createAuthContext, connectClientToRoom, enqueueClientRaw } from "./Transport.mjs";
|
|
40
40
|
import {} from "./presence/Presence.mjs";
|
|
41
41
|
import { LocalPresence } from "./presence/LocalPresence.mjs";
|
|
42
42
|
import {} from "./serializer/Serializer.mjs";
|
|
@@ -106,6 +106,7 @@ export {
|
|
|
106
106
|
basicAuth,
|
|
107
107
|
compileSanitizer,
|
|
108
108
|
connectClientToRoom,
|
|
109
|
+
createAuthContext,
|
|
109
110
|
createEndpoint,
|
|
110
111
|
createInternalContext,
|
|
111
112
|
createMiddleware,
|
|
@@ -134,6 +135,7 @@ export {
|
|
|
134
135
|
matchMaker,
|
|
135
136
|
registerRoomDefinitions,
|
|
136
137
|
requestFromIPC,
|
|
138
|
+
runBeforeUpgrade,
|
|
137
139
|
setDevMode,
|
|
138
140
|
spliceOne,
|
|
139
141
|
subscribeIPC,
|
package/build/index.mjs.map
CHANGED
|
@@ -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 ProtocolModifier,\n ErrorCode,\n CloseCode,\n ResponseStatus,\n type InferState,\n type ExtractRoomMessages,\n type ExtractRoomClientMessages,\n type MessageContext,\n type Rejection,\n type Resolution,\n type ExtractRejectReason,\n type ExtractResponseType,\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, RoomInternalState, validate, type RoomOptions, type DefineInputOptions, type SimulationCallback, type FixedTimestepCallback, type StepContext, type MessageHandlerWithFormat, type Messages, type ExtractRoomState, type ExtractRoomMetadata, type ExtractRoomClient } from './Room.ts';\nexport { InputBufferImpl, compileSanitizer } from './input/InputBuffer.ts';\nexport { type InputAccessor, type InputAPI, type NormalizedInputOptions, type ConsumeOptions, type IdleInput, type IdleContext, type SanitizeInput, type NumericFieldsOf } from './input/types.ts';\nexport { Rewind, RewindView, type RewindOptions, type RewindMode } from './Rewind.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 TimestepException,\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, enqueueClientRaw } from './Transport.ts';\n\n// Presence\nexport { type Presence } from './presence/Presence.ts';\nexport { LocalPresence } from './presence/LocalPresence.ts';\n\n// Serializers\nexport { type Serializer } from './serializer/Serializer.ts';\nexport { SchemaSerializer } from './serializer/SchemaSerializer.ts';\n\n// Utilities\nexport { Clock, Delayed };\nexport { generateId, Deferred, spliceOne, getBearerToken, dynamicImport } from './utils/Utils.ts';\nexport { isDevMode, setDevMode } from './utils/DevMode.ts';\n\n// IPC\nexport { subscribeIPC, requestFromIPC } from './IPC.ts';\n\n// Debug\nexport {\n debugMatchMaking,\n debugMessage,\n debugPatch,\n debugError,\n debugConnection,\n debugDriver,\n debugPresence,\n debugAndPrintError,\n} from './Debug.ts';\n\n// Default rooms\nexport { LobbyRoom } from './rooms/LobbyRoom.ts';\nexport { RelayRoom } from './rooms/RelayRoom.ts';\nexport { QueueRoom, type QueueOptions, type QueueMatchGroup, type QueueMatchTeam, type QueueClientData } from './rooms/QueueRoom.ts';\n\n// Router / Endpoints\nexport {\n createEndpoint,\n createInternalContext,\n createMiddleware,\n createRouter,\n basicAuth,\n type BasicAuthOptions,\n toNodeHandler,\n dualModeEndpoints,\n type Router,\n type RouterConfig,\n type Endpoint,\n type EndpointHandler,\n type EndpointOptions,\n type EndpointContext,\n type StrictEndpoint,\n type ExpressMiddleware,\n type NodeHandler,\n type DualModeHelpers,\n} from './router/index.ts';\n\n// Abstract logging support\nexport { logger } from './Logger.ts';\n"],
|
|
5
|
-
"mappings": ";AAAA,SAAS,cAAc,OAAO,eAAe;AAG7C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OASK;AAGP,SAAS,QAAQ,YAAY,cAAc,yBAAyB,iCAA0F;AAC9J,SAAS,MAAM,mBAAmB,gBAAyP;AAC3R,SAAS,iBAAiB,wBAAwB;AAClD,eAAgL;AAChL,SAAS,QAAQ,kBAAuD;AACxE;AAAA,EACE;AAAA,EAAY;AAAA,EAAe;AAAA,OAEtB;AACP,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAClC,SAAS,mBAAmB;AAE5B;AAAA,EAGE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,YAAY,gBAAgB;AAE5B,SAAS,aAAa,sBAAsB;AAC5C,SAAS,uCAAuC;AAGhD,cAAc;AACd,SAAS,2BAA2B;AAGpC,SAA4D,aAAa,aAAa,
|
|
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 ProtocolModifier,\n ErrorCode,\n CloseCode,\n ResponseStatus,\n type InferState,\n type ExtractRoomMessages,\n type ExtractRoomClientMessages,\n type MessageContext,\n type Rejection,\n type Resolution,\n type ExtractRejectReason,\n type ExtractResponseType,\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, RoomInternalState, validate, type RoomOptions, type DefineInputOptions, type SimulationCallback, type FixedTimestepCallback, type StepContext, type MessageHandlerWithFormat, type Messages, type ExtractRoomState, type ExtractRoomMetadata, type ExtractRoomClient } from './Room.ts';\nexport { InputBufferImpl, compileSanitizer } from './input/InputBuffer.ts';\nexport { type InputAccessor, type InputAPI, type NormalizedInputOptions, type ConsumeOptions, type IdleInput, type IdleContext, type SanitizeInput, type NumericFieldsOf } from './input/types.ts';\nexport { Rewind, RewindView, type RewindOptions, type RewindMode } from './Rewind.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 TimestepException,\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, type BeforeUpgradeHandler, runBeforeUpgrade, createAuthContext, connectClientToRoom, enqueueClientRaw } from './Transport.ts';\n\n// Presence\nexport { type Presence } from './presence/Presence.ts';\nexport { LocalPresence } from './presence/LocalPresence.ts';\n\n// Serializers\nexport { type Serializer } from './serializer/Serializer.ts';\nexport { SchemaSerializer } from './serializer/SchemaSerializer.ts';\n\n// Utilities\nexport { Clock, Delayed };\nexport { generateId, Deferred, spliceOne, getBearerToken, dynamicImport } from './utils/Utils.ts';\nexport { isDevMode, setDevMode } from './utils/DevMode.ts';\n\n// IPC\nexport { subscribeIPC, requestFromIPC } from './IPC.ts';\n\n// Debug\nexport {\n debugMatchMaking,\n debugMessage,\n debugPatch,\n debugError,\n debugConnection,\n debugDriver,\n debugPresence,\n debugAndPrintError,\n} from './Debug.ts';\n\n// Default rooms\nexport { LobbyRoom } from './rooms/LobbyRoom.ts';\nexport { RelayRoom } from './rooms/RelayRoom.ts';\nexport { QueueRoom, type QueueOptions, type QueueMatchGroup, type QueueMatchTeam, type QueueClientData } from './rooms/QueueRoom.ts';\n\n// Router / Endpoints\nexport {\n createEndpoint,\n createInternalContext,\n createMiddleware,\n createRouter,\n basicAuth,\n type BasicAuthOptions,\n toNodeHandler,\n dualModeEndpoints,\n type Router,\n type RouterConfig,\n type Endpoint,\n type EndpointHandler,\n type EndpointOptions,\n type EndpointContext,\n type StrictEndpoint,\n type ExpressMiddleware,\n type NodeHandler,\n type DualModeHelpers,\n} from './router/index.ts';\n\n// Abstract logging support\nexport { logger } from './Logger.ts';\n"],
|
|
5
|
+
"mappings": ";AAAA,SAAS,cAAc,OAAO,eAAe;AAG7C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OASK;AAGP,SAAS,QAAQ,YAAY,cAAc,yBAAyB,iCAA0F;AAC9J,SAAS,MAAM,mBAAmB,gBAAyP;AAC3R,SAAS,iBAAiB,wBAAwB;AAClD,eAAgL;AAChL,SAAS,QAAQ,kBAAuD;AACxE;AAAA,EACE;AAAA,EAAY;AAAA,EAAe;AAAA,OAEtB;AACP,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAClC,SAAS,mBAAmB;AAE5B;AAAA,EAGE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,YAAY,gBAAgB;AAE5B,SAAS,aAAa,sBAAsB;AAC5C,SAAS,uCAAuC;AAGhD,cAAc;AACd,SAAS,2BAA2B;AAGpC,SAA4D,aAAa,aAAa,WAAyD,kBAAkB,mBAAmB,qBAAqB,wBAAwB;AAGjO,eAA8B;AAC9B,SAAS,qBAAqB;AAG9B,eAAgC;AAChC,SAAS,wBAAwB;AAIjC,SAAS,YAAY,UAAU,WAAW,gBAAgB,qBAAqB;AAC/E,SAAS,WAAW,kBAAkB;AAGtC,SAAS,cAAc,sBAAsB;AAG7C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,iBAAiB;AAC1B,SAAS,iBAAiB;AAC1B,SAAS,iBAAqG;AAG9G;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,OAWK;AAGP,SAAS,cAAc;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/input/InputBuffer.ts"],
|
|
4
4
|
"sourcesContent": ["import type { ClientPrivate } from '../Transport.ts';\nimport { $METADATA } from '../utils/Utils.ts';\n\nimport type {\n ConsumeOptions, IdleContext, IdleInput, InputAccessor, SanitizeInput,\n} from './types.ts';\n\n/**\n * @internal Validate a `subSteps` count. Throws on a fractional/non-positive\n * value: both sides loop `subSteps` times at `dt/subSteps`, so anything but a\n * whole number is a determinism bug, not a tunable. Shared by `defineInput`\n * and `setFixedTimestep`.\n */\nexport function validateSubSteps(subSteps: number | undefined, source: string): number | undefined {\n if (subSteps === undefined) { return undefined; }\n if (!Number.isInteger(subSteps) || subSteps < 1) {\n throw new Error(`[${source}] subSteps must be an integer >= 1 (got ${subSteps}).`);\n }\n return subSteps;\n}\n\n/**\n * @internal Compile a {@link SanitizeInput} spec into the per-frame function the\n * decode path applies. The map form precompiles to dense min/max arrays walked\n * with the NaN-safe branch clamp; the callback form passes through.\n */\nexport function compileSanitizer<I>(spec: SanitizeInput<I>): (input: I) => void {\n if (typeof spec === 'function') { return spec; }\n const names = Object.keys(spec);\n const mins = new Float64Array(names.length);\n const maxs = new Float64Array(names.length);\n for (let i = 0; i < names.length; i++) {\n const range = (spec as Record<string, readonly [number, number]>)[names[i]]!;\n mins[i] = range[0];\n maxs[i] = range[1];\n }\n return (input: I) => {\n const inst = input as Record<string, number>;\n for (let i = 0; i < names.length; i++) {\n const v = inst[names[i]];\n // Never-received field: no input to sanitize \u2014 clamping would INVENT\n // one (delta-encoding clients legitimately never transmit fields they\n // never assigned; the range floor turned \"no input\" into \"held stick\").\n if (v === undefined) { continue; }\n // NaN-safe: NaN fails both comparisons \u2192 clamp floor.\n inst[names[i]] = v >= mins[i] ? (v <= maxs[i] ? v : maxs[i]) : mins[i];\n }\n };\n}\n\n/** Field names of an input schema ctor, in declaration order (indices are dense\n * from 0 in the metadata). Resolved ONCE per buffer (cold path). */\nfunction fieldNamesOf(ctor: new () => any): string[] {\n const md = (ctor as any)[$METADATA] as Record<number, { name?: string }> | undefined;\n const names: string[] = [];\n if (md) {\n for (let i = 0; ; i++) {\n const f = md[i];\n if (!f || typeof f.name !== \"string\") break;\n names.push(f.name);\n }\n }\n return names;\n}\n\n/**\n * @internal Seed every declared field that has no construction default with\n * its wire-neutral zero value (0 / false / \"\"; quantized: 0 clamped into the\n * descriptor's range). The input contract is \"the server holds the last\n * received value\" \u2014 before anything is received, that value is the ZERO of\n * the field's type, never `undefined`: a sim would NaN-propagate it and a\n * range sanitizer would clamp it into a phantom input. Clients only transmit\n * fields they assign, so an untouched field stays absent on the wire forever.\n */\nexport function seedInputZeroValues(instance: any, ctor: new () => any): void {\n const md = (ctor as any)[$METADATA] as\n Record<number, { name?: string, type?: unknown }> | undefined;\n if (!md) { return; }\n for (let i = 0; ; i++) {\n const f = md[i];\n if (!f || typeof f.name !== \"string\") break;\n if (instance[f.name] !== undefined) { continue; } // .default() wins\n const type = f.type;\n if (typeof type === \"string\") {\n instance[f.name] = type === \"string\" ? \"\" : type === \"boolean\" ? false : 0;\n } else if (type !== null && typeof type === \"object\" && \"quantized\" in (type as object)) {\n const q = (type as { quantized: { min: number, max: number } }).quantized;\n instance[f.name] = q.min > 0 ? q.min : q.max < 0 ? q.max : 0;\n }\n }\n}\n\n/** Reclaim the consumed prefix once the read cursor passes this many items \u2014\n * bounds the parallel arrays' slack to O(THRESHOLD) between compactions while\n * keeping per-consume work O(1) (no `shift()` re-index on every input). */\nconst COMPACT_THRESHOLD = 32;\n\n/** Shared zero-state \"already done\" iterator \u2014 returned by `consume()` on an\n * empty buffer with no idle policy, and by the no-op accessor. Frozen + a frozen\n * result, so it's allocation-free and safe to share across all callers. */\nconst DONE_RESULT: IteratorResult<any> = Object.freeze({ value: undefined, done: true });\nconst DONE_ITERATOR: IterableIterator<any> = Object.freeze({\n [Symbol.iterator]() { return this; },\n next() { return DONE_RESULT; },\n});\n\n/** @internal */\nexport class InputBufferImpl<I = any> {\n /** Pending snapshots, indexed `[_head, _items.length)`. Consumed inputs are\n * NOT spliced off per-read \u2014 `_head` advances and the prefix is reclaimed in\n * bulk by {@link compact} (a `shift()` per read is O(n), so a burst would be\n * O(n\u00B2)). `_renderTimes`/`_reckonTimes` stay parallel to `_items`. */\n private _items: I[] = [];\n /** Read cursor: index of the oldest UNCONSUMED input (== `_items.length` when empty). */\n private _head = 0;\n private _lastSeq: number = -Infinity;\n private readonly _maxSize: number;\n private readonly _seqField: string | undefined;\n\n /**\n * Cumulative count of inputs CONSUMED from this buffer (via any consume\n * primitive \u2014 {@link next}/{@link take}/{@link drain}/{@link consume} \u2014 plus\n * {@link clear} and overflow). Consumed = \"removed from the pending set\",\n * whether applied to state or discarded. The server echoes this in the TIMED\n * prefix as the reconciliation ack: how many of the client's inputs are\n * reflected in (or finished influencing) the authoritative state, which lags\n * the receive counter by inputs still buffered. Distinct from\n * `_receivedInputCount` (receive-time, for RTT), which leads the state.\n */\n consumedCount = 0;\n\n /** Render times parallel to `_items` (server-clock ms; `0` when unset). */\n private _renderTimes: number[] = [];\n /** Render time of the most recently drained input (see {@link renderTime}). */\n private _lastRenderTime = 0;\n /** Reckon-display stamps parallel to `_items` \u2014 the client's serverNow\n * estimate at input-sample time, i.e. the instant its forward-reckoned\n * entities were displayed at (server-clock ms; `0` when unset). */\n private _reckonTimes: number[] = [];\n /** Reckon stamp of the most recently consumed input (see {@link reckonTime}). */\n private _lastReckonTime = 0;\n /** Framework wire seq per buffered input (parallel to `_items`) \u2014 UNRELIABLE\n * ONLY, lazily created on the first seq-carrying push. Reliable inputs are\n * contiguous, so their consumed-seq-value is always exactly {@link consumedCount}\n * and needs no parallel array; `undefined` here marks that (the common, default\n * path pays nothing). A buffer is single-mode, so this is either never created\n * (reliable) or created once and kept parallel (unreliable). */\n private _seqs?: number[];\n /** Seq VALUE of the last consumed input \u2014 the reconciliation ack echoed to the\n * client (see {@link ackSeq}). Only meaningful when {@link _seqs} is tracked\n * (unreliable); reliable's ack falls back to {@link consumedCount}. */\n private _lastConsumedSeq = 0;\n /** Whether the most recently produced frame was a synthesized idle (see {@link wasIdle}). */\n private _lastWasIdle = false;\n\n /** Reused {@link consume} iterator (lazily minted) + its per-call state, so a\n * per-tick loop allocates no generator frame. `_iterRemaining` snapshots the\n * COUNT to walk \u2014 a count, not an index: mid-pass mutations (`next()`/`take()`/\n * `clear()`/compaction) shift indices but can only shorten a count-based pass,\n * never point it past the tail. `_iterIdle` is an optional trailing synthesized\n * frame; `_iterActive` guards against a nested consume() clobbering the shared\n * `_iterRes`. */\n private _iter?: IterableIterator<I>;\n private _iterRemaining = 0;\n private _iterActive = false;\n private _iterIdle?: I;\n private readonly _iterRes: { value: I | undefined; done: boolean } = { value: undefined, done: false };\n\n /** Input schema ctor \u2014 mints the reused idle frame; idle is off without it. */\n private readonly _ctor?: new () => I;\n /** Client slice this buffer belongs to (the live object is `Client & ClientPrivate`)\n * \u2014 feeds the idle callback's ctx (latest + sessionId). */\n private readonly _client?: Pick<ClientPrivate, '_input'> & { sessionId: string };\n /** Room-level idle policy (`defineInput({ idle })`) \u2014 the bare-call default. */\n private readonly _roomIdle?: IdleInput<I>;\n /** Reused synthesized idle frame + the schema's field names/defaults (lazy). */\n private _idle?: I;\n private _fieldNames?: string[];\n private _defaults?: unknown[];\n /** Reused ctx for the idle callback form (see {@link IdleContext}). */\n private readonly _idleCtx: IdleContext<I> = { latest: undefined, sessionId: \"\" };\n\n constructor(maxSize: number, seqField: string | undefined, ctor?: new () => I, client?: Pick<ClientPrivate, '_input'> & { sessionId: string }, idle?: IdleInput<I>) {\n this._maxSize = maxSize;\n this._seqField = seqField;\n this._ctor = ctor;\n this._client = client;\n this._roomIdle = idle;\n }\n\n /** The effective idle policy for one consume call: per-call `false` suppresses,\n * per-call value overrides, else the room-level default (or none). */\n private effectiveIdle(opts?: ConsumeOptions<I>): IdleInput<I> | undefined {\n return opts?.idle === false ? undefined : (opts?.idle ?? this._roomIdle);\n }\n\n /** Resolve an {@link IdleInput} to overrides \u2014 invokes the callback form\n * LAZILY, here at synthesis time (the buffer is known to be empty). */\n private resolveIdle(idle: IdleInput<I>): true | Partial<I> {\n if (typeof idle !== \"function\") return idle;\n this._idleCtx.latest = this._client?._input as I | undefined;\n this._idleCtx.sessionId = this._client?.sessionId ?? \"\";\n return idle(this._idleCtx) ?? true;\n }\n\n /**\n * The synthesized \"no input this tick\" frame: schema defaults overlaid with\n * `overrides` (`true` = none). Copies BY FIELD NAME from the schema metadata \u2014\n * schema fields are prototype accessors (no own props), so `Object.assign`\n * can't source from a schema instance; the name walk reads getters, letting\n * `overrides` be a plain partial OR a schema instance (e.g. `latest`).\n * ONE reused instance \u2014 refilled per call, never advances the ack.\n */\n private idleFrame(overrides: true | Partial<I>): I {\n if (this._idle === undefined) {\n // Lazy mint (cold): the fresh instance doubles as the defaults source.\n this._idle = new this._ctor!();\n seedInputZeroValues(this._idle, this._ctor!);\n this._fieldNames = fieldNamesOf(this._ctor!);\n const fresh = this._idle as Record<string, unknown>;\n this._defaults = this._fieldNames.map((n) => fresh[n]);\n }\n const idle = this._idle as Record<string, unknown>;\n const names = this._fieldNames!;\n const defaults = this._defaults!;\n const ov = overrides === true ? undefined : (overrides as Record<string, unknown>);\n for (let i = 0; i < names.length; i++) {\n const v = ov?.[names[i]];\n idle[names[i]] = v !== undefined ? v : defaults[i];\n }\n return this._idle;\n }\n\n /** The idle frame to synthesize on an empty tick (room policy or per-call\n * `opts.idle`), or `undefined` when no policy is in effect. Reuses the single\n * idle instance; never advances the ack. Callers set {@link wasIdle}. */\n private idleFrameOnEmpty(opts?: ConsumeOptions<I>): I | undefined {\n const idle = this._ctor !== undefined ? this.effectiveIdle(opts) : undefined;\n return idle === undefined ? undefined : this.idleFrame(this.resolveIdle(idle));\n }\n\n /** Consume the input at the cursor: advance cursor + ack, stamp THIS input's\n * render/reckon times, clear {@link wasIdle}. The shared per-input step behind\n * {@link next}, {@link consume}'s iterator, and the re-entrant fallback. */\n private stepHead(): I {\n const i = this._head;\n this._lastWasIdle = false;\n this._lastRenderTime = this._renderTimes[i];\n this._lastReckonTime = this._reckonTimes[i];\n if (this._seqs !== undefined) { this._lastConsumedSeq = this._seqs[i]; }\n this._head = i + 1;\n this.consumedCount++;\n return this._items[i];\n }\n\n /** Drop ALL slots, reusing the backing arrays' capacity \u2014 the zero-GC reset for\n * the consume/next path ({@link compact}/{@link clear}). `drain()` deliberately\n * does NOT use this (it returns an array, so fresh `[]` is faster there). */\n private truncate(): void {\n this._items.length = 0;\n this._renderTimes.length = 0;\n this._reckonTimes.length = 0;\n if (this._seqs !== undefined) { this._seqs.length = 0; }\n this._head = 0;\n }\n\n /**\n * Append a decoded input snapshot. `seq` is the framework wire seq (unreliable);\n * omit it for reliable inputs, which get an implicit monotonic receive count so\n * {@link ackSeq} stays well-defined in both modes.\n */\n push(snapshot: I, renderTime: number = 0, reckonTime: number = 0, seq?: number): void {\n this._items.push(snapshot);\n this._renderTimes.push(renderTime);\n this._reckonTimes.push(reckonTime);\n // Track the wire seq only for unreliable (seq provided); reliable derives its\n // ack from consumedCount, so it never allocates/maintains this array.\n if (seq !== undefined) { (this._seqs ??= []).push(seq); }\n // Overflow drops the oldest unconsumed input; count it consumed so the ack\n // still advances past it. Advance the cursor (don't shift) \u2014 keeps it O(1).\n if (this.size > this._maxSize) {\n if (this._seqs !== undefined) { this._lastConsumedSeq = this._seqs[this._head]; } // dropped oldest counts as acked\n this._head++;\n this.consumedCount++;\n this.compact();\n }\n }\n\n /** Reclaim the consumed prefix `[0, _head)`. Free when fully drained (reuse the\n * arrays); otherwise splice only once the cursor passes {@link COMPACT_THRESHOLD},\n * so the amortized per-input cost stays O(1). */\n private compact(): void {\n if (this._head === 0) { return; }\n if (this._head >= this._items.length) {\n this.truncate();\n } else if (this._head >= COMPACT_THRESHOLD) {\n this._items.splice(0, this._head);\n this._renderTimes.splice(0, this._head);\n this._reckonTimes.splice(0, this._head);\n if (this._seqs !== undefined) { this._seqs.splice(0, this._head); }\n this._head = 0;\n }\n }\n\n /** Returns true if `value` hasn't been seen, and updates the last-seen marker. */\n accept(value: number): boolean {\n if (value <= this._lastSeq) { return false; }\n this._lastSeq = value;\n return true;\n }\n\n drain(opts?: ConsumeOptions<I>): I[] {\n // Empty: synthesize one idle frame (NOT consumed \u2014 no ack bump, stamps\n // untouched) when a policy is in effect, else [].\n if (this.size === 0) {\n const idle = this.idleFrameOnEmpty(opts);\n this._lastWasIdle = idle !== undefined;\n return idle !== undefined ? [idle] : [];\n }\n this._lastWasIdle = false;\n const last = this._items.length - 1;\n this._lastRenderTime = this._renderTimes[last]; // drain reports the NEWEST stamps\n this._lastReckonTime = this._reckonTimes[last];\n if (this._seqs !== undefined) { this._lastConsumedSeq = this._seqs[last]; }\n // Hand off the backing array untouched when nothing was partially consumed\n // (O(1) \u2014 the caller may retain it); else copy out the unconsumed tail. Fresh\n // arrays here, NOT truncate(): drain already allocates the returned array, and\n // V8 makes `= []` + refill cheaper than `length = 0` reuse (~1.8\u00D7 at small N),\n // so the speed wins and the 3 tiny empties are negligible next to the return.\n const out = this._head === 0 ? this._items : this._items.slice(this._head);\n this.consumedCount += out.length;\n this._items = [];\n this._renderTimes = [];\n this._reckonTimes = [];\n if (this._seqs !== undefined) { this._seqs = []; }\n this._head = 0;\n return out;\n }\n\n /** Consume the single oldest input (ack advances by one); `undefined` if\n * empty \u2014 or the synthesized idle frame when an idle policy is in effect. */\n next(opts?: ConsumeOptions<I>): I | undefined {\n if (this.size === 0) {\n const idle = this.idleFrameOnEmpty(opts);\n this._lastWasIdle = idle !== undefined;\n return idle;\n }\n const item = this.stepHead();\n this.compact();\n return item;\n }\n\n /** Consume up to `n` oldest inputs (ack advances by the count actually taken). */\n take(n: number): I[] {\n this._lastWasIdle = false; // take never synthesizes idle\n const avail = this.size;\n if (n <= 0 || avail === 0) { return []; }\n const count = Math.min(n, avail);\n const start = this._head;\n const out = this._items.slice(start, start + count);\n this._lastRenderTime = this._renderTimes[start + count - 1]; // newest taken input's stamps\n this._lastReckonTime = this._reckonTimes[start + count - 1];\n if (this._seqs !== undefined) { this._lastConsumedSeq = this._seqs[start + count - 1]; }\n this._head += count;\n this.consumedCount += count;\n this.compact();\n return out;\n }\n\n /**\n * Iterate pending inputs one at a time (per-yield ack + stamp updates), or\n * exactly one synthesized idle frame on an empty buffer with a policy in\n * effect. See {@link InputAccessor.consume}.\n *\n * Returns a POOLED iterator (reused across calls \u2014 no generator frame, no\n * per-call allocation) that consumes at most the pending count snapshotted at\n * the call \u2014 never past the live tail \u2014 plus one optional trailing idle frame.\n * The cursor advances per `next()`, so `break` (which calls `return()`)\n * leaves the rest buffered and compacts. A nested\n * `consume()` of the SAME buffer while one is live falls back to a fresh\n * generator so the pooled `_iterRes` isn't clobbered (nesting is meaningless \u2014\n * both share the cursor \u2014 but it must not corrupt).\n */\n consume(opts?: ConsumeOptions<I>): IterableIterator<I> {\n const empty = this.size === 0;\n const idle = empty ? this.idleFrameOnEmpty(opts) : undefined;\n if (empty && idle === undefined) { this._lastWasIdle = false; return DONE_ITERATOR as IterableIterator<I>; }\n // A nested consume() of this same buffer would clobber the pooled iterator's\n // shared state \u2192 hand the rare case a fresh generator instead.\n if (this._iterActive) { return this.consumeGen(idle); }\n this._iterActive = true;\n this._iterIdle = idle; // one trailing idle frame, or undefined\n this._iterRemaining = this.size; // count snapshot \u2014 a (hypothetical) mid-loop push isn't consumed this pass\n return this.ensureIter();\n }\n\n [Symbol.iterator](): IterableIterator<I> {\n return this.consume();\n }\n\n /** Lazily mint the reused iterator. Closures over `this` so it reads the\n * private cursor directly; one `_iterRes` is reused \u2014 read each result before\n * the next `next()`, as `for..of` / spread / `Array.from` all do. */\n private ensureIter(): IterableIterator<I> {\n if (this._iter !== undefined) { return this._iter; }\n const self = this;\n const res = this._iterRes;\n const finish = (): IteratorResult<I> => {\n self.compact();\n self._iterActive = false;\n self._iterRemaining = 0;\n self._iterIdle = undefined;\n res.value = undefined;\n res.done = true;\n return res as IteratorResult<I>;\n };\n this._iter = {\n [Symbol.iterator]() { return this; },\n next(): IteratorResult<I> {\n // `size > 0` re-checks the live tail: a mid-loop next()/take()/clear()\n // can only shorten the pass, never make it read past the end.\n if (self._iterRemaining > 0 && self.size > 0) { // a buffered input\n self._iterRemaining--;\n res.value = self.stepHead();\n res.done = false;\n return res as IteratorResult<I>;\n }\n if (self._iterIdle !== undefined) { // one trailing idle frame\n self._lastWasIdle = true;\n res.value = self._iterIdle;\n self._iterIdle = undefined;\n res.done = false;\n return res as IteratorResult<I>;\n }\n return finish();\n },\n return(): IteratorResult<I> { return finish(); }, // `break` \u2192 compact + release\n };\n return this._iter;\n }\n\n /** Re-entrant fallback: a fresh generator for a nested `consume()` of this same\n * buffer (the pooled iterator is single-active). Same accounting + compaction. */\n private *consumeGen(idleFrame: I | undefined): IterableIterator<I> {\n let remaining = this.size; // count-based walk, same reason as the pooled pass\n try {\n while (remaining-- > 0 && this.size > 0) { yield this.stepHead(); }\n if (idleFrame !== undefined) { this._lastWasIdle = true; yield idleFrame; }\n } finally {\n this.compact();\n }\n }\n\n peek(): I[] {\n return this._items.slice(this._head);\n }\n\n at(value: number): I | undefined {\n if (this._seqField === undefined) { return undefined; }\n for (let i = this._head; i < this._items.length; i++) {\n if ((this._items[i] as any)[this._seqField] === value) { return this._items[i]; }\n }\n return undefined;\n }\n\n get size(): number {\n return this._items.length - this._head;\n }\n\n /** Render time (server-clock ms) of the most recently drained input; `0`\n * until the first render-time-stamped input is drained. */\n get renderTime(): number {\n return this._lastRenderTime;\n }\n\n /** Reckon-display stamp of the most recently consumed input \u2014 the client's\n * serverNow estimate when it sampled that input, i.e. the EXACT instant its\n * forward-reckoned entities were displayed at. Same consume semantics as\n * {@link renderTime}. RAW: stays `0` until stamped \u2014 the resolved,\n * always-usable value is the accessor's `reckonTime`\n * (`room.inputs.get(sid)`); `rewind.lastSeenBy()`'s midpoint-reconstruction\n * fallback depends on this raw `0`. */\n get reckonTime(): number {\n return this._lastReckonTime;\n }\n\n /** Seq VALUE of the last consumed input \u2014 the reconciliation ack sent to the\n * client. Reliable (no wire seq tracked): falls back to {@link consumedCount}\n * for free. Unreliable: the framework wire seq, so a fully-dropped input doesn't\n * make the ack lag the client's sent seq by the lost count. `0` before the first\n * consume. */\n get ackSeq(): number {\n return this._seqs !== undefined ? this._lastConsumedSeq : this.consumedCount;\n }\n\n /** Whether the most recently produced frame was a synthesized idle (see {@link wasIdle}). */\n get wasIdle(): boolean {\n return this._lastWasIdle;\n }\n\n clear(): void {\n // Cleared inputs count as consumed: advance both the count and the seq-value ack\n // past them so the client's pending set drains (capture the newest seq before truncate).\n if (this._seqs !== undefined && this._items.length > 0) { this._lastConsumedSeq = this._seqs[this._items.length - 1]; }\n this.consumedCount += this.size;\n this.truncate();\n this._lastSeq = -Infinity;\n this._iterActive = false; // recovery hatch if a consume() iterator was abandoned unclosed\n this._iterRemaining = 0; // an abandoned iterator must not consume post-clear pushes\n this._iterIdle = undefined;\n }\n}\n\n/**\n * Default per-client accessor. Reads `_input` and `_inputBuffer` off the\n * client at access time \u2014 both are nullable until the room declares input\n * via `defineInput()`. Cached as `client._inputAccessor` at join, so\n * `room.inputs.get(sessionId)` is a Map lookup + property read.\n *\n * @internal\n */\nexport class InputAccessorImpl<I = any> implements InputAccessor<I> {\n private _client: ClientPrivate;\n /** Current room time (`clock.elapsedTime`) \u2014 resolves the {@link reckonTime}\n * fallback. Threaded by `RoomInput.allocate()`; optional so bare\n * constructions (tests) keep the raw 0. */\n private _nowOf?: () => number;\n constructor(client: ClientPrivate, nowOf?: () => number) {\n this._client = client;\n this._nowOf = nowOf;\n }\n get latest(): I | undefined { return this._client._input as I | undefined; }\n at(value: number): I | undefined { return this._client._inputBuffer?.at(value) as I | undefined; }\n consume(opts?: ConsumeOptions<I>): IterableIterator<I> {\n return (this._client._inputBuffer?.consume(opts) ?? DONE_ITERATOR) as IterableIterator<I>;\n }\n [Symbol.iterator](): IterableIterator<I> { return this.consume(); }\n drain(opts?: ConsumeOptions<I>): I[] { return (this._client._inputBuffer?.drain(opts) ?? []) as I[]; }\n next(): I | undefined;\n next(opts: { idle: IdleInput<I> }): I;\n next(opts?: ConsumeOptions<I>): I | undefined { return this._client._inputBuffer?.next(opts) as I | undefined; }\n take(n: number): I[] { return (this._client._inputBuffer?.take(n) ?? []) as I[]; }\n peek(): I[] { return (this._client._inputBuffer?.peek() ?? []) as I[]; }\n get size(): number { return this._client._inputBuffer?.size ?? 0; }\n get consumedCount(): number { return this._client._inputBuffer?.consumedCount ?? 0; }\n get wasIdle(): boolean { return this._client._inputBuffer?.wasIdle ?? false; }\n clear(): void { this._client._inputBuffer?.clear(); }\n get renderTime(): number { return this._client._inputBuffer?.renderTime ?? 0; }\n /** @internal RAW reckon stamp (0 until stamped). The rewind binding reads\n * THIS, not the resolved getter below: `Rewind._aim`'s midpoint fallback\n * must still see 0 for unstamped clients (a resolved value would silently\n * take the direct-stamp clamp path). */\n get rawReckonTime(): number { return this._client._inputBuffer?.reckonTime ?? 0; }\n get reckonTime(): number {\n const raw = this._client._inputBuffer?.reckonTime ?? 0;\n return raw > 0 ? raw : this._nowOf !== undefined ? this._nowOf() : 0;\n }\n}\n\n/**\n * Returned by `room.inputs.get(sessionId)` for unknown sessions and for rooms\n * that didn't call `defineInput()`.\n *\n * @internal\n */\nexport const NO_OP_INPUT_ACCESSOR: InputAccessor<any> = Object.freeze({\n latest: undefined,\n at: () => undefined,\n consume: () => DONE_ITERATOR,\n [Symbol.iterator]: () => DONE_ITERATOR,\n drain: () => [],\n next: () => undefined,\n take: () => [],\n peek: () => [],\n size: 0,\n consumedCount: 0,\n wasIdle: false,\n clear: () => {},\n renderTime: 0,\n reckonTime: 0, // stays 0 \u2014 an unknown session / input-less room has no clock to resolve against\n});\n"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const __cjsImportMetaUrl = require('node:url').pathToFileURL(__filename).href;
|
|
1
2
|
"use strict";
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -29,6 +30,14 @@ var import_shared_types = require("@colyseus/shared-types");
|
|
|
29
30
|
var import_InputBuffer = require("./InputBuffer.cjs");
|
|
30
31
|
var import_Debug = require("../Debug.cjs");
|
|
31
32
|
var _inputReflectionCache = /* @__PURE__ */ new WeakMap();
|
|
33
|
+
function readSeriesDeltas(buffer, it, k, newest) {
|
|
34
|
+
const out = new Array(k);
|
|
35
|
+
out[k - 1] = newest;
|
|
36
|
+
for (let i = k - 2; i >= 0; i--) {
|
|
37
|
+
out[i] = out[i + 1] - import_schema.decode.number(buffer, it);
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
32
41
|
var InputAPIImpl = class {
|
|
33
42
|
constructor(input) {
|
|
34
43
|
this.input = input;
|
|
@@ -221,13 +230,65 @@ var RoomInput = class {
|
|
|
221
230
|
this.capture(client, renderTime, reckonTime);
|
|
222
231
|
}
|
|
223
232
|
/** Decode a `ROOM_INPUT_UNRELIABLE` redundancy ring — each slot carries its
|
|
224
|
-
* framework seq (base seq + position) for ring dedupe, no user seqField.
|
|
225
|
-
|
|
233
|
+
* framework seq (base seq + position) for ring dedupe, no user seqField.
|
|
234
|
+
*
|
|
235
|
+
* With the TIMED bit, a self-contained lag-comp stamp block precedes the ring:
|
|
236
|
+
*
|
|
237
|
+
* [varint k][uint32 newest][varint Δ]×(k−1)
|
|
238
|
+
* [uint16 rdNewest][varint Δrd]×(k−1) ← BOTH mode only
|
|
239
|
+
*
|
|
240
|
+
* One stamp per slot, because a packet carries k inputs sampled at k
|
|
241
|
+
* different instants. The anchor is absolute and the deltas never leave the
|
|
242
|
+
* packet, so — unlike the reliable channel's running baseline — no amount of
|
|
243
|
+
* loss or reordering can desync it, and an input recovered redundantly from a
|
|
244
|
+
* later packet still arrives with its own instant. Stamps are paired
|
|
245
|
+
* positionally with `decodeAll`'s oldest→newest yields; a `k` that disagrees
|
|
246
|
+
* with the decoded slot count means a malformed packet, so the stamps are
|
|
247
|
+
* dropped rather than misapplied (inputs still land, read live). */
|
|
248
|
+
decodeUnreliable(client, buffer, modifiers) {
|
|
226
249
|
if (!client._inputDecoder) {
|
|
227
250
|
return;
|
|
228
251
|
}
|
|
252
|
+
const it = { offset: 1 };
|
|
253
|
+
let stamps;
|
|
254
|
+
let renderDeltas;
|
|
255
|
+
if (modifiers & import_shared_types.ProtocolModifier.TIMED) {
|
|
256
|
+
this.#resolveWireModes();
|
|
257
|
+
try {
|
|
258
|
+
const k = import_schema.decode.number(buffer, it);
|
|
259
|
+
stamps = readSeriesDeltas(buffer, it, k, import_schema.decode.uint32(buffer, it));
|
|
260
|
+
if (this.#stampReckon && this.#stampRender) {
|
|
261
|
+
renderDeltas = readSeriesDeltas(buffer, it, k, import_schema.decode.uint16(buffer, it));
|
|
262
|
+
}
|
|
263
|
+
} catch (e) {
|
|
264
|
+
(0, import_Debug.debugAndPrintError)(e);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
let i = 0;
|
|
229
269
|
try {
|
|
230
|
-
client._inputDecoder.decodeAll(buffer.subarray(
|
|
270
|
+
const count = client._inputDecoder.decodeAll(buffer.subarray(it.offset), (_inst, seq) => {
|
|
271
|
+
const slot = i++;
|
|
272
|
+
const stamp = stamps?.[slot] ?? 0;
|
|
273
|
+
let renderTime = 0, reckonTime = 0;
|
|
274
|
+
if (stamp > 0) {
|
|
275
|
+
if (this.#stampReckon && this.#stampRender) {
|
|
276
|
+
const rd = renderDeltas?.[slot] ?? 0;
|
|
277
|
+
reckonTime = stamp;
|
|
278
|
+
renderTime = stamp > rd ? stamp - rd : 0;
|
|
279
|
+
} else if (this.#stampReckon) {
|
|
280
|
+
reckonTime = stamp;
|
|
281
|
+
} else {
|
|
282
|
+
renderTime = stamp;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
this.capture(client, renderTime, reckonTime, seq);
|
|
286
|
+
});
|
|
287
|
+
if (stamps !== void 0 && count !== stamps.length) {
|
|
288
|
+
(0, import_Debug.debugAndPrintError)(new Error(
|
|
289
|
+
`@colyseus/core: unreliable input stamp block declared ${stamps.length} slots, decoded ${count}`
|
|
290
|
+
));
|
|
291
|
+
}
|
|
231
292
|
} catch (e) {
|
|
232
293
|
(0, import_Debug.debugAndPrintError)(e);
|
|
233
294
|
return;
|