@pluv/io 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
 
2
- > @pluv/io@0.4.2 build /home/runner/work/pluv/pluv/packages/io
2
+ > @pluv/io@0.5.0 build /home/runner/work/pluv/pluv/packages/io
3
3
  > tsup src/index.ts --format esm,cjs --dts
4
4
 
5
5
  CLI Building entry: src/index.ts
@@ -8,10 +8,10 @@
8
8
  CLI Target: es6
9
9
  ESM Build start
10
10
  CJS Build start
11
- CJS dist/index.js 30.12 KB
12
- CJS ⚡️ Build success in 109ms
13
- ESM dist/index.mjs 28.06 KB
14
- ESM ⚡️ Build success in 112ms
11
+ CJS dist/index.js 30.95 KB
12
+ CJS ⚡️ Build success in 112ms
13
+ ESM dist/index.mjs 28.88 KB
14
+ ESM ⚡️ Build success in 129ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 3144ms
17
- DTS dist/index.d.ts 14.86 KB
16
+ DTS ⚡️ Build success in 3722ms
17
+ DTS dist/index.d.ts 16.78 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @pluv/io
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ae4e1f1: added platform-specific contexts to expose env in cloudflare and req in node.js
8
+
3
9
  ## 0.4.2
4
10
 
5
11
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { JsonObject, MaybePromise, IOEventMessage, EventRecord, InputZodLike, Id, IOLike, InferIOOutput, BaseUser, IOAuthorize, BaseIOAuthorize, InferIOInput, InferIOAuthorizeUser, InferIOAuthorize, Spread, InferIOOutputBroadcast, InferIOOutputSelf, InferIOOutputSync, Maybe, BaseClientEventRecord, BaseIOEventRecord } from '@pluv/types';
1
+ import { JsonObject, MaybePromise, IOEventMessage, EventRecord, InputZodLike, Id, IOLike, InferIOOutput, IOAuthorize, BaseIOAuthorize, InferIOInput, BaseUser, InferIOAuthorizeUser, InferIOAuthorize, Spread, InferIOOutputBroadcast, InferIOOutputSelf, InferIOOutputSync, Maybe, BaseClientEventRecord, BaseIOEventRecord } from '@pluv/types';
2
2
  export { BaseUser, EventMessage, EventRecord, IOEventMessage } from '@pluv/types';
3
3
  import { YjsDoc } from '@pluv/crdt-yjs';
4
4
 
@@ -79,12 +79,13 @@ declare global {
79
79
  log: (...data: any[]) => void;
80
80
  };
81
81
  }
82
- interface EventConfig<TContext extends JsonObject = {}, TData extends JsonObject = {}, TResultBroadcast extends EventRecord<string, any> = {}, TResultSelf extends EventRecord<string, any> = {}, TResultSync extends EventRecord<string, any> = {}> {
82
+ interface EventConfig<TPlatform extends AbstractPlatform = AbstractPlatform, TContext extends Record<string, any> = {}, TData extends JsonObject = {}, TResultBroadcast extends EventRecord<string, any> = {}, TResultSelf extends EventRecord<string, any> = {}, TResultSync extends EventRecord<string, any> = {}> {
83
83
  input?: InputZodLike<TData>;
84
- resolver: EventResolver<TContext, TData, TResultBroadcast> | EventResolverObject<TContext, TData, TResultBroadcast, TResultSelf, TResultSync>;
84
+ resolver: EventResolver<TContext & InferPlatformRoomContextType<TPlatform> & InferPlatformEventContextType<TPlatform>, TData, TResultBroadcast> | EventResolverObject<TPlatform, TContext, TData, TResultBroadcast, TResultSelf, TResultSync>;
85
85
  }
86
- type EventResolver<TContext extends JsonObject = {}, TData extends JsonObject = {}, TResultBroadcast extends EventRecord<string, any> = {}> = (data: TData, context: EventResolverContext<TContext>) => MaybePromise<TResultBroadcast | void>;
87
- interface EventResolverContext<TContext extends JsonObject = {}> {
86
+ type SyncEventResolver<TContext extends Record<string, any> = {}, TData extends JsonObject = {}, TResultBroadcast extends EventRecord<string, any> = {}> = (data: TData, context: EventResolverContext<TContext>) => MaybePromise<TResultBroadcast | void>;
87
+ type EventResolver<TContext extends Record<string, any> = {}, TData extends JsonObject = {}, TResultBroadcast extends EventRecord<string, any> = {}> = (data: TData, context: EventResolverContext<TContext>) => MaybePromise<TResultBroadcast | void>;
88
+ interface EventResolverContext<TContext extends Record<string, any> = {}> {
88
89
  context: TContext;
89
90
  doc: YjsDoc<any>;
90
91
  room: string;
@@ -103,13 +104,13 @@ interface EventResolverContext<TContext extends JsonObject = {}> {
103
104
  session: WebSocketSession | null;
104
105
  sessions: Map<string, WebSocketSession>;
105
106
  }
106
- type EventResolverObject<TContext extends JsonObject = {}, TData extends JsonObject = {}, TResultBroadcast extends EventRecord<string, any> = {}, TResultSelf extends EventRecord<string, any> = {}, TResultSync extends EventRecord<string, any> = {}> = {
107
- broadcast?: EventResolver<TContext, TData, TResultBroadcast>;
108
- self?: EventResolver<TContext, TData, TResultSelf>;
109
- sync?: EventResolver<TContext, TData, TResultSync>;
107
+ type EventResolverObject<TPlatform extends AbstractPlatform = AbstractPlatform, TContext extends Record<string, any> = {}, TData extends JsonObject = {}, TResultBroadcast extends EventRecord<string, any> = {}, TResultSelf extends EventRecord<string, any> = {}, TResultSync extends EventRecord<string, any> = {}> = {
108
+ broadcast?: EventResolver<TContext & InferPlatformRoomContextType<TPlatform> & InferPlatformEventContextType<TPlatform>, TData, TResultBroadcast>;
109
+ self?: EventResolver<TContext & InferPlatformRoomContextType<TPlatform> & InferPlatformEventContextType<TPlatform>, TData, TResultSelf>;
110
+ sync?: SyncEventResolver<TContext, TData, TResultSync>;
110
111
  };
111
- type InferEventConfig<TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutputBroadcast extends EventRecord<string, any> = {}, TOutputSelf extends EventRecord<string, any> = {}, TOutputSync extends EventRecord<string, any> = {}> = {
112
- [P in keyof TInput]: P extends string ? Id<EventConfig<TContext, TInput[P], TOutputBroadcast, TOutputSelf, TOutputSync>> : never;
112
+ type InferEventConfig<TPlatform extends AbstractPlatform = AbstractPlatform, TContext extends Record<string, any> = {}, TInput extends EventRecord<string, any> = {}, TOutputBroadcast extends EventRecord<string, any> = {}, TOutputSelf extends EventRecord<string, any> = {}, TOutputSync extends EventRecord<string, any> = {}> = {
113
+ [P in keyof TInput]: P extends string ? Id<EventConfig<TPlatform, TContext, TInput[P], TOutputBroadcast, TOutputSelf, TOutputSync>> : never;
113
114
  };
114
115
  type SendMessageOptions = {
115
116
  type?: "broadcast";
@@ -141,7 +142,9 @@ declare abstract class AbstractPubSub {
141
142
  abstract unsubscribe(subscriptionId: number): void;
142
143
  }
143
144
 
144
- type InferWebSocketType<TPlatform extends AbstractPlatform<any>> = TPlatform extends AbstractPlatform<infer IWebSocket> ? IWebSocket : never;
145
+ type InferPlatformWebSocketType<TPlatform extends AbstractPlatform> = TPlatform extends AbstractPlatform<infer IWebSocket> ? IWebSocket : never;
146
+ type InferPlatformRoomContextType<TPlatform extends AbstractPlatform> = TPlatform extends AbstractPlatform<any, infer IIOContext> ? IIOContext : never;
147
+ type InferPlatformEventContextType<TPlatform extends AbstractPlatform> = TPlatform extends AbstractPlatform<any, any, infer IRoomContext> ? IRoomContext : never;
145
148
  type AbstractPlatformConfig = {
146
149
  persistance?: undefined;
147
150
  pubSub?: undefined;
@@ -152,7 +155,9 @@ type AbstractPlatformConfig = {
152
155
  interface ConvertWebSocketConfig {
153
156
  room: string;
154
157
  }
155
- declare abstract class AbstractPlatform<TWebSocket = any> {
158
+ declare abstract class AbstractPlatform<TWebSocket = any, TIOContext extends Record<string, any> = {}, TRoomContext extends Record<string, any> = {}> {
159
+ readonly _ioContext: TIOContext | undefined;
160
+ readonly _roomContext: TRoomContext | undefined;
156
161
  persistance: AbstractPersistance;
157
162
  pubSub: AbstractPubSub;
158
163
  constructor(config?: AbstractPlatformConfig);
@@ -161,39 +166,24 @@ declare abstract class AbstractPlatform<TWebSocket = any> {
161
166
  abstract randomUUID(): string;
162
167
  }
163
168
 
164
- interface JWT<TUser extends BaseUser> {
165
- room: string;
166
- sub: string;
167
- user: TUser;
168
- }
169
- interface JWTEncodeParams<TUser extends BaseUser> {
170
- maxAge?: number;
169
+ type IORoomListenerEvent<TPlatform extends AbstractPlatform> = {
171
170
  room: string;
172
- user: TUser;
173
- }
174
- interface AuthorizeParams {
175
- platform: AbstractPlatform;
176
- secret: string;
177
- }
178
- interface AuthorizeModule {
179
- decode: <TUser extends BaseUser>(jwt: string) => Promise<TUser | null>;
180
- encode: <TUser extends BaseUser>(params: JWTEncodeParams<TUser>) => Promise<string>;
181
- }
182
-
183
- interface IORoomListeners {
184
- onDestroy: (encodedState: string) => void;
171
+ encodedState: string;
172
+ } & InferPlatformRoomContextType<TPlatform>;
173
+ interface IORoomListeners<TPlatform extends AbstractPlatform> {
174
+ onDestroy: (event: IORoomListenerEvent<TPlatform>) => void;
185
175
  }
186
- type IORoomConfig<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends IOAuthorize<any, any> = BaseIOAuthorize, TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutputBroadcast extends EventRecord<string, any> = {}, TOutputSelf extends EventRecord<string, any> = {}, TOutputSync extends EventRecord<string, any> = {}> = Partial<IORoomListeners> & {
176
+ type IORoomConfig<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends IOAuthorize<any, any> = BaseIOAuthorize, TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutputBroadcast extends EventRecord<string, any> = {}, TOutputSelf extends EventRecord<string, any> = {}, TOutputSync extends EventRecord<string, any> = {}> = Partial<IORoomListeners<TPlatform>> & {
187
177
  authorize?: TAuthorize;
188
- context: TContext;
178
+ context: TContext & InferPlatformRoomContextType<TPlatform>;
189
179
  debug: boolean;
190
- events: InferEventConfig<TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>;
180
+ events: InferEventConfig<TPlatform, TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>;
191
181
  platform: TPlatform;
192
182
  };
193
- interface WebsocketRegisterOptions {
183
+ type WebsocketRegisterOptions<TPlatform extends AbstractPlatform> = {
194
184
  token?: string | null;
195
- }
196
- declare class IORoom<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends IOAuthorize<any, any> = BaseIOAuthorize, TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutputBroadcast extends EventRecord<string, any> = {}, TOutputSelf extends EventRecord<string, any> = {}, TOutputSync extends EventRecord<string, any> = {}> implements IOLike<TAuthorize, TInput, TOutputBroadcast, TOutputSelf, TOutputSync> {
185
+ } & InferPlatformRoomContextType<TPlatform> & InferPlatformEventContextType<TPlatform>;
186
+ declare class IORoom<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends IOAuthorize<any, any> = BaseIOAuthorize, TContext extends Record<string, any> = {}, TInput extends EventRecord<string, any> = {}, TOutputBroadcast extends EventRecord<string, any> = {}, TOutputSelf extends EventRecord<string, any> = {}, TOutputSync extends EventRecord<string, any> = {}> implements IOLike<TAuthorize, TInput, TOutputBroadcast, TOutputSelf, TOutputSync> {
197
187
  private readonly _context;
198
188
  private readonly _debug;
199
189
  private readonly _platform;
@@ -202,12 +192,12 @@ declare class IORoom<TPlatform extends AbstractPlatform<any> = AbstractPlatform<
202
192
  private _sessions;
203
193
  private _uninitialize;
204
194
  readonly _authorize: TAuthorize | null;
205
- readonly _events: InferEventConfig<TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>;
195
+ readonly _events: InferEventConfig<TPlatform, TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>;
206
196
  readonly id: string;
207
197
  constructor(id: string, config: IORoomConfig<TPlatform, TAuthorize, TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>);
208
198
  broadcast<TEvent extends keyof InferIOInput<this>>(event: TEvent, data: Id<InferIOInput<this>[TEvent]>): Promise<void>;
209
199
  getSize(): number;
210
- register(webSocket: InferWebSocketType<TPlatform>, options?: WebsocketRegisterOptions): Promise<void>;
200
+ register(webSocket: InferPlatformWebSocketType<TPlatform>, options: WebsocketRegisterOptions<TPlatform>): Promise<void>;
211
201
  private _broadcast;
212
202
  private _emitQuitters;
213
203
  private _emitRegistered;
@@ -226,49 +216,68 @@ declare class IORoom<TPlatform extends AbstractPlatform<any> = AbstractPlatform<
226
216
  private _sendSyncMessage;
227
217
  }
228
218
 
219
+ interface JWT<TUser extends BaseUser> {
220
+ room: string;
221
+ sub: string;
222
+ user: TUser;
223
+ }
224
+ interface JWTEncodeParams<TUser extends BaseUser> {
225
+ maxAge?: number;
226
+ room: string;
227
+ user: TUser;
228
+ }
229
+ interface AuthorizeParams {
230
+ platform: AbstractPlatform;
231
+ secret: string;
232
+ }
233
+ interface AuthorizeModule {
234
+ decode: <TUser extends BaseUser>(jwt: string) => Promise<TUser | null>;
235
+ encode: <TUser extends BaseUser>(params: JWTEncodeParams<TUser>) => Promise<string>;
236
+ }
237
+
229
238
  type InferIOContext<TIO extends PluvIO<any, any, any, any, any, any, any>> = TIO extends PluvIO<any, any, infer IContext, any, any, any, any> ? IContext : never;
230
239
  type InferIOPlatform<TIO extends PluvIO<any, any, any, any, any, any, any>> = TIO extends PluvIO<infer IPlatform, any, any, any, any, any, any> ? IPlatform : never;
231
240
  type InferIORoom<TIO extends PluvIO<any, any, any, any, any, any, any>> = TIO extends PluvIO<infer IPlatform, infer IAuthorize, infer IContext, infer IInput, infer IOutputBroadcast, infer IOutputSelf, infer IOutputSync> ? IORoom<IPlatform, IAuthorize, IContext, IInput, IOutputBroadcast, IOutputSelf, IOutputSync> : never;
232
- interface PluvIOListeners {
233
- onRoomDeleted: (room: string, encodedState: string) => void;
234
- onStorageUpdated: (room: string, encodedState: string) => void;
241
+ interface PluvIOListeners<TPlatform extends AbstractPlatform> {
242
+ onRoomDeleted: (event: IORoomListenerEvent<TPlatform>) => void;
243
+ onStorageUpdated: (event: IORoomListenerEvent<TPlatform>) => void;
235
244
  }
236
- type PluvIOConfig<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends IOAuthorize<any, any> | null = null, TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutputBroadcast extends EventRecord<string, any> = {}, TOutputSelf extends EventRecord<string, any> = {}, TOutputSync extends EventRecord<string, any> = {}> = Partial<PluvIOListeners> & {
245
+ type PluvIOConfig<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends IOAuthorize<any, any> | null = null, TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutputBroadcast extends EventRecord<string, any> = {}, TOutputSelf extends EventRecord<string, any> = {}, TOutputSync extends EventRecord<string, any> = {}> = Partial<PluvIOListeners<TPlatform>> & {
237
246
  authorize?: TAuthorize;
238
247
  context?: TContext;
239
248
  debug?: boolean;
240
- events?: InferEventConfig<TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>;
249
+ events?: InferEventConfig<TPlatform, TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>;
241
250
  initialStorage?: (room: string) => MaybePromise<Maybe<string>>;
242
251
  platform: TPlatform;
243
252
  };
244
- interface GetRoomOptions {
253
+ type GetRoomOptions<TPlatform extends AbstractPlatform> = {
245
254
  debug?: boolean;
246
- }
255
+ } & InferPlatformRoomContextType<TPlatform>;
247
256
  declare class PluvIO<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends IOAuthorize<any, any> = BaseIOAuthorize, TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutputBroadcast extends EventRecord<string, any> = {}, TOutputSelf extends EventRecord<string, any> = {}, TOutputSync extends EventRecord<string, any> = {}> implements IOLike<TAuthorize, TInput, TOutputBroadcast, TOutputSelf, TOutputSync> {
248
257
  private _context;
249
258
  private _initialStorage;
250
259
  private _rooms;
251
260
  readonly _authorize: TAuthorize | null;
252
261
  readonly _debug: boolean;
253
- readonly _events: InferEventConfig<TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>;
254
- readonly _listeners: PluvIOListeners;
262
+ readonly _events: InferEventConfig<TPlatform, TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>;
263
+ readonly _listeners: PluvIOListeners<TPlatform>;
255
264
  readonly _platform: TPlatform;
256
265
  constructor(options: PluvIOConfig<TPlatform, TAuthorize, TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>);
257
266
  createToken(params: JWTEncodeParams<InferIOAuthorizeUser<InferIOAuthorize<this>>>): Promise<string>;
258
- event<TEvent extends string, TData extends JsonObject = {}, TResultBroadcast extends EventRecord<string, any> = {}, TResultSelf extends EventRecord<string, any> = {}, TResultSync extends EventRecord<string, any> = {}>(event: TEvent, config: EventConfig<TContext, TData, TResultBroadcast, TResultSelf, TResultSync>): PluvIO<TPlatform, TAuthorize, TContext, Spread<[TInput, EventRecord<TEvent, TData>]>, Spread<[TOutputBroadcast, TResultBroadcast]>, Spread<[TOutputSelf, TResultSelf]>, Spread<[TOutputSync, TResultSync]>>;
259
- getRoom(room: string, options?: GetRoomOptions): IORoom<TPlatform, TAuthorize, TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>;
267
+ event<TEvent extends string, TData extends JsonObject = {}, TResultBroadcast extends EventRecord<string, any> = {}, TResultSelf extends EventRecord<string, any> = {}, TResultSync extends EventRecord<string, any> = {}>(event: TEvent, config: EventConfig<TPlatform, TContext, TData, TResultBroadcast, TResultSelf, TResultSync>): PluvIO<TPlatform, TAuthorize, TContext, Spread<[TInput, EventRecord<TEvent, TData>]>, Spread<[TOutputBroadcast, TResultBroadcast]>, Spread<[TOutputSelf, TResultSelf]>, Spread<[TOutputSync, TResultSync]>>;
268
+ getRoom(room: string, options: GetRoomOptions<TPlatform>): IORoom<TPlatform, TAuthorize, TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>;
260
269
  static merge<TIO1 extends PluvIO, TIO2 extends PluvIO>(first: TIO1, second: TIO2): PluvIO<InferIOPlatform<TIO1>, InferIOAuthorize<TIO1>, InferIOContext<TIO1>, Spread<[InferIOInput<TIO1>, InferIOInput<TIO2>]>, Spread<[InferIOOutputBroadcast<TIO1>, InferIOOutputBroadcast<TIO2>]>, Spread<[InferIOOutputSelf<TIO1>, InferIOOutputSelf<TIO2>]>, Spread<[InferIOOutputSync<TIO1>, InferIOOutputSync<TIO2>]>>;
261
270
  private _logDebug;
262
271
  private _purgeEmptyRooms;
263
272
  }
264
273
 
265
- type CreateIOParams<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TContext extends JsonObject = {}, TAuthorizeUser extends BaseUser = BaseUser, TAuthorizeRequired extends boolean = false> = Partial<PluvIOListeners> & {
274
+ type CreateIOParams<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TContext extends JsonObject = {}, TAuthorizeUser extends BaseUser = BaseUser, TAuthorizeRequired extends boolean = false> = Partial<PluvIOListeners<TPlatform>> & {
266
275
  authorize?: IOAuthorize<TAuthorizeUser, TAuthorizeRequired>;
267
276
  context?: TContext;
268
277
  debug?: boolean;
269
278
  initialStorage?: (room: string) => MaybePromise<Maybe<string>>;
270
279
  platform: TPlatform;
271
280
  };
272
- declare const createIO: <TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TContext extends JsonObject = {}, TAuthorizeUser extends BaseUser = BaseUser, TAuthorizeRequired extends boolean = false>(params: CreateIOParams<TPlatform, TContext, TAuthorizeUser, TAuthorizeRequired>) => PluvIO<TPlatform, IOAuthorize<TAuthorizeUser, TAuthorizeRequired>, TContext, BaseClientEventRecord, BaseIOEventRecord<IOAuthorize<TAuthorizeUser, TAuthorizeRequired>>, {}, {}>;
281
+ declare const createIO: <TPlatform extends AbstractPlatform<any, {}, {}> = AbstractPlatform<any, {}, {}>, TContext extends JsonObject = {}, TAuthorizeUser extends BaseUser = BaseUser, TAuthorizeRequired extends boolean = false>(params: CreateIOParams<TPlatform, TContext, TAuthorizeUser, TAuthorizeRequired>) => PluvIO<TPlatform, IOAuthorize<TAuthorizeUser, TAuthorizeRequired>, TContext, BaseClientEventRecord, BaseIOEventRecord<IOAuthorize<TAuthorizeUser, TAuthorizeRequired>>, {}, {}>;
273
282
 
274
- export { AbstractCloseEvent, AbstractErrorEvent, AbstractEvent, AbstractEventMap, AbstractListener, AbstractMessageEvent, AbstractPersistance, AbstractPlatform, AbstractPubSub, AbstractWebSocket, AbstractWebSocketConfig, AbstractWebSocketHandleErrorParams, AuthorizeModule, AuthorizeParams, ConvertWebSocketConfig, CreateIOParams, GetRoomOptions, IOPubSubEventMessage, IORoom, InferIORoom, InferWebSocketType, JWT, JWTEncodeParams, PluvIO, createIO };
283
+ export { AbstractCloseEvent, AbstractErrorEvent, AbstractEvent, AbstractEventMap, AbstractListener, AbstractMessageEvent, AbstractPersistance, AbstractPlatform, AbstractPubSub, AbstractWebSocket, AbstractWebSocketConfig, AbstractWebSocketHandleErrorParams, AuthorizeModule, AuthorizeParams, ConvertWebSocketConfig, CreateIOParams, GetRoomOptions, IOPubSubEventMessage, IORoom, InferIORoom, InferPlatformEventContextType, InferPlatformRoomContextType, InferPlatformWebSocketType, JWT, JWTEncodeParams, PluvIO, createIO };
package/dist/index.js CHANGED
@@ -316,9 +316,7 @@ var IORoom = class {
316
316
  this._platform = platform;
317
317
  this.id = id;
318
318
  this._listeners = {
319
- onDestroy: (encodedState) => {
320
- onDestroy == null ? void 0 : onDestroy(encodedState);
321
- }
319
+ onDestroy: (event) => onDestroy == null ? void 0 : onDestroy(event)
322
320
  };
323
321
  if (authorize2)
324
322
  this._authorize = authorize2;
@@ -337,10 +335,11 @@ var IORoom = class {
337
335
  }
338
336
  register(webSocket, options) {
339
337
  return __async(this, null, function* () {
340
- var _a;
338
+ var _b;
339
+ const _a = options, { token } = _a, _platformEventContext = __objRest(_a, ["token"]);
340
+ const platformEventContext = _platformEventContext;
341
341
  if (!this._uninitialize)
342
342
  yield this._initialize();
343
- const token = options == null ? void 0 : options.token;
344
343
  const sessionId = this._platform.randomUUID();
345
344
  const pluvWs = this._platform.convertWebSocket(webSocket, {
346
345
  room: this.id
@@ -352,7 +351,7 @@ var IORoom = class {
352
351
  );
353
352
  const uninitializeWs = yield pluvWs.initialize();
354
353
  const user = yield this._getAuthorizedUser(token);
355
- const isUnauthorized = !!((_a = this._authorize) == null ? void 0 : _a.required) && !user;
354
+ const isUnauthorized = !!((_b = this._authorize) == null ? void 0 : _b.required) && !user;
356
355
  const isTokenInUse = !!user && Array.from(this._sessions.values()).some(
357
356
  (session2) => {
358
357
  var _a2;
@@ -388,7 +387,9 @@ var IORoom = class {
388
387
  user != null ? user : {}
389
388
  );
390
389
  const onClose = this._onClose(session, uninitializeWs).bind(this);
391
- const onMessage = this._onMessage(session).bind(this);
390
+ const onMessage = this._onMessage(session, platformEventContext).bind(
391
+ this
392
+ );
392
393
  pluvWs.addEventListener("close", onClose);
393
394
  pluvWs.addEventListener("error", onClose);
394
395
  pluvWs.addEventListener("message", onMessage);
@@ -514,7 +515,10 @@ var IORoom = class {
514
515
  const encodedState = this._doc.encodeStateAsUpdate();
515
516
  this._doc.destroy();
516
517
  this._doc = (0, import_crdt_yjs.doc)();
517
- this._listeners.onDestroy(encodedState);
518
+ this._listeners.onDestroy(__spreadProps(__spreadValues({}, this._context), {
519
+ encodedState,
520
+ room: this.id
521
+ }));
518
522
  this._uninitialize = null;
519
523
  });
520
524
  });
@@ -558,10 +562,10 @@ var IORoom = class {
558
562
  });
559
563
  };
560
564
  }
561
- _onMessage(session) {
565
+ _onMessage(session, platformEventContext) {
562
566
  return (event) => {
563
567
  var _a, _b, _c;
564
- const context = {
568
+ const baseContext = {
565
569
  context: this._context,
566
570
  doc: this._doc,
567
571
  room: this.id,
@@ -589,10 +593,13 @@ var IORoom = class {
589
593
  });
590
594
  return;
591
595
  }
596
+ const extendedContext = __spreadProps(__spreadValues({}, baseContext), {
597
+ context: __spreadValues(__spreadValues({}, this._context), platformEventContext)
598
+ });
592
599
  Promise.all([
593
- (_a = resolver.broadcast) == null ? void 0 : _a.call(resolver, inputs, context),
594
- (_b = resolver.self) == null ? void 0 : _b.call(resolver, inputs, context),
595
- (_c = resolver.sync) == null ? void 0 : _c.call(resolver, inputs, context)
600
+ (_a = resolver.broadcast) == null ? void 0 : _a.call(resolver, inputs, extendedContext),
601
+ (_b = resolver.self) == null ? void 0 : _b.call(resolver, inputs, extendedContext),
602
+ (_c = resolver.sync) == null ? void 0 : _c.call(resolver, inputs, baseContext)
596
603
  ]).then(([broadcast, self, sync]) => {
597
604
  if (broadcast) {
598
605
  Object.entries(broadcast).forEach(([type, data]) => {
@@ -759,7 +766,7 @@ var PluvIO = class {
759
766
  }
760
767
  };
761
768
  },
762
- self: (_0, _1) => __async(this, [_0, _1], function* ({ update }, { doc: doc2, room }) {
769
+ self: (_0, _1) => __async(this, [_0, _1], function* ({ update }, { context, doc: doc2, room }) {
763
770
  var _a, _b;
764
771
  const oldState = yield this._platform.persistance.getStorageState(room);
765
772
  const updates = [
@@ -767,12 +774,15 @@ var PluvIO = class {
767
774
  update
768
775
  ];
769
776
  if (updates.some((_update) => !!_update)) {
770
- const state2 = updates.reduce((_doc, _up) => _doc.applyUpdate(_up), doc2).encodeStateAsUpdate();
777
+ const encodedState = updates.reduce((_doc, _up) => _doc.applyUpdate(_up), doc2).encodeStateAsUpdate();
771
778
  yield this._platform.persistance.setStorageState(
772
779
  room,
773
- state2
780
+ encodedState
774
781
  );
775
- this._listeners.onStorageUpdated(room, state2);
782
+ this._listeners.onStorageUpdated(__spreadProps(__spreadValues({}, context), {
783
+ encodedState,
784
+ room
785
+ }));
776
786
  }
777
787
  const state = (_b = yield this._platform.persistance.getStorageState(
778
788
  room
@@ -805,16 +815,19 @@ var PluvIO = class {
805
815
  }
806
816
  },
807
817
  $UPDATE_STORAGE: {
808
- resolver: ({ origin, update }, { doc: doc2, room }) => {
818
+ resolver: ({ origin, update }, { context, doc: doc2, room }) => {
809
819
  if (origin === "$STORAGE_RECEIVED" && Object.keys(doc2.toJSON()).length) {
810
820
  return;
811
821
  }
812
822
  const updated = doc2.applyUpdate(update);
813
- const state = updated.encodeStateAsUpdate();
814
- this._platform.persistance.setStorageState(room, state).then(() => {
815
- this._listeners.onStorageUpdated(room, state);
823
+ const encodedState = updated.encodeStateAsUpdate();
824
+ this._platform.persistance.setStorageState(room, encodedState).then(() => {
825
+ this._listeners.onStorageUpdated(__spreadProps(__spreadValues({}, context), {
826
+ encodedState,
827
+ room
828
+ }));
816
829
  });
817
- return { $STORAGE_UPDATED: { state } };
830
+ return { $STORAGE_UPDATED: { state: encodedState } };
818
831
  }
819
832
  }
820
833
  };
@@ -839,12 +852,8 @@ var PluvIO = class {
839
852
  if (initialStorage)
840
853
  this._initialStorage = initialStorage;
841
854
  this._listeners = {
842
- onRoomDeleted: (room, encodedState) => {
843
- return onRoomDeleted == null ? void 0 : onRoomDeleted(room, encodedState);
844
- },
845
- onStorageUpdated: (room, encodedState) => {
846
- return onStorageUpdated == null ? void 0 : onStorageUpdated(room, encodedState);
847
- }
855
+ onRoomDeleted: (event) => onRoomDeleted == null ? void 0 : onRoomDeleted(event),
856
+ onStorageUpdated: (event) => onStorageUpdated == null ? void 0 : onStorageUpdated(event)
848
857
  };
849
858
  }
850
859
  createToken(params) {
@@ -875,9 +884,9 @@ var PluvIO = class {
875
884
  })
876
885
  );
877
886
  }
878
- getRoom(room, options = {}) {
879
- var _a;
880
- const { debug } = options;
887
+ getRoom(room, options) {
888
+ var _b;
889
+ const _a = options, { debug } = _a, platformRoomContext = __objRest(_a, ["debug"]);
881
890
  this._purgeEmptyRooms();
882
891
  if (!/^[a-z0-9]+[a-z0-9\-_]+[a-z0-9]+$/i.test(room)) {
883
892
  throw new Error("Unsupported room name");
@@ -886,20 +895,25 @@ var PluvIO = class {
886
895
  const oldRoom = this._rooms.get(room);
887
896
  if (oldRoom)
888
897
  return oldRoom;
898
+ const roomContext = __spreadValues(__spreadValues({}, this._context), platformRoomContext);
889
899
  const newRoom = new IORoom(room, {
890
- authorize: (_a = this._authorize) != null ? _a : void 0,
891
- context: this._context,
900
+ authorize: (_b = this._authorize) != null ? _b : void 0,
901
+ context: roomContext,
892
902
  debug: debug != null ? debug : this._debug,
893
903
  events: this._events,
894
- onDestroy: (encodedState) => {
904
+ onDestroy: ({ encodedState, room: room2 }) => {
895
905
  this._logDebug(
896
- `${import_kleur2.default.blue("Deleting empty room:")} ${room}`
906
+ `${import_kleur2.default.blue("Deleting empty room:")} ${room2}`
897
907
  );
898
- this._rooms.delete(room);
899
- this._listeners.onRoomDeleted(room, encodedState);
908
+ const roomContext2 = __spreadValues({
909
+ room: room2,
910
+ encodedState
911
+ }, platformRoomContext);
912
+ this._rooms.delete(room2);
913
+ this._listeners.onRoomDeleted(roomContext2);
900
914
  if (this._debug) {
901
915
  const rooms = Array.from(this._rooms.keys());
902
- this._logDebug(`${import_kleur2.default.blue("Deleted room:")} ${room}`);
916
+ this._logDebug(`${import_kleur2.default.blue("Deleted room:")} ${room2}`);
903
917
  this._logDebug(
904
918
  `${import_kleur2.default.blue("Rooms available:")} ${rooms.join(", ")}`
905
919
  );
package/dist/index.mjs CHANGED
@@ -279,9 +279,7 @@ var IORoom = class {
279
279
  this._platform = platform;
280
280
  this.id = id;
281
281
  this._listeners = {
282
- onDestroy: (encodedState) => {
283
- onDestroy == null ? void 0 : onDestroy(encodedState);
284
- }
282
+ onDestroy: (event) => onDestroy == null ? void 0 : onDestroy(event)
285
283
  };
286
284
  if (authorize2)
287
285
  this._authorize = authorize2;
@@ -300,10 +298,11 @@ var IORoom = class {
300
298
  }
301
299
  register(webSocket, options) {
302
300
  return __async(this, null, function* () {
303
- var _a;
301
+ var _b;
302
+ const _a = options, { token } = _a, _platformEventContext = __objRest(_a, ["token"]);
303
+ const platformEventContext = _platformEventContext;
304
304
  if (!this._uninitialize)
305
305
  yield this._initialize();
306
- const token = options == null ? void 0 : options.token;
307
306
  const sessionId = this._platform.randomUUID();
308
307
  const pluvWs = this._platform.convertWebSocket(webSocket, {
309
308
  room: this.id
@@ -315,7 +314,7 @@ var IORoom = class {
315
314
  );
316
315
  const uninitializeWs = yield pluvWs.initialize();
317
316
  const user = yield this._getAuthorizedUser(token);
318
- const isUnauthorized = !!((_a = this._authorize) == null ? void 0 : _a.required) && !user;
317
+ const isUnauthorized = !!((_b = this._authorize) == null ? void 0 : _b.required) && !user;
319
318
  const isTokenInUse = !!user && Array.from(this._sessions.values()).some(
320
319
  (session2) => {
321
320
  var _a2;
@@ -351,7 +350,9 @@ var IORoom = class {
351
350
  user != null ? user : {}
352
351
  );
353
352
  const onClose = this._onClose(session, uninitializeWs).bind(this);
354
- const onMessage = this._onMessage(session).bind(this);
353
+ const onMessage = this._onMessage(session, platformEventContext).bind(
354
+ this
355
+ );
355
356
  pluvWs.addEventListener("close", onClose);
356
357
  pluvWs.addEventListener("error", onClose);
357
358
  pluvWs.addEventListener("message", onMessage);
@@ -477,7 +478,10 @@ var IORoom = class {
477
478
  const encodedState = this._doc.encodeStateAsUpdate();
478
479
  this._doc.destroy();
479
480
  this._doc = doc();
480
- this._listeners.onDestroy(encodedState);
481
+ this._listeners.onDestroy(__spreadProps(__spreadValues({}, this._context), {
482
+ encodedState,
483
+ room: this.id
484
+ }));
481
485
  this._uninitialize = null;
482
486
  });
483
487
  });
@@ -521,10 +525,10 @@ var IORoom = class {
521
525
  });
522
526
  };
523
527
  }
524
- _onMessage(session) {
528
+ _onMessage(session, platformEventContext) {
525
529
  return (event) => {
526
530
  var _a, _b, _c;
527
- const context = {
531
+ const baseContext = {
528
532
  context: this._context,
529
533
  doc: this._doc,
530
534
  room: this.id,
@@ -552,10 +556,13 @@ var IORoom = class {
552
556
  });
553
557
  return;
554
558
  }
559
+ const extendedContext = __spreadProps(__spreadValues({}, baseContext), {
560
+ context: __spreadValues(__spreadValues({}, this._context), platformEventContext)
561
+ });
555
562
  Promise.all([
556
- (_a = resolver.broadcast) == null ? void 0 : _a.call(resolver, inputs, context),
557
- (_b = resolver.self) == null ? void 0 : _b.call(resolver, inputs, context),
558
- (_c = resolver.sync) == null ? void 0 : _c.call(resolver, inputs, context)
563
+ (_a = resolver.broadcast) == null ? void 0 : _a.call(resolver, inputs, extendedContext),
564
+ (_b = resolver.self) == null ? void 0 : _b.call(resolver, inputs, extendedContext),
565
+ (_c = resolver.sync) == null ? void 0 : _c.call(resolver, inputs, baseContext)
559
566
  ]).then(([broadcast, self, sync]) => {
560
567
  if (broadcast) {
561
568
  Object.entries(broadcast).forEach(([type, data]) => {
@@ -722,7 +729,7 @@ var PluvIO = class {
722
729
  }
723
730
  };
724
731
  },
725
- self: (_0, _1) => __async(this, [_0, _1], function* ({ update }, { doc: doc2, room }) {
732
+ self: (_0, _1) => __async(this, [_0, _1], function* ({ update }, { context, doc: doc2, room }) {
726
733
  var _a, _b;
727
734
  const oldState = yield this._platform.persistance.getStorageState(room);
728
735
  const updates = [
@@ -730,12 +737,15 @@ var PluvIO = class {
730
737
  update
731
738
  ];
732
739
  if (updates.some((_update) => !!_update)) {
733
- const state2 = updates.reduce((_doc, _up) => _doc.applyUpdate(_up), doc2).encodeStateAsUpdate();
740
+ const encodedState = updates.reduce((_doc, _up) => _doc.applyUpdate(_up), doc2).encodeStateAsUpdate();
734
741
  yield this._platform.persistance.setStorageState(
735
742
  room,
736
- state2
743
+ encodedState
737
744
  );
738
- this._listeners.onStorageUpdated(room, state2);
745
+ this._listeners.onStorageUpdated(__spreadProps(__spreadValues({}, context), {
746
+ encodedState,
747
+ room
748
+ }));
739
749
  }
740
750
  const state = (_b = yield this._platform.persistance.getStorageState(
741
751
  room
@@ -768,16 +778,19 @@ var PluvIO = class {
768
778
  }
769
779
  },
770
780
  $UPDATE_STORAGE: {
771
- resolver: ({ origin, update }, { doc: doc2, room }) => {
781
+ resolver: ({ origin, update }, { context, doc: doc2, room }) => {
772
782
  if (origin === "$STORAGE_RECEIVED" && Object.keys(doc2.toJSON()).length) {
773
783
  return;
774
784
  }
775
785
  const updated = doc2.applyUpdate(update);
776
- const state = updated.encodeStateAsUpdate();
777
- this._platform.persistance.setStorageState(room, state).then(() => {
778
- this._listeners.onStorageUpdated(room, state);
786
+ const encodedState = updated.encodeStateAsUpdate();
787
+ this._platform.persistance.setStorageState(room, encodedState).then(() => {
788
+ this._listeners.onStorageUpdated(__spreadProps(__spreadValues({}, context), {
789
+ encodedState,
790
+ room
791
+ }));
779
792
  });
780
- return { $STORAGE_UPDATED: { state } };
793
+ return { $STORAGE_UPDATED: { state: encodedState } };
781
794
  }
782
795
  }
783
796
  };
@@ -802,12 +815,8 @@ var PluvIO = class {
802
815
  if (initialStorage)
803
816
  this._initialStorage = initialStorage;
804
817
  this._listeners = {
805
- onRoomDeleted: (room, encodedState) => {
806
- return onRoomDeleted == null ? void 0 : onRoomDeleted(room, encodedState);
807
- },
808
- onStorageUpdated: (room, encodedState) => {
809
- return onStorageUpdated == null ? void 0 : onStorageUpdated(room, encodedState);
810
- }
818
+ onRoomDeleted: (event) => onRoomDeleted == null ? void 0 : onRoomDeleted(event),
819
+ onStorageUpdated: (event) => onStorageUpdated == null ? void 0 : onStorageUpdated(event)
811
820
  };
812
821
  }
813
822
  createToken(params) {
@@ -838,9 +847,9 @@ var PluvIO = class {
838
847
  })
839
848
  );
840
849
  }
841
- getRoom(room, options = {}) {
842
- var _a;
843
- const { debug } = options;
850
+ getRoom(room, options) {
851
+ var _b;
852
+ const _a = options, { debug } = _a, platformRoomContext = __objRest(_a, ["debug"]);
844
853
  this._purgeEmptyRooms();
845
854
  if (!/^[a-z0-9]+[a-z0-9\-_]+[a-z0-9]+$/i.test(room)) {
846
855
  throw new Error("Unsupported room name");
@@ -849,20 +858,25 @@ var PluvIO = class {
849
858
  const oldRoom = this._rooms.get(room);
850
859
  if (oldRoom)
851
860
  return oldRoom;
861
+ const roomContext = __spreadValues(__spreadValues({}, this._context), platformRoomContext);
852
862
  const newRoom = new IORoom(room, {
853
- authorize: (_a = this._authorize) != null ? _a : void 0,
854
- context: this._context,
863
+ authorize: (_b = this._authorize) != null ? _b : void 0,
864
+ context: roomContext,
855
865
  debug: debug != null ? debug : this._debug,
856
866
  events: this._events,
857
- onDestroy: (encodedState) => {
867
+ onDestroy: ({ encodedState, room: room2 }) => {
858
868
  this._logDebug(
859
- `${colors2.blue("Deleting empty room:")} ${room}`
869
+ `${colors2.blue("Deleting empty room:")} ${room2}`
860
870
  );
861
- this._rooms.delete(room);
862
- this._listeners.onRoomDeleted(room, encodedState);
871
+ const roomContext2 = __spreadValues({
872
+ room: room2,
873
+ encodedState
874
+ }, platformRoomContext);
875
+ this._rooms.delete(room2);
876
+ this._listeners.onRoomDeleted(roomContext2);
863
877
  if (this._debug) {
864
878
  const rooms = Array.from(this._rooms.keys());
865
- this._logDebug(`${colors2.blue("Deleted room:")} ${room}`);
879
+ this._logDebug(`${colors2.blue("Deleted room:")} ${room2}`);
866
880
  this._logDebug(
867
881
  `${colors2.blue("Rooms available:")} ${rooms.join(", ")}`
868
882
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluv/io",
3
- "version": "0.4.2",
3
+ "version": "0.5.0",
4
4
  "description": "@pluv/io server-side websocket manager",
5
5
  "author": "leedavidcs",
6
6
  "license": "MIT",
@@ -4,9 +4,19 @@ import type { AbstractWebSocket } from "./AbstractWebSocket";
4
4
  import { Persistance } from "./Persistance";
5
5
  import { PubSub } from "./PubSub";
6
6
 
7
- export type InferWebSocketType<TPlatform extends AbstractPlatform<any>> =
7
+ export type InferPlatformWebSocketType<TPlatform extends AbstractPlatform> =
8
8
  TPlatform extends AbstractPlatform<infer IWebSocket> ? IWebSocket : never;
9
9
 
10
+ export type InferPlatformRoomContextType<TPlatform extends AbstractPlatform> =
11
+ TPlatform extends AbstractPlatform<any, infer IIOContext>
12
+ ? IIOContext
13
+ : never;
14
+
15
+ export type InferPlatformEventContextType<TPlatform extends AbstractPlatform> =
16
+ TPlatform extends AbstractPlatform<any, any, infer IRoomContext>
17
+ ? IRoomContext
18
+ : never;
19
+
10
20
  export type AbstractPlatformConfig =
11
21
  | { persistance?: undefined; pubSub?: undefined }
12
22
  | {
@@ -18,7 +28,14 @@ export interface ConvertWebSocketConfig {
18
28
  room: string;
19
29
  }
20
30
 
21
- export abstract class AbstractPlatform<TWebSocket = any> {
31
+ export abstract class AbstractPlatform<
32
+ TWebSocket = any,
33
+ TIOContext extends Record<string, any> = {},
34
+ TRoomContext extends Record<string, any> = {}
35
+ > {
36
+ readonly _ioContext: TIOContext | undefined;
37
+ readonly _roomContext: TRoomContext | undefined;
38
+
22
39
  public persistance: AbstractPersistance;
23
40
  public pubSub: AbstractPubSub;
24
41
 
package/src/IORoom.ts CHANGED
@@ -14,11 +14,15 @@ import type {
14
14
  IOLike,
15
15
  JsonObject,
16
16
  Maybe,
17
- MaybePromise,
18
- Spread,
19
17
  } from "@pluv/types";
20
18
  import colors from "kleur";
21
- import type { AbstractPlatform, InferWebSocketType } from "./AbstractPlatform";
19
+ import type {
20
+ AbstractPlatform,
21
+ InferPlatformEventContextType,
22
+ InferPlatformRoomContextType,
23
+ InferPlatformWebSocketType,
24
+ } from "./AbstractPlatform";
25
+ import { AbstractMessageEvent } from "./AbstractWebSocket";
22
26
  import { authorize } from "./authorize";
23
27
  import type {
24
28
  EventResolver,
@@ -28,7 +32,6 @@ import type {
28
32
  SendMessageOptions,
29
33
  WebSocketSession,
30
34
  } from "./types";
31
- import { AbstractMessageEvent } from "./AbstractWebSocket";
32
35
 
33
36
  const PING_TIMEOUT_MS = 30_000;
34
37
 
@@ -41,8 +44,13 @@ interface BroadcastParams<TIO extends IORoom<any, any, any, any, any>> {
41
44
  senderId?: string;
42
45
  }
43
46
 
44
- interface IORoomListeners {
45
- onDestroy: (encodedState: string) => void;
47
+ export type IORoomListenerEvent<TPlatform extends AbstractPlatform> = {
48
+ room: string;
49
+ encodedState: string;
50
+ } & InferPlatformRoomContextType<TPlatform>;
51
+
52
+ interface IORoomListeners<TPlatform extends AbstractPlatform> {
53
+ onDestroy: (event: IORoomListenerEvent<TPlatform>) => void;
46
54
  }
47
55
 
48
56
  export type IORoomConfig<
@@ -53,11 +61,12 @@ export type IORoomConfig<
53
61
  TOutputBroadcast extends EventRecord<string, any> = {},
54
62
  TOutputSelf extends EventRecord<string, any> = {},
55
63
  TOutputSync extends EventRecord<string, any> = {}
56
- > = Partial<IORoomListeners> & {
64
+ > = Partial<IORoomListeners<TPlatform>> & {
57
65
  authorize?: TAuthorize;
58
- context: TContext;
66
+ context: TContext & InferPlatformRoomContextType<TPlatform>;
59
67
  debug: boolean;
60
68
  events: InferEventConfig<
69
+ TPlatform,
61
70
  TContext,
62
71
  TInput,
63
72
  TOutputBroadcast,
@@ -72,14 +81,15 @@ interface SendMessageSender {
72
81
  user: JsonObject | null;
73
82
  }
74
83
 
75
- export interface WebsocketRegisterOptions {
84
+ export type WebsocketRegisterOptions<TPlatform extends AbstractPlatform> = {
76
85
  token?: string | null;
77
- }
86
+ } & InferPlatformRoomContextType<TPlatform> &
87
+ InferPlatformEventContextType<TPlatform>;
78
88
 
79
89
  export class IORoom<
80
90
  TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>,
81
91
  TAuthorize extends IOAuthorize<any, any> = BaseIOAuthorize,
82
- TContext extends JsonObject = {},
92
+ TContext extends Record<string, any> = {},
83
93
  TInput extends EventRecord<string, any> = {},
84
94
  TOutputBroadcast extends EventRecord<string, any> = {},
85
95
  TOutputSelf extends EventRecord<string, any> = {},
@@ -87,17 +97,19 @@ export class IORoom<
87
97
  > implements
88
98
  IOLike<TAuthorize, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>
89
99
  {
90
- private readonly _context: TContext;
100
+ private readonly _context: TContext &
101
+ InferPlatformRoomContextType<TPlatform>;
91
102
  private readonly _debug: boolean;
92
103
  private readonly _platform: TPlatform;
93
104
 
94
105
  private _doc: YjsDoc<any> = doc();
95
- private _listeners: IORoomListeners;
106
+ private _listeners: IORoomListeners<TPlatform>;
96
107
  private _sessions = new Map<string, WebSocketSession>();
97
108
  private _uninitialize: (() => Promise<void>) | null = null;
98
109
 
99
110
  readonly _authorize: TAuthorize | null = null;
100
111
  readonly _events: InferEventConfig<
112
+ TPlatform,
101
113
  TContext,
102
114
  TInput,
103
115
  TOutputBroadcast,
@@ -130,9 +142,7 @@ export class IORoom<
130
142
  this.id = id;
131
143
 
132
144
  this._listeners = {
133
- onDestroy: (encodedState) => {
134
- onDestroy?.(encodedState);
135
- },
145
+ onDestroy: (event) => onDestroy?.(event),
136
146
  };
137
147
 
138
148
  if (authorize) this._authorize = authorize;
@@ -166,12 +176,16 @@ export class IORoom<
166
176
  }
167
177
 
168
178
  public async register(
169
- webSocket: InferWebSocketType<TPlatform>,
170
- options?: WebsocketRegisterOptions
179
+ webSocket: InferPlatformWebSocketType<TPlatform>,
180
+ options: WebsocketRegisterOptions<TPlatform>
171
181
  ): Promise<void> {
182
+ const { token, ..._platformEventContext } = options;
183
+ const platformEventContext =
184
+ _platformEventContext as InferPlatformRoomContextType<TPlatform> &
185
+ InferPlatformEventContextType<TPlatform>;
186
+
172
187
  if (!this._uninitialize) await this._initialize();
173
188
 
174
- const token = options?.token;
175
189
  const sessionId = this._platform.randomUUID();
176
190
  const pluvWs = this._platform.convertWebSocket(webSocket, {
177
191
  room: this.id,
@@ -230,7 +244,9 @@ export class IORoom<
230
244
  );
231
245
 
232
246
  const onClose = this._onClose(session, uninitializeWs).bind(this);
233
- const onMessage = this._onMessage(session).bind(this);
247
+ const onMessage = this._onMessage(session, platformEventContext).bind(
248
+ this
249
+ );
234
250
 
235
251
  pluvWs.addEventListener("close", onClose);
236
252
  pluvWs.addEventListener("error", onClose);
@@ -340,6 +356,7 @@ export class IORoom<
340
356
  message: EventMessage<string, any>
341
357
  ):
342
358
  | InferEventConfig<
359
+ TPlatform,
343
360
  TContext,
344
361
  TInput,
345
362
  TOutputBroadcast,
@@ -373,6 +390,7 @@ export class IORoom<
373
390
  private _getEventResolverObject(
374
391
  message: EventMessage<string, any>
375
392
  ): EventResolverObject<
393
+ TPlatform,
376
394
  TContext,
377
395
  TInput[string],
378
396
  TOutputBroadcast,
@@ -384,8 +402,15 @@ export class IORoom<
384
402
  if (!eventConfig) return {};
385
403
 
386
404
  const resolver:
387
- | EventResolver<TContext, TInput[string], TOutputBroadcast>
405
+ | EventResolver<
406
+ TContext &
407
+ InferPlatformRoomContextType<TPlatform> &
408
+ InferPlatformEventContextType<TPlatform>,
409
+ TInput[string],
410
+ TOutputBroadcast
411
+ >
388
412
  | EventResolverObject<
413
+ TPlatform,
389
414
  TContext,
390
415
  TInput[string],
391
416
  TOutputBroadcast,
@@ -427,7 +452,11 @@ export class IORoom<
427
452
  this._doc.destroy();
428
453
  this._doc = doc();
429
454
 
430
- this._listeners.onDestroy(encodedState);
455
+ this._listeners.onDestroy({
456
+ ...this._context,
457
+ encodedState,
458
+ room: this.id,
459
+ });
431
460
 
432
461
  this._uninitialize = null;
433
462
  };
@@ -485,10 +514,11 @@ export class IORoom<
485
514
  }
486
515
 
487
516
  private _onMessage(
488
- session: WebSocketSession
517
+ session: WebSocketSession,
518
+ platformEventContext: InferPlatformEventContextType<TPlatform>
489
519
  ): (event: AbstractMessageEvent) => void {
490
520
  return (event: AbstractMessageEvent): void => {
491
- const context: EventResolverContext<TContext> = {
521
+ const baseContext: EventResolverContext<TContext> = {
492
522
  context: this._context,
493
523
  doc: this._doc,
494
524
  room: this.id,
@@ -524,10 +554,19 @@ export class IORoom<
524
554
  return;
525
555
  }
526
556
 
557
+ const extendedContext: EventResolverContext<
558
+ TContext &
559
+ InferPlatformRoomContextType<TPlatform> &
560
+ InferPlatformEventContextType<TPlatform>
561
+ > = {
562
+ ...baseContext,
563
+ context: { ...this._context, ...platformEventContext },
564
+ };
565
+
527
566
  Promise.all([
528
- resolver.broadcast?.(inputs, context),
529
- resolver.self?.(inputs, context),
530
- resolver.sync?.(inputs, context),
567
+ resolver.broadcast?.(inputs, extendedContext),
568
+ resolver.self?.(inputs, extendedContext),
569
+ resolver.sync?.(inputs, baseContext),
531
570
  ]).then(([broadcast, self, sync]) => {
532
571
  if (broadcast) {
533
572
  Object.entries(broadcast).forEach(([type, data]: any) => {
package/src/PluvIO.ts CHANGED
@@ -15,8 +15,11 @@ import type {
15
15
  Spread,
16
16
  } from "@pluv/types";
17
17
  import colors from "kleur";
18
- import type { AbstractPlatform } from "./AbstractPlatform";
19
- import { IORoom } from "./IORoom";
18
+ import type {
19
+ AbstractPlatform,
20
+ InferPlatformRoomContextType,
21
+ } from "./AbstractPlatform";
22
+ import { IORoom, IORoomListenerEvent } from "./IORoom";
20
23
  import type { JWTEncodeParams } from "./authorize";
21
24
  import { authorize } from "./authorize";
22
25
  import type { EventConfig, InferEventConfig } from "./types";
@@ -54,13 +57,9 @@ export type InferIORoom<TIO extends PluvIO<any, any, any, any, any, any, any>> =
54
57
  >
55
58
  : never;
56
59
 
57
- export interface PluvIORegisterOptions {
58
- token?: string;
59
- }
60
-
61
- export interface PluvIOListeners {
62
- onRoomDeleted: (room: string, encodedState: string) => void;
63
- onStorageUpdated: (room: string, encodedState: string) => void;
60
+ export interface PluvIOListeners<TPlatform extends AbstractPlatform> {
61
+ onRoomDeleted: (event: IORoomListenerEvent<TPlatform>) => void;
62
+ onStorageUpdated: (event: IORoomListenerEvent<TPlatform>) => void;
64
63
  }
65
64
 
66
65
  export type PluvIOConfig<
@@ -71,11 +70,12 @@ export type PluvIOConfig<
71
70
  TOutputBroadcast extends EventRecord<string, any> = {},
72
71
  TOutputSelf extends EventRecord<string, any> = {},
73
72
  TOutputSync extends EventRecord<string, any> = {}
74
- > = Partial<PluvIOListeners> & {
73
+ > = Partial<PluvIOListeners<TPlatform>> & {
75
74
  authorize?: TAuthorize;
76
75
  context?: TContext;
77
76
  debug?: boolean;
78
77
  events?: InferEventConfig<
78
+ TPlatform,
79
79
  TContext,
80
80
  TInput,
81
81
  TOutputBroadcast,
@@ -86,9 +86,9 @@ export type PluvIOConfig<
86
86
  platform: TPlatform;
87
87
  };
88
88
 
89
- export interface GetRoomOptions {
89
+ export type GetRoomOptions<TPlatform extends AbstractPlatform> = {
90
90
  debug?: boolean;
91
- }
91
+ } & InferPlatformRoomContextType<TPlatform>;
92
92
 
93
93
  export class PluvIO<
94
94
  TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>,
@@ -121,6 +121,7 @@ export class PluvIO<
121
121
  readonly _authorize: TAuthorize | null = null;
122
122
  readonly _debug: boolean;
123
123
  readonly _events: InferEventConfig<
124
+ TPlatform,
124
125
  TContext,
125
126
  TInput,
126
127
  TOutputBroadcast,
@@ -170,7 +171,7 @@ export class PluvIO<
170
171
  },
171
172
  };
172
173
  },
173
- self: async ({ update }, { doc, room }) => {
174
+ self: async ({ update }, { context, doc, room }) => {
174
175
  const oldState =
175
176
  await this._platform.persistance.getStorageState(room);
176
177
 
@@ -180,16 +181,20 @@ export class PluvIO<
180
181
  ];
181
182
 
182
183
  if (updates.some((_update) => !!_update)) {
183
- const state = updates
184
+ const encodedState = updates
184
185
  .reduce((_doc, _up) => _doc.applyUpdate(_up), doc)
185
186
  .encodeStateAsUpdate();
186
187
 
187
188
  await this._platform.persistance.setStorageState(
188
189
  room,
189
- state
190
+ encodedState
190
191
  );
191
192
 
192
- this._listeners.onStorageUpdated(room, state);
193
+ this._listeners.onStorageUpdated({
194
+ ...context,
195
+ encodedState,
196
+ room,
197
+ });
193
198
  }
194
199
 
195
200
  const state =
@@ -228,7 +233,7 @@ export class PluvIO<
228
233
  },
229
234
  },
230
235
  $UPDATE_STORAGE: {
231
- resolver: ({ origin, update }, { doc, room }) => {
236
+ resolver: ({ origin, update }, { context, doc, room }) => {
232
237
  if (
233
238
  origin === "$STORAGE_RECEIVED" &&
234
239
  Object.keys(doc.toJSON()).length
@@ -237,25 +242,30 @@ export class PluvIO<
237
242
  }
238
243
 
239
244
  const updated = doc.applyUpdate(update);
240
- const state = updated.encodeStateAsUpdate();
245
+ const encodedState = updated.encodeStateAsUpdate();
241
246
 
242
247
  this._platform.persistance
243
- .setStorageState(room, state)
248
+ .setStorageState(room, encodedState)
244
249
  .then(() => {
245
- this._listeners.onStorageUpdated(room, state);
250
+ this._listeners.onStorageUpdated({
251
+ ...context,
252
+ encodedState,
253
+ room,
254
+ });
246
255
  });
247
256
 
248
- return { $STORAGE_UPDATED: { state } };
257
+ return { $STORAGE_UPDATED: { state: encodedState } };
249
258
  },
250
259
  },
251
260
  } as InferEventConfig<
261
+ TPlatform,
252
262
  TContext,
253
263
  TInput,
254
264
  TOutputBroadcast,
255
265
  TOutputSelf,
256
266
  TOutputSync
257
267
  >;
258
- readonly _listeners: PluvIOListeners;
268
+ readonly _listeners: PluvIOListeners<TPlatform>;
259
269
  readonly _platform: TPlatform;
260
270
 
261
271
  constructor(
@@ -289,12 +299,8 @@ export class PluvIO<
289
299
  if (initialStorage) this._initialStorage = initialStorage;
290
300
 
291
301
  this._listeners = {
292
- onRoomDeleted: (room, encodedState) => {
293
- return onRoomDeleted?.(room, encodedState);
294
- },
295
- onStorageUpdated: (room, encodedState) => {
296
- return onStorageUpdated?.(room, encodedState);
297
- },
302
+ onRoomDeleted: (event) => onRoomDeleted?.(event),
303
+ onStorageUpdated: (event) => onStorageUpdated?.(event),
298
304
  };
299
305
  }
300
306
 
@@ -322,6 +328,7 @@ export class PluvIO<
322
328
  >(
323
329
  event: TEvent,
324
330
  config: EventConfig<
331
+ TPlatform,
325
332
  TContext,
326
333
  TData,
327
334
  TResultBroadcast,
@@ -344,6 +351,7 @@ export class PluvIO<
344
351
  const newEvent = {
345
352
  [event]: config,
346
353
  } as InferEventConfig<
354
+ TPlatform,
347
355
  TContext,
348
356
  EventRecord<TEvent, TData>,
349
357
  TResultBroadcast extends EventRecord<string, any>
@@ -377,7 +385,7 @@ export class PluvIO<
377
385
 
378
386
  public getRoom(
379
387
  room: string,
380
- options: GetRoomOptions = {}
388
+ options: GetRoomOptions<TPlatform>
381
389
  ): IORoom<
382
390
  TPlatform,
383
391
  TAuthorize,
@@ -387,7 +395,7 @@ export class PluvIO<
387
395
  TOutputSelf,
388
396
  TOutputSync
389
397
  > {
390
- const { debug } = options;
398
+ const { debug, ...platformRoomContext } = options;
391
399
 
392
400
  this._purgeEmptyRooms();
393
401
 
@@ -400,6 +408,11 @@ export class PluvIO<
400
408
 
401
409
  if (oldRoom) return oldRoom;
402
410
 
411
+ const roomContext = {
412
+ ...this._context,
413
+ ...platformRoomContext,
414
+ } as TContext & InferPlatformRoomContextType<TPlatform>;
415
+
403
416
  const newRoom = new IORoom<
404
417
  TPlatform,
405
418
  TAuthorize,
@@ -410,16 +423,23 @@ export class PluvIO<
410
423
  TOutputSync
411
424
  >(room, {
412
425
  authorize: this._authorize ?? undefined,
413
- context: this._context,
426
+ context: roomContext,
414
427
  debug: debug ?? this._debug,
415
428
  events: this._events,
416
- onDestroy: (encodedState) => {
429
+ onDestroy: ({ encodedState, room }) => {
417
430
  this._logDebug(
418
431
  `${colors.blue("Deleting empty room:")} ${room}`
419
432
  );
420
433
 
434
+ const roomContext = {
435
+ room,
436
+ encodedState,
437
+ ...platformRoomContext,
438
+ } as IORoomListenerEvent<TPlatform> &
439
+ InferPlatformRoomContextType<TPlatform>;
440
+
421
441
  this._rooms.delete(room);
422
- this._listeners.onRoomDeleted(room, encodedState);
442
+ this._listeners.onRoomDeleted(roomContext);
423
443
 
424
444
  if (this._debug) {
425
445
  const rooms = Array.from(this._rooms.keys());
package/src/createIO.ts CHANGED
@@ -16,7 +16,7 @@ export type CreateIOParams<
16
16
  TContext extends JsonObject = {},
17
17
  TAuthorizeUser extends BaseUser = BaseUser,
18
18
  TAuthorizeRequired extends boolean = false
19
- > = Partial<PluvIOListeners> & {
19
+ > = Partial<PluvIOListeners<TPlatform>> & {
20
20
  authorize?: IOAuthorize<TAuthorizeUser, TAuthorizeRequired>;
21
21
  context?: TContext;
22
22
  debug?: boolean;
package/src/index.ts CHANGED
@@ -4,32 +4,34 @@ export type {
4
4
  EventRecord,
5
5
  IOEventMessage,
6
6
  } from "@pluv/types";
7
+ export { AbstractPersistance } from "./AbstractPersistance";
8
+ export { AbstractPlatform } from "./AbstractPlatform";
7
9
  export type {
8
10
  ConvertWebSocketConfig,
9
- InferWebSocketType,
11
+ InferPlatformEventContextType,
12
+ InferPlatformRoomContextType,
13
+ InferPlatformWebSocketType,
10
14
  } from "./AbstractPlatform";
11
- export { AbstractPersistance } from "./AbstractPersistance";
12
- export { AbstractPlatform } from "./AbstractPlatform";
13
- export type { IOPubSubEventMessage } from "./AbstractPubSub";
14
15
  export { AbstractPubSub } from "./AbstractPubSub";
16
+ export type { IOPubSubEventMessage } from "./AbstractPubSub";
17
+ export { AbstractWebSocket } from "./AbstractWebSocket";
15
18
  export type {
16
19
  AbstractCloseEvent,
17
20
  AbstractErrorEvent,
18
21
  AbstractEvent,
19
- AbstractMessageEvent,
20
22
  AbstractEventMap,
21
23
  AbstractListener,
24
+ AbstractMessageEvent,
22
25
  AbstractWebSocketConfig,
23
26
  AbstractWebSocketHandleErrorParams,
24
27
  } from "./AbstractWebSocket";
25
- export { AbstractWebSocket } from "./AbstractWebSocket";
28
+ export type { IORoom } from "./IORoom";
29
+ export type { GetRoomOptions, InferIORoom, PluvIO } from "./PluvIO";
26
30
  export type {
27
31
  AuthorizeModule,
28
32
  AuthorizeParams,
29
33
  JWT,
30
34
  JWTEncodeParams,
31
35
  } from "./authorize";
32
- export type { CreateIOParams } from "./createIO";
33
36
  export { createIO } from "./createIO";
34
- export type { IORoom } from "./IORoom";
35
- export type { GetRoomOptions, InferIORoom, PluvIO } from "./PluvIO";
37
+ export type { CreateIOParams } from "./createIO";
package/src/types.ts CHANGED
@@ -6,6 +6,11 @@ import type {
6
6
  JsonObject,
7
7
  MaybePromise,
8
8
  } from "@pluv/types";
9
+ import {
10
+ AbstractPlatform,
11
+ InferPlatformEventContextType,
12
+ InferPlatformRoomContextType,
13
+ } from "./AbstractPlatform";
9
14
  import type { AbstractWebSocket } from "./AbstractWebSocket";
10
15
 
11
16
  export interface Console {
@@ -23,7 +28,8 @@ declare global {
23
28
  }
24
29
 
25
30
  export interface EventConfig<
26
- TContext extends JsonObject = {},
31
+ TPlatform extends AbstractPlatform = AbstractPlatform,
32
+ TContext extends Record<string, any> = {},
27
33
  TData extends JsonObject = {},
28
34
  TResultBroadcast extends EventRecord<string, any> = {},
29
35
  TResultSelf extends EventRecord<string, any> = {},
@@ -31,8 +37,15 @@ export interface EventConfig<
31
37
  > {
32
38
  input?: InputZodLike<TData>;
33
39
  resolver:
34
- | EventResolver<TContext, TData, TResultBroadcast>
40
+ | EventResolver<
41
+ TContext &
42
+ InferPlatformRoomContextType<TPlatform> &
43
+ InferPlatformEventContextType<TPlatform>,
44
+ TData,
45
+ TResultBroadcast
46
+ >
35
47
  | EventResolverObject<
48
+ TPlatform,
36
49
  TContext,
37
50
  TData,
38
51
  TResultBroadcast,
@@ -43,8 +56,17 @@ export interface EventConfig<
43
56
 
44
57
  export type EventConfigType = "broadcast" | "self" | "sync";
45
58
 
59
+ export type SyncEventResolver<
60
+ TContext extends Record<string, any> = {},
61
+ TData extends JsonObject = {},
62
+ TResultBroadcast extends EventRecord<string, any> = {}
63
+ > = (
64
+ data: TData,
65
+ context: EventResolverContext<TContext>
66
+ ) => MaybePromise<TResultBroadcast | void>;
67
+
46
68
  export type EventResolver<
47
- TContext extends JsonObject = {},
69
+ TContext extends Record<string, any> = {},
48
70
  TData extends JsonObject = {},
49
71
  TResultBroadcast extends EventRecord<string, any> = {}
50
72
  > = (
@@ -52,7 +74,9 @@ export type EventResolver<
52
74
  context: EventResolverContext<TContext>
53
75
  ) => MaybePromise<TResultBroadcast | void>;
54
76
 
55
- export interface EventResolverContext<TContext extends JsonObject = {}> {
77
+ export interface EventResolverContext<
78
+ TContext extends Record<string, any> = {}
79
+ > {
56
80
  context: TContext;
57
81
  doc: YjsDoc<any>;
58
82
  room: string;
@@ -73,19 +97,33 @@ export interface EventResolverContext<TContext extends JsonObject = {}> {
73
97
  }
74
98
 
75
99
  export type EventResolverObject<
76
- TContext extends JsonObject = {},
100
+ TPlatform extends AbstractPlatform = AbstractPlatform,
101
+ TContext extends Record<string, any> = {},
77
102
  TData extends JsonObject = {},
78
103
  TResultBroadcast extends EventRecord<string, any> = {},
79
104
  TResultSelf extends EventRecord<string, any> = {},
80
105
  TResultSync extends EventRecord<string, any> = {}
81
106
  > = {
82
- broadcast?: EventResolver<TContext, TData, TResultBroadcast>;
83
- self?: EventResolver<TContext, TData, TResultSelf>;
84
- sync?: EventResolver<TContext, TData, TResultSync>;
107
+ broadcast?: EventResolver<
108
+ TContext &
109
+ InferPlatformRoomContextType<TPlatform> &
110
+ InferPlatformEventContextType<TPlatform>,
111
+ TData,
112
+ TResultBroadcast
113
+ >;
114
+ self?: EventResolver<
115
+ TContext &
116
+ InferPlatformRoomContextType<TPlatform> &
117
+ InferPlatformEventContextType<TPlatform>,
118
+ TData,
119
+ TResultSelf
120
+ >;
121
+ sync?: SyncEventResolver<TContext, TData, TResultSync>;
85
122
  };
86
123
 
87
124
  export type InferEventConfig<
88
- TContext extends JsonObject = {},
125
+ TPlatform extends AbstractPlatform = AbstractPlatform,
126
+ TContext extends Record<string, any> = {},
89
127
  TInput extends EventRecord<string, any> = {},
90
128
  TOutputBroadcast extends EventRecord<string, any> = {},
91
129
  TOutputSelf extends EventRecord<string, any> = {},
@@ -94,6 +132,7 @@ export type InferEventConfig<
94
132
  [P in keyof TInput]: P extends string
95
133
  ? Id<
96
134
  EventConfig<
135
+ TPlatform,
97
136
  TContext,
98
137
  TInput[P],
99
138
  TOutputBroadcast,