@eleven-am/pondsocket 0.1.217 → 0.1.219

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +84 -164
  2. package/{abstracts → dist/abstracts}/types.d.ts +3 -3
  3. package/{contexts → dist/contexts}/baseContext.d.ts +3 -1
  4. package/{contexts → dist/contexts}/baseContext.js +6 -0
  5. package/{contexts → dist/contexts}/eventContext.d.ts +2 -2
  6. package/{contexts → dist/contexts}/joinContext.js +8 -2
  7. package/dist/contexts/outgoingContext.d.ts +36 -0
  8. package/{contexts → dist/contexts}/outgoingContext.js +12 -6
  9. package/{engines → dist/engines}/channelEngine.d.ts +3 -1
  10. package/{engines → dist/engines}/channelEngine.js +103 -13
  11. package/{engines → dist/engines}/endpointEngine.d.ts +2 -1
  12. package/{engines → dist/engines}/endpointEngine.js +29 -11
  13. package/{engines → dist/engines}/lobbyEngine.js +14 -9
  14. package/{index.d.ts → dist/index.d.ts} +1 -0
  15. package/dist/matcher/matcher.js +17 -0
  16. package/{server → dist/server}/server.d.ts +8 -4
  17. package/{server → dist/server}/server.js +112 -33
  18. package/{types.d.ts → dist/types.d.ts} +6 -6
  19. package/{wrappers → dist/wrappers}/channel.d.ts +13 -5
  20. package/{wrappers → dist/wrappers}/channel.js +22 -6
  21. package/{wrappers → dist/wrappers}/endpoint.d.ts +4 -2
  22. package/{wrappers → dist/wrappers}/pondChannel.d.ts +4 -4
  23. package/{wrappers → dist/wrappers}/pondChannel.js +6 -6
  24. package/package.json +48 -64
  25. package/contexts/outgoingContext.d.ts +0 -28
  26. package/matcher/matcher.js +0 -74
  27. /package/{abstracts → dist/abstracts}/distributor.d.ts +0 -0
  28. /package/{abstracts → dist/abstracts}/distributor.js +0 -0
  29. /package/{abstracts → dist/abstracts}/middleware.d.ts +0 -0
  30. /package/{abstracts → dist/abstracts}/middleware.js +0 -0
  31. /package/{abstracts → dist/abstracts}/types.js +0 -0
  32. /package/{contexts → dist/contexts}/connectionContext.d.ts +0 -0
  33. /package/{contexts → dist/contexts}/connectionContext.js +0 -0
  34. /package/{contexts → dist/contexts}/eventContext.js +0 -0
  35. /package/{contexts → dist/contexts}/joinContext.d.ts +0 -0
  36. /package/{engines → dist/engines}/lobbyEngine.d.ts +0 -0
  37. /package/{engines → dist/engines}/presenceEngine.d.ts +0 -0
  38. /package/{engines → dist/engines}/presenceEngine.js +0 -0
  39. /package/{errors → dist/errors}/httpError.d.ts +0 -0
  40. /package/{errors → dist/errors}/httpError.js +0 -0
  41. /package/{index.js → dist/index.js} +0 -0
  42. /package/{matcher → dist/matcher}/matcher.d.ts +0 -0
  43. /package/{types.js → dist/types.js} +0 -0
  44. /package/{wrappers → dist/wrappers}/endpoint.js +0 -0
package/README.md CHANGED
@@ -1,212 +1,132 @@
1
1
  # PondSocket
2
2
 
3
- PondSocket is a high-performance, minimalist, and bidirectional socket framework designed for Node.js. It provides a seamless way to handle real-time communication between server and client applications, making it an ideal choice for building WebSocket-based projects.
3
+ Typed WebSocket channels for Node.js with presence, private assigns, request/reply events, and Redis-backed distribution.
4
4
 
5
- ## Installation
6
-
7
- To integrate PondSocket into your Node.js project, simply install it via npm:
5
+ ## Install
8
6
 
9
7
  ```bash
10
8
  npm install @eleven-am/pondsocket
11
9
  ```
12
10
 
13
- ## Overview
14
-
15
- PondSocket simplifies the complexity of handling WebSocket connections by abstracting the communication process into individual requests rather than dealing with intricate callbacks within the connection event. It offers a lightweight yet powerful solution for managing bidirectional communication channels, enabling real-time updates and collaboration between server and client components.
16
-
17
- ## Key Features
18
-
19
- - **Simple and Efficient API**: PondSocket offers an easy-to-use API, making WebSocket communication straightforward and hassle-free.
20
- - **Organized Channels**: Channels provide a structured approach for grouping users and facilitating efficient communication.
21
- - **Assigns**: PondSocket allows the storage of private information for users and channels, enhancing data security.
22
- - **Presence**: The presence feature keeps track of users' current states and notifies other users about any changes.
23
- - **Broadcasting**: PondSocket enables broadcasting messages to all users or specific groups within a channel, facilitating real-time updates.
24
- - **Type Safety**: The codebase is thoroughly typed with TypeScript, providing a seamless development experience with improved IDE suggestions.
25
- - **Middleware Support**: Extensible middleware system for request processing and validation.
26
- - **Distributed Support**: Built-in support for distributed deployment with state synchronization.
27
-
28
- ## Server-side Usage
11
+ ## Server
29
12
 
30
- When setting up the server, PondSocket allows you to create multiple endpoints, each serving as a gateway for sockets to connect and communicate. Each endpoint operates independently, ensuring that sockets from one endpoint cannot interact with sockets from another. This isolation enhances security and simplifies resource management.
31
-
32
- ```typescript
33
- import PondSocket from "@eleven-am/pondsocket";
13
+ ```ts
14
+ import { PondSocket } from '@eleven-am/pondsocket';
34
15
 
35
16
  const pond = new PondSocket();
36
17
 
37
- // Create an endpoint for handling socket connections
38
- const endpoint = pond.createEndpoint('/api/socket', (ctx, next) => {
39
- // Handle socket connection and authentication
40
- const token = ctx.request.query.token;
41
-
42
- if (isValidToken(token)) {
43
- const role = getRoleFromToken(token);
44
- ctx.accept({ role }); // Assign the user's role to the socket
45
- } else {
46
- ctx.reject('Invalid token', 401);
18
+ const endpoint = pond.createEndpoint('/v1/socket', (ctx) => {
19
+ const token = ctx.query.token;
20
+
21
+ if (!token) {
22
+ ctx.decline('Missing token', 401);
23
+ return;
47
24
  }
25
+
26
+ ctx.accept({ role: 'member' });
48
27
  });
49
28
 
50
- // Create a channel with path parameters
51
- const channel = endpoint.createChannel('/channel/:id', (ctx, next) => {
52
- const { role } = ctx.user.assigns;
53
- const { username } = ctx.joinParams;
54
- const { id } = ctx.event.params;
55
-
56
- if (role === 'admin') {
57
- ctx.accept({ username })
58
- .trackPresence({
59
- username,
60
- role,
61
- status: 'online',
62
- onlineSince: Date.now(),
63
- });
64
- } else {
65
- ctx.decline('Insufficient permissions', 403);
66
- }
29
+ const chat = endpoint.createChannel('/chat/:roomId', (ctx) => {
30
+ ctx.params.roomId.toUpperCase();
31
+ ctx.accept({ displayName: ctx.joinParams.displayName });
32
+ ctx.trackPresence({ online: true });
67
33
  });
68
34
 
69
- // Handle channel events
70
- channel.onEvent('message', (ctx, next) => {
71
- const { text } = ctx.event.payload;
72
-
73
- // Broadcast to all users in the channel
74
- ctx.broadcast('message', { text });
75
-
76
- // Or broadcast to specific users
77
- ctx.broadcastTo(['user1', 'user2'], 'message', { text });
78
-
79
- // Or broadcast to all except sender
80
- ctx.broadcastFrom('message', { text });
35
+ chat.onEvent('message/:messageId', (ctx) => {
36
+ ctx.params.messageId.toUpperCase();
37
+ ctx.broadcast(ctx.event.event, ctx.payload);
81
38
  });
82
39
 
83
- // Start the server
84
40
  pond.listen(3000);
85
41
  ```
86
42
 
87
- ## Client-side Usage
43
+ Connection and join handlers must call `accept()`, `decline()`, or delegate with `next()`. A handler that completes without deciding is declined instead of leaving the client pending.
44
+
45
+ ## Shared schema
46
+
47
+ Schemas are optional. A definition can be shared by Core, the Nest adapter, and the client without repeating route literals as generic arguments.
48
+
49
+ ```ts
50
+ import {
51
+ definePondChannel,
52
+ definePondEndpoint,
53
+ definePondSchema,
54
+ PondSocket,
55
+ } from '@eleven-am/pondsocket';
56
+
57
+ interface ChatSchema {
58
+ events: {
59
+ message: { text: string };
60
+ ping: [{ sentAt: number }, { receivedAt: number }];
61
+ };
62
+ presence: {
63
+ online: boolean;
64
+ };
65
+ assigns: {
66
+ role: 'admin' | 'member';
67
+ };
68
+ joinParams: {
69
+ token: string;
70
+ };
71
+ }
72
+
73
+ export const Socket = definePondEndpoint('/v1/socket');
74
+ export const Chat = definePondChannel(
75
+ definePondSchema<ChatSchema>(),
76
+ '/chat/:roomId',
77
+ );
88
78
 
89
- On the client-side, PondSocket provides the PondClient class to establish connections with the server. Clients can easily initiate connections, join channels, and participate in real-time interactions.
90
-
91
- ```typescript
92
- import PondClient from "@eleven-am/pondsocket-client";
93
-
94
- // Create a new client instance
95
- const socket = new PondClient('ws://your-server/api/socket', {
96
- token: 'your-auth-token'
97
- });
98
-
99
- // Connect to the server
100
- socket.connect();
101
-
102
- // Handle connection state changes
103
- socket.onConnectionChange((connected) => {
104
- if (connected) {
105
- console.log('Connected to the server');
106
- } else {
107
- console.log('Disconnected from the server');
108
- }
109
- });
79
+ const pond = new PondSocket();
80
+ const endpoint = pond.createEndpoint(Socket, (ctx) => ctx.accept());
110
81
 
111
- // Create and join a channel
112
- const channel = socket.createChannel('/channel/123', {
113
- username: 'user123'
82
+ const channel = endpoint.createChannel(Chat, (ctx) => {
83
+ ctx.params.roomId.toUpperCase();
84
+ ctx.joinParams.token.toUpperCase();
85
+ ctx.accept({ role: 'member' }).trackPresence({ online: true });
114
86
  });
115
87
 
116
- // Join the channel
117
- channel.join();
118
-
119
- // Handle channel events
120
- const subscription = channel.onMessage((event, message) => {
121
- console.log(`Received message: ${message.text}`);
88
+ channel.onEvent('ping', (ctx) => {
89
+ ctx.payload.sentAt.toFixed();
90
+ ctx.reply('ping', { receivedAt: Date.now() });
122
91
  });
123
-
124
- // Send a message
125
- channel.broadcast('message', { text: 'Hello, PondSocket!' });
126
-
127
- // Leave the channel
128
- channel.leave();
129
-
130
- // Unsubscribe from events
131
- subscription();
132
92
  ```
133
93
 
134
- ## Advanced Features
94
+ The schema types event names and payloads, request/response tuples, join params, presence, assigns, channel route params, and event route params.
135
95
 
136
- ### Presence Management
96
+ ## Distribution
137
97
 
138
- ```typescript
139
- // Server-side
140
- channel.onEvent('presence', (ctx, next) => {
141
- ctx.trackPresence({
142
- username: ctx.user.assigns.username,
143
- status: 'online',
144
- lastSeen: Date.now()
145
- });
146
- });
98
+ ```ts
99
+ import { PondSocket, RedisDistributedBackend } from '@eleven-am/pondsocket';
147
100
 
148
- // Client-side
149
- channel.onPresence((presences) => {
150
- console.log('Current users:', presences);
101
+ const backend = new RedisDistributedBackend({
102
+ url: process.env.REDIS_URL,
103
+ namespace: 'my-app',
151
104
  });
152
- ```
153
-
154
- ### User Assigns
155
105
 
156
- ```typescript
157
- // Server-side
158
- channel.onEvent('update-profile', (ctx, next) => {
159
- ctx.assign({
160
- ...ctx.user.assigns,
161
- profile: ctx.event.payload
162
- });
163
- });
106
+ const pond = new PondSocket({ distributedBackend: backend });
164
107
 
165
- // Client-side
166
- channel.onAssigns((assigns) => {
167
- console.log('User data updated:', assigns);
168
- });
108
+ await pond.ready();
169
109
  ```
170
110
 
171
- ### Error Handling
111
+ Distributed messages use the PondSocket v1 protocol shared by the supported server implementations. Events, presence, assigns, user removal, and cross-node user lookup are propagated through the backend.
172
112
 
173
- ```typescript
174
- // Server-side
175
- channel.onEvent('message', (ctx, next) => {
176
- try {
177
- // Your logic here
178
- ctx.accept();
179
- } catch (error) {
180
- ctx.decline(error.message, 400);
181
- }
182
- });
183
-
184
- // Client-side
185
- channel.onError((error) => {
186
- console.error('Channel error:', error);
187
- });
188
- ```
189
-
190
- ## Distributed Deployment
113
+ ## Lifecycle
191
114
 
192
- PondSocket supports distributed deployment through its distributed backend system. This allows you to scale your application across multiple nodes while maintaining state synchronization.
115
+ `ready()` reports distributed-backend initialization failures. `isHealthy()` reports backend/server health. `closeAsync()` stops heartbeat work, closes WebSockets, unsubscribes from the backend, and optionally closes the HTTP server.
193
116
 
194
- ```typescript
195
- import PondSocket from "@eleven-am/pondsocket";
196
- import { RedisBackend } from "@eleven-am/pondsocket";
117
+ When PondSocket uses a framework-owned HTTP server, pass `closeHttpServerOnShutdown: false`.
197
118
 
119
+ ```ts
198
120
  const pond = new PondSocket({
199
- backend: new RedisBackend({
200
- host: 'localhost',
201
- port: 6379
202
- })
121
+ server: existingHttpServer,
122
+ closeHttpServerOnShutdown: false,
203
123
  });
204
- ```
205
124
 
206
- ## Contributing
125
+ await pond.closeAsync();
126
+ ```
207
127
 
208
- Contributions are welcome! Please feel free to submit a Pull Request.
128
+ Channel patterns use path syntax. `/jobs/:id` and a whole `*` segment are supported; `job:*` is invalid and throws during registration. An unmatched join receives `CHANNEL_NOT_FOUND` with the original channel name and request ID.
209
129
 
210
130
  ## License
211
131
 
212
- This project is licensed under the GPL-3.0 License - see the LICENSE file for details.
132
+ GPL-3.0
@@ -6,7 +6,7 @@ import { WebSocket, WebSocketServer } from 'ws';
6
6
  import { ConnectionContext } from '../contexts/connectionContext';
7
7
  import { EventContext } from '../contexts/eventContext';
8
8
  import { JoinContext } from '../contexts/joinContext';
9
- import { OutgoingContext } from '../contexts/outgoingContext';
9
+ import { OutgoingHandlerContext } from '../contexts/outgoingContext';
10
10
  import { EndpointEngine } from '../engines/endpointEngine';
11
11
  import { HttpError } from '../errors/httpError';
12
12
  import { Channel } from '../wrappers/channel';
@@ -23,7 +23,7 @@ export type EventKey<Schema extends AnyPondSchema> = Extract<keyof EventsOf<Sche
23
23
  export type ConnectionHandler<Path extends string> = (ctx: ConnectionContext<Path>, next: NextFunction) => unknown | Promise<unknown>;
24
24
  export type AuthorizationHandler<Path extends string, Schema extends AnyPondSchema = AnyPondSchema> = (ctx: JoinContext<Path, Schema>, next: NextFunction) => unknown | Promise<unknown>;
25
25
  export type EventHandler<Path extends string, Schema extends AnyPondSchema = AnyPondSchema, Event extends EventKey<Schema> = EventKey<Schema>> = (ctx: EventContext<Path, Schema, Event>, next: NextFunction) => unknown | Promise<unknown>;
26
- export type OutgoingEventHandler<Path extends string, Schema extends AnyPondSchema = AnyPondSchema, Event extends EventKey<Schema> = EventKey<Schema>> = (event: OutgoingContext<Path, Schema, Event>, next: NextFunction) => EventPayload<EventsOf<Schema>, Event> | Promise<EventPayload<EventsOf<Schema>, Event>> | void | Promise<void>;
26
+ export type OutgoingEventHandler<Path extends string, Schema extends AnyPondSchema = AnyPondSchema, Event extends EventKey<Schema> = EventKey<Schema>> = (event: OutgoingHandlerContext<Path, Schema, Event>) => void | Promise<void>;
27
27
  export interface ConnectionParams {
28
28
  head: Buffer;
29
29
  socket: internal.Duplex;
@@ -65,4 +65,4 @@ export interface LeaveEvent {
65
65
  user: UserData<PondPresence, PondAssigns>;
66
66
  channel: Channel;
67
67
  }
68
- export type LeaveCallback = (event: LeaveEvent) => void;
68
+ export type LeaveCallback = (event: LeaveEvent) => unknown | Promise<unknown>;
@@ -14,12 +14,14 @@ export declare abstract class BaseContext<Path extends string, Schema extends An
14
14
  get channel(): Channel<Schema>;
15
15
  get presences(): UserPresences<PresenceOf<Schema>>;
16
16
  get assigns(): UserAssigns<AssignsOf<Schema>>;
17
- get user(): import("@eleven-am/pondsocket-common").UserData<PresenceOf<Schema>, AssignsOf<Schema>> | null;
17
+ get user(): import("@eleven-am/pondsocket-common").UserData<PresenceOf<Schema>, AssignsOf<Schema>>;
18
18
  broadcast<Event extends Extract<keyof EventsOf<Schema>, string>>(event: Event, payload: EventPayload<EventsOf<Schema>, Event>): this;
19
19
  broadcastFrom<Event extends Extract<keyof EventsOf<Schema>, string>>(event: Event, payload: EventPayload<EventsOf<Schema>, Event>): this;
20
20
  broadcastTo<Event extends Extract<keyof EventsOf<Schema>, string>>(event: Event, payload: EventPayload<EventsOf<Schema>, Event>, userIds: string | string[]): this;
21
21
  protected abstract _sendMessageToRecipients(recipient: ChannelReceivers, event: string, payload: PondObject): void;
22
22
  protected get engine(): ChannelEngine;
23
23
  protected get sender(): string;
24
+ protected get currentPayload(): Payload;
25
+ protected updatePayload(payload: Payload): void;
24
26
  protected updateParams(params: EventParams<Path>): void;
25
27
  }
@@ -76,6 +76,12 @@ class BaseContext {
76
76
  get sender() {
77
77
  return __classPrivateFieldGet(this, _BaseContext_sender, "f");
78
78
  }
79
+ get currentPayload() {
80
+ return __classPrivateFieldGet(this, _BaseContext_payload, "f");
81
+ }
82
+ updatePayload(payload) {
83
+ __classPrivateFieldSet(this, _BaseContext_payload, payload, "f");
84
+ }
79
85
  updateParams(params) {
80
86
  __classPrivateFieldSet(this, _BaseContext_params, params, "f");
81
87
  }
@@ -1,4 +1,4 @@
1
- import { ChannelReceivers, AnyPondSchema, AssignsOf, EventParams, EventPayload, EventsOf, PondObject, PresenceOf } from '@eleven-am/pondsocket-common';
1
+ import { ChannelReceivers, AnyPondSchema, AssignsOf, EventParams, EventPayload, EventReplyPayload, EventsOf, PondObject, PresenceOf } from '@eleven-am/pondsocket-common';
2
2
  import { BaseContext } from './baseContext';
3
3
  import { BroadcastEvent } from '../abstracts/types';
4
4
  import { ChannelEngine } from '../engines/channelEngine';
@@ -7,7 +7,7 @@ export declare class EventContext<Path extends string, Schema extends AnyPondSch
7
7
  constructor(event: BroadcastEvent, params: EventParams<Path>, engine: ChannelEngine);
8
8
  get payload(): EventPayload<EventsOf<Schema>, EventName>;
9
9
  assign(assigns: Partial<AssignsOf<Schema>>): EventContext<Path, Schema, EventName>;
10
- reply<Event extends Extract<keyof EventsOf<Schema>, string>>(event: Event, payload: EventPayload<EventsOf<Schema>, Event>): this;
10
+ reply<Event extends Extract<keyof EventsOf<Schema>, string>>(event: Event, payload: EventReplyPayload<EventsOf<Schema>, Event>): this;
11
11
  trackPresence(presence: PresenceOf<Schema>, userId?: string): EventContext<Path, Schema, EventName>;
12
12
  updatePresence(presence: Partial<PresenceOf<Schema>>, userId?: string): EventContext<Path, Schema, EventName>;
13
13
  evictUser(reason: string, userId?: string): EventContext<Path, Schema, EventName>;
@@ -51,7 +51,7 @@ class JoinContext extends baseContext_1.BaseContext {
51
51
  }
52
52
  __classPrivateFieldGet(this, _JoinContext_instances, "m", _JoinContext_performChecks).call(this);
53
53
  const onMessage = this.engine.parent.parent.sendMessage.bind(this.engine.parent.parent, __classPrivateFieldGet(this, _JoinContext_user, "f").socket);
54
- const subscription = this.engine.addUser(__classPrivateFieldGet(this, _JoinContext_user, "f").clientId, __classPrivateFieldGet(this, _JoinContext_newAssigns, "f"), onMessage);
54
+ const subscription = this.engine.addUser(__classPrivateFieldGet(this, _JoinContext_user, "f").clientId, __classPrivateFieldGet(this, _JoinContext_newAssigns, "f"), onMessage, __classPrivateFieldGet(this, _JoinContext_user, "f").requestId);
55
55
  const wrappedSubscription = () => {
56
56
  var _a;
57
57
  subscription();
@@ -68,8 +68,14 @@ class JoinContext extends baseContext_1.BaseContext {
68
68
  const errorMessage = {
69
69
  event: pondsocket_common_1.ErrorTypes.UNAUTHORIZED_JOIN_REQUEST,
70
70
  payload: {
71
+ code: pondsocket_common_1.ErrorTypes.UNAUTHORIZED_JOIN_REQUEST,
71
72
  message: message || 'Unauthorized connection',
72
- code: errorCode || 401,
73
+ status: errorCode || 401,
74
+ statusCode: errorCode || 401,
75
+ error: {
76
+ message: message || 'Unauthorized connection',
77
+ status: errorCode || 401,
78
+ },
73
79
  },
74
80
  channelName: this.engine.name,
75
81
  action: pondsocket_common_1.ServerActions.ERROR,
@@ -0,0 +1,36 @@
1
+ import { ChannelReceivers, AnyPondSchema, Event, EventParams, EventPayload, EventReplyPayload, EventsOf, PondEvent, PondMessage, PondObject, ServerActions } from '@eleven-am/pondsocket-common';
2
+ import { BaseContext } from './baseContext';
3
+ import { ChannelEngine } from '../engines/channelEngine';
4
+ export declare class OutgoingContext<Path extends string, Schema extends AnyPondSchema = AnyPondSchema, EventName extends Extract<keyof EventsOf<Schema>, string> = Extract<keyof EventsOf<Schema>, string>, Action extends Event['action'] = Event['action']> extends BaseContext<Path, Schema, EventName, OutgoingPayload<Schema, EventName, Action>> {
5
+ #private;
6
+ constructor(event: Event, params: EventParams<Path>, engine: ChannelEngine, userid: string);
7
+ get action(): Action;
8
+ get event(): PondEvent<Path> & {
9
+ action: Action;
10
+ event: EventName;
11
+ payload: OutgoingPayload<Schema, EventName, Action>;
12
+ };
13
+ get payload(): OutgoingPayload<Schema, EventName, Action>;
14
+ /**
15
+ * Blocks the outgoing context, preventing further processing of the event.
16
+ */
17
+ block(): this;
18
+ /**
19
+ * Checks if the outgoing context is blocked.
20
+ * @returns {boolean} - True if blocked, false otherwise.
21
+ */
22
+ isBlocked(): boolean;
23
+ /**
24
+ * Transforms the outgoing context with a new payload.
25
+ * @param payload - The new payload to set for the context.
26
+ */
27
+ transform(payload: OutgoingPayload<Schema, EventName, Action>): this;
28
+ /**
29
+ * Updates the parameters of the outgoing context.
30
+ * @param params - The new parameters to set for the context.
31
+ */
32
+ updateParams(params: EventParams<Path>): void;
33
+ protected _sendMessageToRecipients(_recipient: ChannelReceivers, _event: string, _payload: PondObject): void;
34
+ }
35
+ export type OutgoingPayload<Schema extends AnyPondSchema, EventName extends Extract<keyof EventsOf<Schema>, string>, Action extends Event['action']> = Action extends ServerActions.BROADCAST ? EventPayload<EventsOf<Schema>, EventName> : Action extends ServerActions.SYSTEM ? EventReplyPayload<EventsOf<Schema>, EventName> : PondMessage;
36
+ export type OutgoingHandlerContext<Path extends string, Schema extends AnyPondSchema, EventName extends Extract<keyof EventsOf<Schema>, string>> = OutgoingContext<Path, Schema, EventName, ServerActions.BROADCAST> | OutgoingContext<Path, Schema, EventName, ServerActions.SYSTEM>;
@@ -10,20 +10,26 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _OutgoingContext_payload, _OutgoingContext_isBlocked;
13
+ var _OutgoingContext_action, _OutgoingContext_isBlocked;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.OutgoingContext = void 0;
16
16
  const baseContext_1 = require("./baseContext");
17
17
  class OutgoingContext extends baseContext_1.BaseContext {
18
18
  constructor(event, params, engine, userid) {
19
19
  super(engine, params, event.event, event.payload, userid);
20
- _OutgoingContext_payload.set(this, void 0);
20
+ _OutgoingContext_action.set(this, void 0);
21
21
  _OutgoingContext_isBlocked.set(this, void 0);
22
- __classPrivateFieldSet(this, _OutgoingContext_payload, event.payload, "f");
22
+ __classPrivateFieldSet(this, _OutgoingContext_action, event.action, "f");
23
23
  __classPrivateFieldSet(this, _OutgoingContext_isBlocked, false, "f");
24
24
  }
25
+ get action() {
26
+ return __classPrivateFieldGet(this, _OutgoingContext_action, "f");
27
+ }
28
+ get event() {
29
+ return Object.assign(Object.assign({}, super.event), { action: __classPrivateFieldGet(this, _OutgoingContext_action, "f"), payload: this.currentPayload });
30
+ }
25
31
  get payload() {
26
- return __classPrivateFieldGet(this, _OutgoingContext_payload, "f");
32
+ return this.currentPayload;
27
33
  }
28
34
  /**
29
35
  * Blocks the outgoing context, preventing further processing of the event.
@@ -44,7 +50,7 @@ class OutgoingContext extends baseContext_1.BaseContext {
44
50
  * @param payload - The new payload to set for the context.
45
51
  */
46
52
  transform(payload) {
47
- __classPrivateFieldSet(this, _OutgoingContext_payload, payload, "f");
53
+ this.updatePayload(payload);
48
54
  return this;
49
55
  }
50
56
  /**
@@ -59,4 +65,4 @@ class OutgoingContext extends baseContext_1.BaseContext {
59
65
  }
60
66
  }
61
67
  exports.OutgoingContext = OutgoingContext;
62
- _OutgoingContext_payload = new WeakMap(), _OutgoingContext_isBlocked = new WeakMap();
68
+ _OutgoingContext_action = new WeakMap(), _OutgoingContext_isBlocked = new WeakMap();
@@ -8,7 +8,7 @@ export declare class ChannelEngine {
8
8
  constructor(parent: LobbyEngine, name: string, backend?: IDistributedBackend | null);
9
9
  get name(): string;
10
10
  get users(): Set<string>;
11
- addUser(userId: string, assigns: PondAssigns, onMessage: (event: ChannelEvent) => void): Unsubscribe;
11
+ addUser(userId: string, assigns: PondAssigns, onMessage: (event: ChannelEvent) => void, requestId?: string): Unsubscribe;
12
12
  sendMessage(sender: ChannelSenders, recipient: ChannelReceivers, action: ServerActions, event: string, payload: PondMessage, requestId?: string): void;
13
13
  broadcastMessage(userId: string, message: ClientMessage): void;
14
14
  trackPresence(userId: string, presence: PondPresence): void;
@@ -17,6 +17,8 @@ export declare class ChannelEngine {
17
17
  upsertPresence(userId: string, presence: PondPresence): void;
18
18
  updateAssigns(userId: string, assigns: PondMessage): void;
19
19
  kickUser(userId: string, reason: string): void;
20
+ requestUserRemoval(userId: string): void;
21
+ getUserAcrossNodes(userId: string, timeoutMs?: number): Promise<UserData | null>;
20
22
  getAssigns(): UserAssigns;
21
23
  getPresence(): UserPresences;
22
24
  destroy(reason?: string): void;