@mml-io/3d-web-user-networking
Advanced tools
Comparing version 0.0.0-experimental-8ac7fdd-20240221 to 0.0.0-experimental-8dada83-20250122
export * from "./UserNetworkingCodec"; | ||
export * from "./UserNetworkingServer"; | ||
export * from "./UserNetworkingClient"; | ||
export * from "./UserData"; | ||
export * from "./ReconnectingWebSocket"; | ||
export * from "./messages"; | ||
export * from "./UserNetworkingMessages"; |
@@ -30,9 +30,2 @@ // src/UserNetworkingCodec.ts | ||
// src/messages.ts | ||
var CONNECTED_MESSAGE_TYPE = "connected"; | ||
var DISCONNECTED_MESSAGE_TYPE = "disconnected"; | ||
var IDENTITY_MESSAGE_TYPE = "identity"; | ||
var PING_MESSAGE_TYPE = "ping"; | ||
var PONG_MESSAGE_TYPE = "pong"; | ||
// src/user-networking-settings.ts | ||
@@ -43,27 +36,34 @@ var pingPongRate = 1500; | ||
// src/UserNetworkingMessages.ts | ||
var USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE = "disconnected"; | ||
var USER_NETWORKING_IDENTITY_MESSAGE_TYPE = "identity"; | ||
var USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE = "user_auth"; | ||
var USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE = "user_profile"; | ||
var USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE = "user_update"; | ||
var USER_NETWORKING_SERVER_BROADCAST_MESSAGE_TYPE = "broadcast"; | ||
var USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE = "error"; | ||
var USER_NETWORKING_PING_MESSAGE_TYPE = "ping"; | ||
var USER_NETWORKING_PONG_MESSAGE_TYPE = "pong"; | ||
var USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE = "CONNECTION_LIMIT_REACHED"; | ||
var USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE = "AUTHENTICATION_FAILED"; | ||
var USER_NETWORKING_SERVER_SHUTDOWN_ERROR_TYPE = "SERVER_SHUTDOWN"; | ||
var USER_NETWORKING_UNKNOWN_ERROR = "UNKNOWN_ERROR"; | ||
// src/UserNetworkingServer.ts | ||
var WebSocketOpenStatus = 1; | ||
var UserNetworkingServer = class { | ||
constructor() { | ||
this.clients = /* @__PURE__ */ new Map(); | ||
this.clientLastPong = /* @__PURE__ */ new Map(); | ||
setInterval(this.sendUpdates.bind(this), packetsUpdateRate); | ||
setInterval(this.pingClients.bind(this), pingPongRate); | ||
setInterval(this.heartBeat.bind(this), heartBeatRate); | ||
constructor(options) { | ||
this.options = options; | ||
this.allClientsById = /* @__PURE__ */ new Map(); | ||
this.authenticatedClientsById = /* @__PURE__ */ new Map(); | ||
this.sendUpdatesIntervalTimer = setInterval(this.sendUpdates.bind(this), packetsUpdateRate); | ||
this.pingClientsIntervalTimer = setInterval(this.pingClients.bind(this), pingPongRate); | ||
this.heartbeatIntervalTimer = setInterval(this.heartBeat.bind(this), heartBeatRate); | ||
} | ||
heartBeat() { | ||
const now = Date.now(); | ||
this.clientLastPong.forEach((clientLastPong, id) => { | ||
if (now - clientLastPong > heartBeatRate) { | ||
this.clients.delete(id); | ||
this.clientLastPong.delete(id); | ||
const disconnectMessage = JSON.stringify({ | ||
id, | ||
type: DISCONNECTED_MESSAGE_TYPE | ||
}); | ||
for (const { socket: otherSocket } of this.clients.values()) { | ||
if (otherSocket.readyState === WebSocketOpenStatus) { | ||
otherSocket.send(disconnectMessage); | ||
} | ||
} | ||
this.allClientsById.forEach((client) => { | ||
if (now - client.lastPong > heartBeatRate) { | ||
client.socket.close(); | ||
this.handleDisconnectedClient(client); | ||
} | ||
@@ -73,5 +73,7 @@ }); | ||
pingClients() { | ||
this.clients.forEach((client) => { | ||
const message = { type: "ping" }; | ||
const messageString = JSON.stringify(message); | ||
this.authenticatedClientsById.forEach((client) => { | ||
if (client.socket.readyState === WebSocketOpenStatus) { | ||
client.socket.send(JSON.stringify({ type: "ping" })); | ||
client.socket.send(messageString); | ||
} | ||
@@ -82,28 +84,28 @@ }); | ||
let id = 1; | ||
while (this.clients.has(id)) | ||
while (this.allClientsById.has(id)) { | ||
id++; | ||
} | ||
return id; | ||
} | ||
broadcastMessage(broadcastType, broadcastPayload) { | ||
const message = { | ||
type: "broadcast", | ||
broadcastType, | ||
payload: broadcastPayload | ||
}; | ||
const messageString = JSON.stringify(message); | ||
for (const [, client] of this.authenticatedClientsById) { | ||
if (client.socket.readyState === WebSocketOpenStatus) { | ||
client.socket.send(messageString); | ||
} | ||
} | ||
} | ||
connectClient(socket) { | ||
const id = this.getId(); | ||
console.log(`Client ID: ${id} joined`); | ||
const connectMessage = JSON.stringify({ | ||
console.log(`Client ID: ${id} joined, waiting for user-identification`); | ||
const client = { | ||
id, | ||
type: CONNECTED_MESSAGE_TYPE | ||
}); | ||
for (const { socket: otherSocket } of this.clients.values()) { | ||
if (otherSocket.readyState === WebSocketOpenStatus) { | ||
otherSocket.send(connectMessage); | ||
} | ||
} | ||
const identityMessage = JSON.stringify({ | ||
id, | ||
type: IDENTITY_MESSAGE_TYPE | ||
}); | ||
socket.send(identityMessage); | ||
for (const { update } of this.clients.values()) { | ||
socket.send(UserNetworkingCodec.encodeUpdate(update)); | ||
} | ||
this.clients.set(id, { | ||
lastPong: Date.now(), | ||
socket, | ||
authenticatedUser: null, | ||
update: { | ||
@@ -115,3 +117,4 @@ id, | ||
} | ||
}); | ||
}; | ||
this.allClientsById.set(id, client); | ||
socket.on("message", (message, _isBinary) => { | ||
@@ -122,14 +125,87 @@ if (message instanceof Buffer) { | ||
update.id = id; | ||
if (this.clients.get(id) !== void 0) { | ||
this.clients.get(id).update = update; | ||
} | ||
client.update = update; | ||
} else { | ||
let parsed; | ||
try { | ||
const data = JSON.parse(message); | ||
if (data.type === "pong") { | ||
this.clientLastPong.set(id, Date.now()); | ||
} | ||
parsed = JSON.parse(message); | ||
} catch (e) { | ||
console.error("Error parsing JSON message", message, e); | ||
return; | ||
} | ||
if (!client.authenticatedUser) { | ||
if (parsed.type === USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE) { | ||
this.handleUserAuth(client, parsed).then((authResult) => { | ||
var _a, _b; | ||
if (client.socket.readyState !== WebSocketOpenStatus) { | ||
return; | ||
} | ||
if (!authResult) { | ||
const serverError = JSON.stringify({ | ||
type: USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE, | ||
errorType: USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE, | ||
message: "Authentication failed" | ||
}); | ||
socket.send(serverError); | ||
socket.close(); | ||
} else { | ||
if (this.options.connectionLimit !== void 0 && this.authenticatedClientsById.size >= this.options.connectionLimit) { | ||
const serverError = JSON.stringify({ | ||
type: USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE, | ||
errorType: USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE, | ||
message: "Connection limit reached" | ||
}); | ||
socket.send(serverError); | ||
socket.close(); | ||
return; | ||
} | ||
const userData = authResult; | ||
client.authenticatedUser = userData; | ||
const userProfileMessage = JSON.stringify({ | ||
id: client.id, | ||
type: USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE, | ||
username: userData.username, | ||
characterDescription: userData.characterDescription | ||
}); | ||
client.socket.send(userProfileMessage); | ||
const identityMessage = JSON.stringify({ | ||
id: client.id, | ||
type: USER_NETWORKING_IDENTITY_MESSAGE_TYPE | ||
}); | ||
client.socket.send(identityMessage); | ||
const userUpdateMessage = UserNetworkingCodec.encodeUpdate(client.update); | ||
for (const [, otherClient] of this.authenticatedClientsById) { | ||
if (otherClient.socket.readyState !== WebSocketOpenStatus || otherClient === client) { | ||
continue; | ||
} | ||
client.socket.send( | ||
JSON.stringify({ | ||
id: otherClient.update.id, | ||
type: USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE, | ||
username: (_a = otherClient.authenticatedUser) == null ? void 0 : _a.username, | ||
characterDescription: (_b = otherClient.authenticatedUser) == null ? void 0 : _b.characterDescription | ||
}) | ||
); | ||
client.socket.send(UserNetworkingCodec.encodeUpdate(otherClient.update)); | ||
otherClient.socket.send(userProfileMessage); | ||
otherClient.socket.send(userUpdateMessage); | ||
} | ||
this.authenticatedClientsById.set(id, client); | ||
} | ||
}); | ||
} else { | ||
console.error(`Unhandled message pre-auth: ${JSON.stringify(parsed)}`); | ||
socket.close(); | ||
} | ||
} else { | ||
switch (parsed.type) { | ||
case USER_NETWORKING_PONG_MESSAGE_TYPE: | ||
client.lastPong = Date.now(); | ||
break; | ||
case USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE: | ||
this.handleUserUpdate(id, parsed); | ||
break; | ||
default: | ||
console.error(`Unhandled message: ${JSON.stringify(parsed)}`); | ||
} | ||
} | ||
} | ||
@@ -139,19 +215,89 @@ }); | ||
console.log("Client disconnected", id); | ||
this.clients.delete(id); | ||
this.handleDisconnectedClient(client); | ||
}); | ||
} | ||
handleDisconnectedClient(client) { | ||
if (!this.allClientsById.has(client.id)) { | ||
return; | ||
} | ||
this.allClientsById.delete(client.id); | ||
if (client.authenticatedUser !== null) { | ||
this.options.onClientDisconnect(client.id); | ||
this.authenticatedClientsById.delete(client.id); | ||
const disconnectMessage = JSON.stringify({ | ||
id, | ||
type: DISCONNECTED_MESSAGE_TYPE | ||
id: client.id, | ||
type: USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE | ||
}); | ||
for (const [clientId, { socket: otherSocket }] of this.clients) { | ||
if (otherSocket.readyState === WebSocketOpenStatus) { | ||
otherSocket.send(disconnectMessage); | ||
for (const [, otherClient] of this.authenticatedClientsById) { | ||
if (otherClient.socket.readyState === WebSocketOpenStatus) { | ||
otherClient.socket.send(disconnectMessage); | ||
} | ||
} | ||
} | ||
} | ||
async handleUserAuth(client, credentials) { | ||
const userData = this.options.onClientConnect( | ||
client.id, | ||
credentials.sessionToken, | ||
credentials.userIdentity | ||
); | ||
let resolvedUserData; | ||
if (userData instanceof Promise) { | ||
resolvedUserData = await userData; | ||
} else { | ||
resolvedUserData = userData; | ||
} | ||
if (resolvedUserData === null) { | ||
console.error(`Client-id ${client.id} user_auth unauthorized and ignored`); | ||
return false; | ||
} | ||
console.log("Client authenticated", client.id, resolvedUserData); | ||
return resolvedUserData; | ||
} | ||
updateUserCharacter(clientId, userData) { | ||
this.internalUpdateUser(clientId, userData); | ||
} | ||
internalUpdateUser(clientId, userData) { | ||
const client = this.authenticatedClientsById.get(clientId); | ||
client.authenticatedUser = userData; | ||
this.authenticatedClientsById.set(clientId, client); | ||
const newUserData = JSON.stringify({ | ||
id: clientId, | ||
type: USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE, | ||
username: userData.username, | ||
characterDescription: userData.characterDescription | ||
}); | ||
for (const [otherClientId, otherClient] of this.authenticatedClientsById) { | ||
if (otherClient.socket.readyState === WebSocketOpenStatus) { | ||
otherClient.socket.send(newUserData); | ||
} | ||
} | ||
} | ||
async handleUserUpdate(clientId, message) { | ||
const client = this.authenticatedClientsById.get(clientId); | ||
if (!client) { | ||
console.error(`Client-id ${clientId} user_update ignored, client not found`); | ||
return; | ||
} | ||
const authorizedUserData = this.options.onClientUserIdentityUpdate( | ||
clientId, | ||
message.userIdentity | ||
); | ||
let resolvedAuthorizedUserData; | ||
if (authorizedUserData instanceof Promise) { | ||
resolvedAuthorizedUserData = await authorizedUserData; | ||
} else { | ||
resolvedAuthorizedUserData = authorizedUserData; | ||
} | ||
if (!resolvedAuthorizedUserData) { | ||
console.warn(`Client-id ${clientId} user_update unauthorized and ignored`); | ||
return; | ||
} | ||
this.internalUpdateUser(clientId, resolvedAuthorizedUserData); | ||
} | ||
sendUpdates() { | ||
for (const [clientId, client] of this.clients) { | ||
for (const [clientId, client] of this.authenticatedClientsById) { | ||
const update = client.update; | ||
const encodedUpdate = UserNetworkingCodec.encodeUpdate(update); | ||
for (const [otherClientId, otherClient] of this.clients) { | ||
for (const [otherClientId, otherClient] of this.authenticatedClientsById) { | ||
if (otherClientId !== clientId && otherClient.socket.readyState === WebSocketOpenStatus) { | ||
@@ -163,11 +309,23 @@ otherClient.socket.send(encodedUpdate); | ||
} | ||
dispose(clientCloseError) { | ||
clearInterval(this.sendUpdatesIntervalTimer); | ||
clearInterval(this.pingClientsIntervalTimer); | ||
clearInterval(this.heartbeatIntervalTimer); | ||
const stringifiedError = clientCloseError ? JSON.stringify(clientCloseError) : void 0; | ||
for (const [, client] of this.authenticatedClientsById) { | ||
if (stringifiedError) { | ||
client.socket.send(stringifiedError); | ||
} | ||
client.socket.close(); | ||
} | ||
} | ||
}; | ||
// src/ReconnectingWebSocket.ts | ||
var WebsocketStatus = /* @__PURE__ */ ((WebsocketStatus3) => { | ||
WebsocketStatus3[WebsocketStatus3["Connecting"] = 0] = "Connecting"; | ||
WebsocketStatus3[WebsocketStatus3["Connected"] = 1] = "Connected"; | ||
WebsocketStatus3[WebsocketStatus3["Reconnecting"] = 2] = "Reconnecting"; | ||
WebsocketStatus3[WebsocketStatus3["Disconnected"] = 3] = "Disconnected"; | ||
return WebsocketStatus3; | ||
var WebsocketStatus = /* @__PURE__ */ ((WebsocketStatus2) => { | ||
WebsocketStatus2[WebsocketStatus2["Connecting"] = 0] = "Connecting"; | ||
WebsocketStatus2[WebsocketStatus2["Connected"] = 1] = "Connected"; | ||
WebsocketStatus2[WebsocketStatus2["Reconnecting"] = 2] = "Reconnecting"; | ||
WebsocketStatus2[WebsocketStatus2["Disconnected"] = 3] = "Disconnected"; | ||
return WebsocketStatus2; | ||
})(WebsocketStatus || {}); | ||
@@ -285,3 +443,3 @@ var startingBackoffTimeMilliseconds = 100; | ||
} | ||
console.log("NetworkedDOMWebsocket close", e); | ||
console.log("ReconnectingWebSocket close", e); | ||
onWebsocketClose(); | ||
@@ -294,3 +452,3 @@ }); | ||
} | ||
console.error("NetworkedDOMWebsocket error", e); | ||
console.error("ReconnectingWebSocket error", e); | ||
onWebsocketClose(); | ||
@@ -317,6 +475,13 @@ }); | ||
var UserNetworkingClient = class extends ReconnectingWebSocket { | ||
constructor(url, websocketFactory, statusUpdateCallback, setIdentityCallback, clientUpdate) { | ||
super(url, websocketFactory, statusUpdateCallback); | ||
this.setIdentityCallback = setIdentityCallback; | ||
this.clientUpdate = clientUpdate; | ||
constructor(config) { | ||
super(config.url, config.websocketFactory, (status) => { | ||
if (status === 1 /* Connected */) { | ||
this.sendMessage({ | ||
type: USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE, | ||
sessionToken: config.sessionToken | ||
}); | ||
} | ||
config.statusUpdateCallback(status); | ||
}); | ||
this.config = config; | ||
} | ||
@@ -327,2 +492,5 @@ sendUpdate(update) { | ||
} | ||
sendMessage(message) { | ||
this.send(message); | ||
} | ||
handleIncomingWebsocketMessage(message) { | ||
@@ -332,23 +500,39 @@ if (typeof message.data === "string") { | ||
switch (parsed.type) { | ||
case IDENTITY_MESSAGE_TYPE: | ||
console.log(`Assigned ID: ${parsed.id}`); | ||
this.setIdentityCallback(parsed.id); | ||
case USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE: | ||
console.error(`Server error: ${parsed.message}. errorType: ${parsed.errorType}`); | ||
this.config.onServerError(parsed); | ||
break; | ||
case CONNECTED_MESSAGE_TYPE: | ||
console.log(`Client ID: ${parsed.id} joined`); | ||
break; | ||
case DISCONNECTED_MESSAGE_TYPE: | ||
case USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE: | ||
console.log(`Client ID: ${parsed.id} left`); | ||
this.clientUpdate(parsed.id, null); | ||
this.config.clientUpdate(parsed.id, null); | ||
break; | ||
case PING_MESSAGE_TYPE: { | ||
this.send({ type: "pong" }); | ||
case USER_NETWORKING_IDENTITY_MESSAGE_TYPE: | ||
console.log(`Client ID: ${parsed.id} assigned to self`); | ||
this.config.assignedIdentity(parsed.id); | ||
break; | ||
case USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE: | ||
console.log(`Client ID: ${parsed.id} updated profile`); | ||
this.config.clientProfileUpdated(parsed.id, parsed.username, parsed.characterDescription); | ||
break; | ||
case USER_NETWORKING_PING_MESSAGE_TYPE: { | ||
this.sendMessage({ type: "pong" }); | ||
break; | ||
} | ||
case USER_NETWORKING_SERVER_BROADCAST_MESSAGE_TYPE: { | ||
if (this.config.onServerBroadcast) { | ||
this.config.onServerBroadcast({ | ||
broadcastType: parsed.broadcastType, | ||
payload: parsed.payload | ||
}); | ||
} else { | ||
console.warn("Unhandled broadcast", parsed); | ||
} | ||
break; | ||
} | ||
default: | ||
console.warn("unknown message type received", parsed); | ||
console.error("Unhandled message", parsed); | ||
} | ||
} else if (message.data instanceof ArrayBuffer) { | ||
const userNetworkingClientUpdate = UserNetworkingCodec.decodeUpdate(message.data); | ||
this.clientUpdate(userNetworkingClientUpdate.id, userNetworkingClientUpdate); | ||
this.config.clientUpdate(userNetworkingClientUpdate.id, userNetworkingClientUpdate); | ||
} else { | ||
@@ -360,8 +544,16 @@ console.error("Unhandled message type", message.data); | ||
export { | ||
CONNECTED_MESSAGE_TYPE, | ||
DISCONNECTED_MESSAGE_TYPE, | ||
IDENTITY_MESSAGE_TYPE, | ||
PING_MESSAGE_TYPE, | ||
PONG_MESSAGE_TYPE, | ||
ReconnectingWebSocket, | ||
USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE, | ||
USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE, | ||
USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE, | ||
USER_NETWORKING_IDENTITY_MESSAGE_TYPE, | ||
USER_NETWORKING_PING_MESSAGE_TYPE, | ||
USER_NETWORKING_PONG_MESSAGE_TYPE, | ||
USER_NETWORKING_SERVER_BROADCAST_MESSAGE_TYPE, | ||
USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE, | ||
USER_NETWORKING_SERVER_SHUTDOWN_ERROR_TYPE, | ||
USER_NETWORKING_UNKNOWN_ERROR, | ||
USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE, | ||
USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE, | ||
USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE, | ||
UserNetworkingClient, | ||
@@ -368,0 +560,0 @@ UserNetworkingCodec, |
import { ReconnectingWebSocket, WebsocketFactory, WebsocketStatus } from "./ReconnectingWebSocket"; | ||
import { UserNetworkingClientUpdate } from "./UserNetworkingCodec"; | ||
import { CharacterDescription, FromUserNetworkingClientMessage, UserNetworkingServerErrorType } from "./UserNetworkingMessages"; | ||
export type UserNetworkingClientConfig = { | ||
url: string; | ||
sessionToken: string; | ||
websocketFactory: WebsocketFactory; | ||
statusUpdateCallback: (status: WebsocketStatus) => void; | ||
assignedIdentity: (clientId: number) => void; | ||
clientUpdate: (id: number, update: null | UserNetworkingClientUpdate) => void; | ||
clientProfileUpdated: (id: number, username: string, characterDescription: CharacterDescription) => void; | ||
onServerError: (error: { | ||
message: string; | ||
errorType: UserNetworkingServerErrorType; | ||
}) => void; | ||
onServerBroadcast?: (broadcast: { | ||
broadcastType: string; | ||
payload: any; | ||
}) => void; | ||
}; | ||
export declare class UserNetworkingClient extends ReconnectingWebSocket { | ||
private setIdentityCallback; | ||
private clientUpdate; | ||
constructor(url: string, websocketFactory: WebsocketFactory, statusUpdateCallback: (status: WebsocketStatus) => void, setIdentityCallback: (id: number) => void, clientUpdate: (id: number, update: null | UserNetworkingClientUpdate) => void); | ||
private config; | ||
constructor(config: UserNetworkingClientConfig); | ||
sendUpdate(update: UserNetworkingClientUpdate): void; | ||
sendMessage(message: FromUserNetworkingClientMessage): void; | ||
protected handleIncomingWebsocketMessage(message: MessageEvent): void; | ||
} |
import WebSocket from "ws"; | ||
import { UserData } from "./UserData"; | ||
import { UserNetworkingClientUpdate } from "./UserNetworkingCodec"; | ||
export type Client = { | ||
import { UserIdentity, UserNetworkingServerError } from "./UserNetworkingMessages"; | ||
export type UserNetworkingServerClient = { | ||
socket: WebSocket; | ||
id: number; | ||
lastPong: number; | ||
update: UserNetworkingClientUpdate; | ||
authenticatedUser: UserData | null; | ||
}; | ||
export type UserNetworkingServerOptions = { | ||
connectionLimit?: number; | ||
onClientConnect: (clientId: number, sessionToken: string, userIdentity?: UserIdentity) => Promise<UserData | null> | UserData | null; | ||
onClientUserIdentityUpdate: (clientId: number, userIdentity: UserIdentity) => Promise<UserData | null> | UserData | null; | ||
onClientDisconnect: (clientId: number) => void; | ||
}; | ||
export declare class UserNetworkingServer { | ||
private clients; | ||
private clientLastPong; | ||
constructor(); | ||
heartBeat(): void; | ||
pingClients(): void; | ||
getId(): number; | ||
private options; | ||
private allClientsById; | ||
private authenticatedClientsById; | ||
private sendUpdatesIntervalTimer; | ||
private pingClientsIntervalTimer; | ||
private heartbeatIntervalTimer; | ||
constructor(options: UserNetworkingServerOptions); | ||
private heartBeat; | ||
private pingClients; | ||
private getId; | ||
broadcastMessage(broadcastType: string, broadcastPayload: any): void; | ||
connectClient(socket: WebSocket): void; | ||
sendUpdates(): void; | ||
private handleDisconnectedClient; | ||
private handleUserAuth; | ||
updateUserCharacter(clientId: number, userData: UserData): void; | ||
private internalUpdateUser; | ||
private handleUserUpdate; | ||
private sendUpdates; | ||
dispose(clientCloseError?: UserNetworkingServerError): void; | ||
} |
{ | ||
"name": "@mml-io/3d-web-user-networking", | ||
"version": "0.0.0-experimental-8ac7fdd-20240221", | ||
"version": "0.0.0-experimental-8dada83-20250122", | ||
"publishConfig": { | ||
@@ -22,3 +22,3 @@ "access": "public" | ||
"dependencies": { | ||
"ws": "^8.16.0" | ||
"ws": "^8.18.0" | ||
}, | ||
@@ -28,8 +28,8 @@ "devDependencies": { | ||
"@types/express-ws": "^3.0.4", | ||
"@types/node": "^20.11.13", | ||
"@types/node": "^20.14.10", | ||
"@types/ws": "^8.5.10", | ||
"express": "4.18.2", | ||
"express": "4.19.2", | ||
"express-ws": "5.0.2" | ||
}, | ||
"gitHead": "1c36e5c6d6603f37404430c2ec65d5b1aedbac93" | ||
"gitHead": "93bc9e1f6a894a70a9542d5118c14905032a8726" | ||
} |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
70809
738
1
Updatedws@^8.18.0