@pluv/io 0.3.9 → 0.4.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.3.9 build /home/runner/work/pluv/pluv/packages/io
2
+ > @pluv/io@0.4.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 29.45 KB
12
- CJS ⚡️ Build success in 105ms
13
- ESM dist/index.mjs 27.39 KB
14
- ESM ⚡️ Build success in 107ms
11
+ ESM dist/index.mjs 28.25 KB
12
+ ESM ⚡️ Build success in 154ms
13
+ CJS dist/index.js 30.31 KB
14
+ CJS ⚡️ Build success in 155ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 2633ms
17
- DTS dist/index.d.ts 12.84 KB
16
+ DTS ⚡️ Build success in 4082ms
17
+ DTS dist/index.d.ts 14.78 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @pluv/io
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - bb2886b: allow sending multiple output types (broadcast, self, sync) per event
8
+ - ae679a8: updated offline presence to be set when reconnecting to a room
9
+
10
+ ### Patch Changes
11
+
12
+ - 41943cf: bumped dependencies
13
+ - 0dd847e: updated storage to be synced when reconnected to the room
14
+ - 3518a83: bumped dependencies
15
+ - Updated dependencies [0dd847e]
16
+ - Updated dependencies [bb2886b]
17
+ - Updated dependencies [ae679a8]
18
+ - Updated dependencies [3518a83]
19
+ - @pluv/crdt-yjs@0.3.7
20
+ - @pluv/types@0.2.0
21
+
3
22
  ## 0.3.9
4
23
 
5
24
  ### 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, Maybe, InferIOAuthorizeUser, InferIOAuthorize, Spread, BaseClientEventRecord, BaseIOEventRecord } from '@pluv/types';
1
+ import { JsonObject, MaybePromise, IOEventMessage, EventRecord, InputZodLike, Id, IOLike, InferIOOutput, BaseUser, IOAuthorize, BaseIOAuthorize, InferIOInput, Maybe, InferIOAuthorizeUser, InferIOAuthorize, Spread, InferIOOutputBroadcast, InferIOOutputSelf, InferIOOutputSync, 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,11 @@ declare global {
79
79
  log: (...data: any[]) => void;
80
80
  };
81
81
  }
82
- interface EventConfig<TContext extends JsonObject = {}, TData extends JsonObject = {}, TResult extends EventRecord<string, any> = {}> {
82
+ interface EventConfig<TContext extends JsonObject = {}, TData extends JsonObject = {}, TResultBroadcast extends EventRecord<string, any> = {}, TResultSelf extends EventRecord<string, any> = {}, TResultSync extends EventRecord<string, any> = {}> {
83
83
  input?: InputZodLike<TData>;
84
- options?: SendMessageOptions;
85
- resolver: EventResolver<TContext, TData, TResult>;
84
+ resolver: EventResolver<TContext, TData, TResultBroadcast> | EventResolverObject<TContext, TData, TResultBroadcast, TResultSelf, TResultSync>;
86
85
  }
87
- type EventResolver<TContext extends JsonObject = {}, TData extends JsonObject = {}, TResult extends EventRecord<string, any> = {}> = (data: TData, context: EventResolverContext<TContext>) => MaybePromise<TResult | void>;
86
+ type EventResolver<TContext extends JsonObject = {}, TData extends JsonObject = {}, TResultBroadcast extends EventRecord<string, any> = {}> = (data: TData, context: EventResolverContext<TContext>) => MaybePromise<TResultBroadcast | void>;
88
87
  interface EventResolverContext<TContext extends JsonObject = {}> {
89
88
  context: TContext;
90
89
  doc: YjsDoc<any>;
@@ -104,8 +103,13 @@ interface EventResolverContext<TContext extends JsonObject = {}> {
104
103
  session: WebSocketSession | null;
105
104
  sessions: Map<string, WebSocketSession>;
106
105
  }
107
- type InferEventConfig<TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutput extends EventRecord<string, any> = {}> = {
108
- [P in keyof TInput]: P extends string ? Id<EventConfig<TContext, TInput[P], TOutput>> : never;
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>;
110
+ };
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;
109
113
  };
110
114
  type SendMessageOptions = {
111
115
  type?: "broadcast";
@@ -179,18 +183,18 @@ interface AuthorizeModule {
179
183
  interface IORoomListeners {
180
184
  onDestroy: (encodedState: string) => void;
181
185
  }
182
- type IORoomConfig<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends IOAuthorize<any, any> = BaseIOAuthorize, TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutput extends EventRecord<string, any> = {}> = Partial<IORoomListeners> & {
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> & {
183
187
  authorize?: TAuthorize;
184
188
  context: TContext;
185
189
  debug: boolean;
186
- events: InferEventConfig<TContext, TInput, TOutput>;
190
+ events: InferEventConfig<TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>;
187
191
  initialStorage?: () => MaybePromise<Maybe<string>>;
188
192
  platform: TPlatform;
189
193
  };
190
194
  interface WebsocketRegisterOptions {
191
195
  token?: string;
192
196
  }
193
- declare class IORoom<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends IOAuthorize<any, any> = BaseIOAuthorize, TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutput extends EventRecord<string, any> = {}> implements IOLike<TAuthorize, TInput, TOutput> {
197
+ 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> {
194
198
  private readonly _context;
195
199
  private readonly _debug;
196
200
  private readonly _platform;
@@ -200,23 +204,24 @@ declare class IORoom<TPlatform extends AbstractPlatform<any> = AbstractPlatform<
200
204
  private _sessions;
201
205
  private _uninitialize;
202
206
  readonly _authorize: TAuthorize | null;
203
- readonly _events: InferEventConfig<TContext, TInput, TOutput>;
207
+ readonly _events: InferEventConfig<TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>;
204
208
  readonly id: string;
205
- constructor(id: string, config: IORoomConfig<TPlatform, TAuthorize, TContext, TInput, TOutput>);
209
+ constructor(id: string, config: IORoomConfig<TPlatform, TAuthorize, TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>);
206
210
  broadcast<TEvent extends keyof InferIOInput<this>>(event: TEvent, data: Id<InferIOInput<this>[TEvent]>): Promise<void>;
207
211
  getSize(): number;
208
212
  register(webSocket: InferWebSocketType<TPlatform>, options?: WebsocketRegisterOptions): Promise<void>;
209
213
  private _broadcast;
210
214
  private _emitQuitters;
211
215
  private _emitRegistered;
212
- private _emitStorageReceived;
213
- private _emitUserJoined;
214
216
  private _getAuthorizedUser;
215
217
  private _getEventConfig;
218
+ private _getEventInputs;
219
+ private _getEventResolverObject;
216
220
  private _initialize;
217
221
  private _logDebug;
222
+ private _onClose;
223
+ private _onMessage;
218
224
  private _parseMessage;
219
- private _resolveMessage;
220
225
  private _sendMessage;
221
226
  private _sendBroadcastMessage;
222
227
  private _sendSelfMessage;
@@ -230,31 +235,31 @@ interface PluvIOListeners {
230
235
  onRoomDeleted: (room: string, encodedState: string) => void;
231
236
  onStorageUpdated: (room: string, encodedState: string) => void;
232
237
  }
233
- type PluvIOConfig<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends IOAuthorize<any, any> | null = null, TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutput extends EventRecord<string, any> = {}> = Partial<PluvIOListeners> & {
238
+ 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> & {
234
239
  authorize?: TAuthorize;
235
240
  context?: TContext;
236
241
  debug?: boolean;
237
- events?: InferEventConfig<TContext, TInput, TOutput>;
242
+ events?: InferEventConfig<TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>;
238
243
  initialStorage?: (room: string) => MaybePromise<Maybe<string>>;
239
244
  platform: TPlatform;
240
245
  };
241
246
  interface GetRoomOptions {
242
247
  debug?: boolean;
243
248
  }
244
- declare class PluvIO<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends IOAuthorize<any, any> = BaseIOAuthorize, TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutput extends EventRecord<string, any> = {}> implements IOLike<TAuthorize, TInput, TOutput> {
249
+ 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> {
245
250
  private _context;
246
251
  private _initialStorage;
247
252
  private _listeners;
248
253
  private _rooms;
249
254
  readonly _authorize: TAuthorize | null;
250
255
  readonly _debug: boolean;
251
- readonly _events: InferEventConfig<TContext, TInput, TOutput>;
256
+ readonly _events: InferEventConfig<TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>;
252
257
  readonly _platform: TPlatform;
253
- constructor(options: PluvIOConfig<TPlatform, TAuthorize, TContext, TInput, TOutput>);
258
+ constructor(options: PluvIOConfig<TPlatform, TAuthorize, TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>);
254
259
  createToken(params: JWTEncodeParams<InferIOAuthorizeUser<InferIOAuthorize<this>>>): Promise<string>;
255
- event<TEvent extends string, TData extends JsonObject = {}, TResult extends EventRecord<string, any> = {}>(event: TEvent, config: EventConfig<TContext, TData, TResult>): PluvIO<TPlatform, TAuthorize, TContext, Spread<[TInput, EventRecord<TEvent, TData>]>, Spread<[TOutput, TResult]>>;
256
- getRoom(room: string, options?: GetRoomOptions): IORoom<TPlatform, TAuthorize, TContext, TInput, TOutput>;
257
- 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<[InferIOOutput<TIO1>, InferIOOutput<TIO2>]>>;
260
+ 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]>>;
261
+ getRoom(room: string, options?: GetRoomOptions): IORoom<TPlatform, TAuthorize, TContext, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>;
262
+ 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>]>>;
258
263
  private _logDebug;
259
264
  private _purgeEmptyRooms;
260
265
  }
@@ -266,6 +271,6 @@ type CreateIOParams<TPlatform extends AbstractPlatform<any> = AbstractPlatform<a
266
271
  initialStorage?: (room: string) => MaybePromise<Maybe<string>>;
267
272
  platform: TPlatform;
268
273
  };
269
- 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>>>;
274
+ 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>>, {}, {}>;
270
275
 
271
276
  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 };
package/dist/index.js CHANGED
@@ -261,6 +261,10 @@ var AbstractWebSocket = class {
261
261
  // src/PluvIO.ts
262
262
  var import_kleur2 = __toESM(require("kleur"));
263
263
 
264
+ // src/IORoom.ts
265
+ var import_crdt_yjs = require("@pluv/crdt-yjs");
266
+ var import_kleur = __toESM(require("kleur"));
267
+
264
268
  // src/authorize.ts
265
269
  var import_hkdf = __toESM(require("@panva/hkdf"));
266
270
  var import_jose = require("jose");
@@ -298,8 +302,6 @@ var authorize = (params) => {
298
302
  };
299
303
 
300
304
  // src/IORoom.ts
301
- var import_crdt_yjs = require("@pluv/crdt-yjs");
302
- var import_kleur = __toESM(require("kleur"));
303
305
  var PING_TIMEOUT_MS = 3e4;
304
306
  var IORoom = class {
305
307
  constructor(id, config) {
@@ -396,101 +398,12 @@ var IORoom = class {
396
398
  sessionId,
397
399
  user != null ? user : {}
398
400
  );
401
+ const onClose = this._onClose(session, uninitializeWs).bind(this);
402
+ const onMessage = this._onMessage(session).bind(this);
403
+ pluvWs.addEventListener("close", onClose);
404
+ pluvWs.addEventListener("error", onClose);
405
+ pluvWs.addEventListener("message", onMessage);
399
406
  this._emitRegistered(session);
400
- this._emitStorageReceived(session);
401
- this._emitUserJoined(session);
402
- const context = {
403
- context: this._context,
404
- doc: this._doc,
405
- room: this.id,
406
- session,
407
- sessions: this._sessions
408
- };
409
- pluvWs.addEventListener("message", (event) => {
410
- if (!this._uninitialize)
411
- return;
412
- if (session.quit) {
413
- session.webSocket.close(1011, "WebSocket broken.");
414
- return;
415
- }
416
- const message = this._parseMessage(event);
417
- if (!message)
418
- return;
419
- const eventConfig = this._getEventConfig(message);
420
- if (!eventConfig)
421
- return;
422
- this._resolveMessage(message, context).then((output) => {
423
- var _a2, _b;
424
- if (!output)
425
- return;
426
- const eventType = (_b = (_a2 = eventConfig.options) == null ? void 0 : _a2.type) != null ? _b : "broadcast";
427
- switch (eventType) {
428
- case "self": {
429
- Object.entries(output).forEach(([type, data]) => {
430
- this._sendSelfMessage({ data, type }, session);
431
- });
432
- return;
433
- }
434
- case "sync": {
435
- this._platform.pubSub.publish(this.id, __spreadValues({
436
- connectionId: session.id,
437
- options: eventConfig.options,
438
- room: this.id,
439
- user: session.user
440
- }, message));
441
- Object.entries(output).forEach(([type, data]) => {
442
- this._sendSelfMessage({ data, type }, session);
443
- });
444
- return;
445
- }
446
- case "broadcast":
447
- default: {
448
- Object.entries(output).forEach(([type, data]) => {
449
- this._broadcast({
450
- message: { data, type },
451
- senderId: session.id
452
- });
453
- });
454
- }
455
- }
456
- });
457
- });
458
- const closeHandler = () => {
459
- if (!this._uninitialize)
460
- return;
461
- session.quit = true;
462
- this._logDebug(
463
- `${import_kleur.default.blue(
464
- `(Unregistering connection for room ${this.id}:`
465
- )} ${sessionId}`
466
- );
467
- this._sessions.delete(session.id);
468
- this._platform.persistance.deleteUser(this.id, session.id).finally(() => {
469
- var _a2;
470
- this._broadcast({
471
- message: {
472
- type: "$EXIT",
473
- data: { sessionId: session.id }
474
- },
475
- senderId: session.id
476
- });
477
- uninitializeWs();
478
- const size2 = this.getSize();
479
- this._logDebug(
480
- `${import_kleur.default.blue(
481
- `Unregistered connection for room ${this.id}:`
482
- )} ${sessionId}`
483
- );
484
- this._logDebug(
485
- `${import_kleur.default.blue(`Room ${this.id} size:`)} ${size2}`
486
- );
487
- if (size2)
488
- return;
489
- (_a2 = this._uninitialize) == null ? void 0 : _a2.call(this);
490
- });
491
- };
492
- pluvWs.addEventListener("close", closeHandler);
493
- pluvWs.addEventListener("error", closeHandler);
494
407
  this._logDebug(
495
408
  `${import_kleur.default.blue(
496
409
  `Registered connection for room ${this.id}:`
@@ -538,34 +451,6 @@ var IORoom = class {
538
451
  session
539
452
  );
540
453
  }
541
- _emitStorageReceived(session) {
542
- this._platform.persistance.getStorageState(this.id).then((_state) => __async(this, null, function* () {
543
- var _a, _b;
544
- const state = (_b = _state != null ? _state : yield (_a = this._initialStorage) == null ? void 0 : _a.call(this)) != null ? _b : this._doc.encodeStateAsUpdate();
545
- this._sendSelfMessage(
546
- {
547
- type: "$STORAGE_RECEIVED",
548
- data: { state }
549
- },
550
- session
551
- );
552
- }));
553
- }
554
- _emitUserJoined(session) {
555
- const user = session.user;
556
- if (!user)
557
- return;
558
- this._broadcast({
559
- message: {
560
- type: "$USER_JOINED",
561
- data: {
562
- connectionId: session.id,
563
- user
564
- }
565
- },
566
- senderId: session.id
567
- });
568
- }
569
454
  _getAuthorizedUser(token) {
570
455
  return __async(this, null, function* () {
571
456
  var _a;
@@ -604,6 +489,19 @@ var IORoom = class {
604
489
  var _a;
605
490
  return (_a = this._events[message.type]) != null ? _a : null;
606
491
  }
492
+ _getEventInputs(message) {
493
+ const eventConfig = this._getEventConfig(message);
494
+ if (!eventConfig)
495
+ return message.data;
496
+ return eventConfig.input ? eventConfig.input.parse(message.data) : message.data;
497
+ }
498
+ _getEventResolverObject(message) {
499
+ const eventConfig = this._getEventConfig(message);
500
+ if (!eventConfig)
501
+ return {};
502
+ const resolver = eventConfig.resolver;
503
+ return typeof resolver === "function" ? { broadcast: resolver } : __spreadValues({}, resolver);
504
+ }
607
505
  _initialize() {
608
506
  return __async(this, null, function* () {
609
507
  this._logDebug(`${import_kleur.default.blue(`Initializing room ${this.id}:`)}`);
@@ -635,6 +533,105 @@ var IORoom = class {
635
533
  _logDebug(...data) {
636
534
  this._debug && console.log(...data);
637
535
  }
536
+ _onClose(session, callback) {
537
+ return () => {
538
+ if (!this._uninitialize)
539
+ return;
540
+ session.quit = true;
541
+ this._logDebug(
542
+ `${import_kleur.default.blue(
543
+ `(Unregistering connection for room ${this.id}:`
544
+ )} ${session.id}`
545
+ );
546
+ this._sessions.delete(session.id);
547
+ this._platform.persistance.deleteUser(this.id, session.id).finally(() => {
548
+ var _a;
549
+ this._broadcast({
550
+ message: {
551
+ type: "$EXIT",
552
+ data: { sessionId: session.id }
553
+ },
554
+ senderId: session.id
555
+ });
556
+ callback == null ? void 0 : callback();
557
+ const size = this.getSize();
558
+ this._logDebug(
559
+ `${import_kleur.default.blue(
560
+ `Unregistered connection for room ${this.id}:`
561
+ )} ${session.id}`
562
+ );
563
+ this._logDebug(
564
+ `${import_kleur.default.blue(`Room ${this.id} size:`)} ${size}`
565
+ );
566
+ if (size)
567
+ return;
568
+ (_a = this._uninitialize) == null ? void 0 : _a.call(this);
569
+ });
570
+ };
571
+ }
572
+ _onMessage(session) {
573
+ return (event) => {
574
+ var _a, _b, _c;
575
+ const context = {
576
+ context: this._context,
577
+ doc: this._doc,
578
+ room: this.id,
579
+ session,
580
+ sessions: this._sessions
581
+ };
582
+ if (!this._uninitialize)
583
+ return;
584
+ if (session.quit) {
585
+ session.webSocket.close(1011, "WebSocket broken.");
586
+ return;
587
+ }
588
+ const message = this._parseMessage(event);
589
+ if (!message)
590
+ return;
591
+ const resolver = this._getEventResolverObject(message);
592
+ let inputs;
593
+ try {
594
+ inputs = this._getEventInputs(message);
595
+ } catch (error) {
596
+ session == null ? void 0 : session.webSocket.handleError({
597
+ error,
598
+ message: "Invalid input",
599
+ session
600
+ });
601
+ return;
602
+ }
603
+ Promise.all([
604
+ (_a = resolver.broadcast) == null ? void 0 : _a.call(resolver, inputs, context),
605
+ (_b = resolver.self) == null ? void 0 : _b.call(resolver, inputs, context),
606
+ (_c = resolver.sync) == null ? void 0 : _c.call(resolver, inputs, context)
607
+ ]).then(([broadcast, self, sync]) => {
608
+ if (broadcast) {
609
+ Object.entries(broadcast).forEach(([type, data]) => {
610
+ this._broadcast({
611
+ message: { data, type },
612
+ senderId: session.id
613
+ });
614
+ });
615
+ }
616
+ if (self) {
617
+ Object.entries(self).forEach(([type, data]) => {
618
+ this._sendSelfMessage({ data, type }, session);
619
+ });
620
+ }
621
+ if (sync) {
622
+ this._platform.pubSub.publish(this.id, __spreadValues({
623
+ connectionId: session.id,
624
+ options: { type: "sync" },
625
+ room: this.id,
626
+ user: session.user
627
+ }, message));
628
+ Object.entries(sync).forEach(([type, data]) => {
629
+ this._sendSelfMessage({ data, type }, session);
630
+ });
631
+ }
632
+ });
633
+ };
634
+ }
638
635
  _parseMessage(message) {
639
636
  const parsed = this._platform.parseData(message.data);
640
637
  try {
@@ -649,29 +646,6 @@ var IORoom = class {
649
646
  return null;
650
647
  }
651
648
  }
652
- _resolveMessage(message, context) {
653
- return __async(this, null, function* () {
654
- const { session } = context;
655
- const eventConfig = this._getEventConfig(message);
656
- if (!eventConfig)
657
- return null;
658
- let input;
659
- try {
660
- input = eventConfig.input ? eventConfig.input.parse(message.data) : message.data;
661
- } catch (error) {
662
- session == null ? void 0 : session.webSocket.handleError({
663
- error,
664
- message: "Invalid input",
665
- session
666
- });
667
- return null;
668
- }
669
- const output = yield eventConfig.resolver(input, context);
670
- if (!output)
671
- return null;
672
- return output;
673
- });
674
- }
675
649
  _sendMessage(message, sender, options = {}) {
676
650
  switch (options.type) {
677
651
  case "self": {
@@ -721,13 +695,23 @@ var IORoom = class {
721
695
  const senderId = sender == null ? void 0 : sender.id;
722
696
  if (!senderId)
723
697
  return;
724
- this._resolveMessage(message, {
698
+ const context = {
725
699
  context: this._context,
726
700
  doc: this._doc,
727
701
  room: this.id,
728
702
  session: null,
729
703
  sessions: this._sessions
730
- }).then((output) => {
704
+ };
705
+ const resolver = this._getEventResolverObject(message).sync;
706
+ if (!resolver)
707
+ return;
708
+ let inputs;
709
+ try {
710
+ inputs = this._getEventInputs(message);
711
+ } catch (e) {
712
+ return;
713
+ }
714
+ Promise.resolve(resolver(inputs, context)).then((output) => {
731
715
  if (!output)
732
716
  return;
733
717
  Object.keys(output).forEach((type) => {
@@ -754,32 +738,70 @@ var PluvIO = class {
754
738
  this._rooms = /* @__PURE__ */ new Map();
755
739
  this._authorize = null;
756
740
  this._events = {
757
- $PING: {
758
- resolver: (data, { session }) => {
759
- if (!session)
760
- return {};
761
- const currentTime = (/* @__PURE__ */ new Date()).getTime();
762
- session.timers.ping = currentTime;
763
- return { $PONG: {} };
764
- },
765
- options: { type: "self" }
766
- },
767
741
  $GET_OTHERS: {
768
- resolver: (data, { room, session, sessions }) => {
769
- const others = Array.from(sessions.entries()).filter(([, wsSession]) => wsSession.id !== (session == null ? void 0 : session.id)).reduce(
770
- (acc, [connectionId, { presence, user }]) => __spreadProps(__spreadValues({}, acc), {
771
- [connectionId]: {
772
- connectionId,
773
- presence,
774
- room,
775
- user
742
+ resolver: {
743
+ sync: (data, { room, session, sessions }) => {
744
+ const others = Array.from(sessions.entries()).filter(([, wsSession]) => wsSession.id !== (session == null ? void 0 : session.id)).reduce(
745
+ (acc, [connectionId, { presence, user }]) => __spreadProps(__spreadValues({}, acc), {
746
+ [connectionId]: {
747
+ connectionId,
748
+ presence,
749
+ room,
750
+ user
751
+ }
752
+ }),
753
+ {}
754
+ );
755
+ return { $OTHERS_RECEIVED: { others } };
756
+ }
757
+ }
758
+ },
759
+ $INITIALIZE_SESSION: {
760
+ resolver: {
761
+ broadcast: ({ presence }, { session }) => {
762
+ if (!session)
763
+ return {};
764
+ session.presence = presence;
765
+ return {
766
+ $USER_JOINED: {
767
+ connectionId: session.id,
768
+ user: session.user,
769
+ presence
776
770
  }
777
- }),
778
- {}
779
- );
780
- return { $OTHERS_RECEIVED: { others } };
781
- },
782
- options: { type: "sync" }
771
+ };
772
+ },
773
+ self: (_0, _1) => __async(this, [_0, _1], function* ({ update }, { doc: doc2, room }) {
774
+ var _a, _b;
775
+ const oldState = yield this._platform.persistance.getStorageState(room);
776
+ const updates = [
777
+ oldState ? null : yield (_a = this._initialStorage) == null ? void 0 : _a.call(this, room),
778
+ update
779
+ ];
780
+ if (updates.some((_update) => !!_update)) {
781
+ const state2 = updates.reduce((_doc, _up) => _doc.applyUpdate(_up), doc2).encodeStateAsUpdate();
782
+ yield this._platform.persistance.setStorageState(
783
+ room,
784
+ state2
785
+ );
786
+ this._listeners.onStorageUpdated(room, state2);
787
+ }
788
+ const state = (_b = yield this._platform.persistance.getStorageState(
789
+ room
790
+ )) != null ? _b : doc2.encodeStateAsUpdate();
791
+ return { $STORAGE_RECEIVED: { state } };
792
+ })
793
+ }
794
+ },
795
+ $PING: {
796
+ resolver: {
797
+ self: (data, { session }) => {
798
+ if (!session)
799
+ return {};
800
+ const currentTime = (/* @__PURE__ */ new Date()).getTime();
801
+ session.timers.ping = currentTime;
802
+ return { $PONG: {} };
803
+ }
804
+ }
783
805
  },
784
806
  $UPDATE_PRESENCE: {
785
807
  resolver: ({ presence }, { session }) => {