@pluv/io 0.17.2 → 0.18.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.
package/dist/index.mjs CHANGED
@@ -203,11 +203,7 @@ var AbstractWebSocket = class {
203
203
  }
204
204
  handleError(params) {
205
205
  var _a, _b, _c;
206
- const {
207
- error,
208
- message = error instanceof Error ? error.message : "Unexpected error",
209
- session
210
- } = params;
206
+ const { error, message = error instanceof Error ? error.message : "Unexpected error", session } = params;
211
207
  const stack = error instanceof Error ? (_a = error.stack) != null ? _a : null : null;
212
208
  return this.sendMessage({
213
209
  connectionId: (_b = session == null ? void 0 : session.id) != null ? _b : null,
@@ -223,6 +219,79 @@ var AbstractWebSocket = class {
223
219
  };
224
220
 
225
221
  // src/PluvIO.ts
222
+ import { noop as noop3 } from "@pluv/crdt";
223
+
224
+ // src/PluvProcedure.ts
225
+ var PluvProcedure = class _PluvProcedure {
226
+ constructor(config = {}) {
227
+ this._broadcast = null;
228
+ this._input = null;
229
+ this._self = null;
230
+ this._sync = null;
231
+ const { broadcast, input, self, sync } = config;
232
+ this._broadcast = broadcast != null ? broadcast : null;
233
+ this._input = input != null ? input : null;
234
+ this._self = self != null ? self : null;
235
+ this._sync = sync != null ? sync : null;
236
+ }
237
+ get config() {
238
+ var _a, _b, _c, _d, _e, _f, _g;
239
+ return {
240
+ broadcast: (_b = (_a = this._broadcast) == null ? void 0 : _a.bind(this)) != null ? _b : null,
241
+ input: (_c = this._input) != null ? _c : null,
242
+ resolver: this._resolver,
243
+ self: (_e = (_d = this._self) == null ? void 0 : _d.bind(this)) != null ? _e : null,
244
+ sync: (_g = (_f = this._sync) == null ? void 0 : _f.bind(this)) != null ? _g : null
245
+ };
246
+ }
247
+ broadcast(resolver) {
248
+ const { broadcast } = this.config;
249
+ if (!!broadcast)
250
+ throw new Error("Broadcast was already defined for this procedure");
251
+ return new _PluvProcedure(__spreadProps(__spreadValues({}, this.config), {
252
+ broadcast: resolver
253
+ }));
254
+ }
255
+ input(input) {
256
+ return new _PluvProcedure({ input });
257
+ }
258
+ self(resolver) {
259
+ const { self } = this.config;
260
+ if (!!self)
261
+ throw new Error("Self was already defined for this procedure");
262
+ return new _PluvProcedure(__spreadProps(__spreadValues({}, this.config), {
263
+ self: resolver
264
+ }));
265
+ }
266
+ sync(resolver) {
267
+ const { sync } = this.config;
268
+ if (!!sync)
269
+ throw new Error("Sync was already defined for this procedure");
270
+ return new _PluvProcedure(__spreadProps(__spreadValues({}, this.config), {
271
+ sync: resolver
272
+ }));
273
+ }
274
+ _resolver() {
275
+ return (data, context) => {
276
+ var _a, _b, _c;
277
+ return __spreadValues(__spreadValues(__spreadValues({}, (_a = this._broadcast) == null ? void 0 : _a.call(this, data, context)), (_b = this._self) == null ? void 0 : _b.call(this, data, context)), (_c = this._sync) == null ? void 0 : _c.call(this, data, context));
278
+ };
279
+ }
280
+ };
281
+
282
+ // src/PluvRouter.ts
283
+ var PluvRouter = class _PluvRouter {
284
+ constructor(events) {
285
+ this._events = {};
286
+ this._events = events;
287
+ }
288
+ static merge(...routers) {
289
+ const events = Object.assign(/* @__PURE__ */ Object.create(null), ...routers.map((router) => router._events));
290
+ return new _PluvRouter(events);
291
+ }
292
+ };
293
+
294
+ // src/PluvServer.ts
226
295
  import { noop as noop2 } from "@pluv/crdt";
227
296
  import colors2 from "kleur";
228
297
 
@@ -235,13 +304,7 @@ import hkdf from "@panva/hkdf";
235
304
  import { EncryptJWT, jwtDecrypt } from "jose";
236
305
  var DEFAULT_MAX_AGE_MS = 6e4;
237
306
  var getEncryptionKey = (secret) => __async(void 0, null, function* () {
238
- return yield hkdf(
239
- "sha256",
240
- secret,
241
- "",
242
- "Pluv.io Generated Encryption Key",
243
- 32
244
- );
307
+ return yield hkdf("sha256", secret, "", "Pluv.io Generated Encryption Key", 32);
245
308
  });
246
309
  var now = () => Date.now() / 1e3 | 0;
247
310
  var authorize = (params) => {
@@ -273,20 +336,12 @@ var IORoom = class {
273
336
  this._sessions = /* @__PURE__ */ new Map();
274
337
  this._uninitialize = null;
275
338
  this._authorize = null;
276
- const {
277
- authorize: authorize2,
278
- context,
279
- crdt = noop,
280
- debug,
281
- events,
282
- onDestroy,
283
- platform
284
- } = config;
339
+ const { authorize: authorize2, context, crdt = noop, debug, onDestroy, platform, router } = config;
285
340
  this._context = context;
286
341
  this._debug = debug;
287
342
  this._docFactory = crdt.doc(() => ({}));
288
343
  this._doc = this._docFactory.getEmpty();
289
- this._events = events;
344
+ this._router = router;
290
345
  this._platform = platform;
291
346
  this.id = id;
292
347
  this._listeners = {
@@ -295,9 +350,19 @@ var IORoom = class {
295
350
  if (authorize2)
296
351
  this._authorize = authorize2;
297
352
  }
298
- broadcast(event, data) {
299
- const message = { type: event, data };
300
- return Promise.resolve(this._broadcast({ message }));
353
+ get _events() {
354
+ return this._router._events;
355
+ }
356
+ get broadcast() {
357
+ const _broadcast = (event, data) => {
358
+ const message = { type: event, data };
359
+ return Promise.resolve(this._broadcast({ message }));
360
+ };
361
+ return new Proxy(_broadcast, {
362
+ get(fn, prop) {
363
+ return (data) => fn(prop, data);
364
+ }
365
+ });
301
366
  }
302
367
  getSize() {
303
368
  const currentTime = (/* @__PURE__ */ new Date()).getTime();
@@ -321,26 +386,16 @@ var IORoom = class {
321
386
  sessionId,
322
387
  userId: (_b = user == null ? void 0 : user.id) != null ? _b : null
323
388
  });
324
- this._logDebug(
325
- `${colors.blue(
326
- `Registering connection for room ${this.id}:`
327
- )} ${sessionId}`
328
- );
389
+ this._logDebug(`${colors.blue(`Registering connection for room ${this.id}:`)} ${sessionId}`);
329
390
  const uninitializeWs = yield pluvWs.initialize();
330
391
  const ioAuthorize = this._getIOAuthorize(options);
331
392
  const isUnauthorized = !!(ioAuthorize == null ? void 0 : ioAuthorize.required) && !user;
332
- const isTokenInUse = !!user && Array.from(this._sessions.values()).some(
333
- (session2) => {
334
- var _a2;
335
- return ((_a2 = session2.user) == null ? void 0 : _a2.id) === user.id;
336
- }
337
- );
393
+ const isTokenInUse = !!user && Array.from(this._sessions.values()).some((session2) => {
394
+ var _a2;
395
+ return ((_a2 = session2.user) == null ? void 0 : _a2.id) === user.id;
396
+ });
338
397
  if (isUnauthorized || isTokenInUse) {
339
- this._logDebug(
340
- `${colors.blue(
341
- "Authorization failed for connection:"
342
- )} ${sessionId}`
343
- );
398
+ this._logDebug(`${colors.blue("Authorization failed for connection:")} ${sessionId}`);
344
399
  pluvWs.handleError({ error: new Error("Not authorized") });
345
400
  pluvWs.close(3e3, "WebSocket unauthorized.");
346
401
  return;
@@ -358,24 +413,14 @@ var IORoom = class {
358
413
  user
359
414
  };
360
415
  this._sessions.set(session.id, session);
361
- yield this._platform.persistance.addUser(
362
- this.id,
363
- sessionId,
364
- user != null ? user : {}
365
- );
416
+ yield this._platform.persistance.addUser(this.id, sessionId, user != null ? user : {});
366
417
  const onClose = this._onClose(session, uninitializeWs).bind(this);
367
- const onMessage = this._onMessage(session, platformEventContext).bind(
368
- this
369
- );
418
+ const onMessage = this._onMessage(session, platformEventContext).bind(this);
370
419
  pluvWs.addEventListener("close", onClose);
371
420
  pluvWs.addEventListener("error", onClose);
372
421
  pluvWs.addEventListener("message", onMessage);
373
422
  this._emitRegistered(session);
374
- this._logDebug(
375
- `${colors.blue(
376
- `Registered connection for room ${this.id}:`
377
- )} ${sessionId}`
378
- );
423
+ this._logDebug(`${colors.blue(`Registered connection for room ${this.id}:`)} ${sessionId}`);
379
424
  const size = this.getSize();
380
425
  this._logDebug(`${colors.blue(`Room ${this.id} size:`)} ${size}`);
381
426
  });
@@ -442,9 +487,7 @@ var IORoom = class {
442
487
  return null;
443
488
  }
444
489
  if (payload.room !== this.id) {
445
- this._logDebug(
446
- colors.blue(`Token is not authorized for room ${this.id}:`)
447
- );
490
+ this._logDebug(colors.blue(`Token is not authorized for room ${this.id}:`));
448
491
  this._logDebug(colors.blue("Received:"), payload.room);
449
492
  this._logDebug(token);
450
493
  return null;
@@ -452,29 +495,20 @@ var IORoom = class {
452
495
  try {
453
496
  return (_a = ioAuthorize.user.parse(payload.user)) != null ? _a : null;
454
497
  } catch (e) {
455
- this._logDebug(
456
- `${colors.blue("Token fails validation:")} ${token}`
457
- );
498
+ this._logDebug(`${colors.blue("Token fails validation:")} ${token}`);
458
499
  return null;
459
500
  }
460
501
  });
461
502
  }
462
- _getEventConfig(message) {
503
+ _getProcedure(message) {
463
504
  var _a;
464
- return (_a = this._events[message.type]) != null ? _a : null;
505
+ return (_a = this._router._events[message.type]) != null ? _a : null;
465
506
  }
466
- _getEventInputs(message) {
467
- const eventConfig = this._getEventConfig(message);
468
- if (!eventConfig)
507
+ _getProcedureInputs(message) {
508
+ const procedure = this._getProcedure(message);
509
+ if (!procedure)
469
510
  return message.data;
470
- return eventConfig.input ? eventConfig.input.parse(message.data) : message.data;
471
- }
472
- _getEventResolverObject(message) {
473
- const eventConfig = this._getEventConfig(message);
474
- if (!eventConfig)
475
- return {};
476
- const resolver = eventConfig.resolver;
477
- return typeof resolver === "function" ? { broadcast: resolver } : __spreadValues({}, resolver);
511
+ return procedure.config.input ? procedure.config.input.parse(message.data) : message.data;
478
512
  }
479
513
  _initialize() {
480
514
  return __async(this, null, function* () {
@@ -483,17 +517,14 @@ var IORoom = class {
483
517
  yield this._uninitialize();
484
518
  this._uninitialize = null;
485
519
  }
486
- const pubSubId = yield this._platform.pubSub.subscribe(
487
- this.id,
488
- (_a) => {
489
- var _b = _a, { options = {} } = _b, message = __objRest(_b, ["options"]);
490
- const session = {
491
- id: message.connectionId,
492
- user: message.user
493
- };
494
- this._sendMessage(message, session, options);
495
- }
496
- );
520
+ const pubSubId = yield this._platform.pubSub.subscribe(this.id, (_a) => {
521
+ var _b = _a, { options = {} } = _b, message = __objRest(_b, ["options"]);
522
+ const session = {
523
+ id: message.connectionId,
524
+ user: message.user
525
+ };
526
+ this._sendMessage(message, session, options);
527
+ });
497
528
  this._uninitialize = () => __async(this, null, function* () {
498
529
  this._platform.pubSub.unsubscribe(pubSubId);
499
530
  const encodedState = this._doc.getEncodedState();
@@ -515,11 +546,7 @@ var IORoom = class {
515
546
  if (!this._uninitialize)
516
547
  return;
517
548
  session.quit = true;
518
- this._logDebug(
519
- `${colors.blue(
520
- `(Unregistering connection for room ${this.id}:`
521
- )} ${session.id}`
522
- );
549
+ this._logDebug(`${colors.blue(`(Unregistering connection for room ${this.id}:`)} ${session.id}`);
523
550
  this._sessions.delete(session.id);
524
551
  this._platform.persistance.deleteUser(this.id, session.id).finally(() => {
525
552
  var _a;
@@ -532,14 +559,8 @@ var IORoom = class {
532
559
  });
533
560
  callback == null ? void 0 : callback();
534
561
  const size = this.getSize();
535
- this._logDebug(
536
- `${colors.blue(
537
- `Unregistered connection for room ${this.id}:`
538
- )} ${session.id}`
539
- );
540
- this._logDebug(
541
- `${colors.blue(`Room ${this.id} size:`)} ${size}`
542
- );
562
+ this._logDebug(`${colors.blue(`Unregistered connection for room ${this.id}:`)} ${session.id}`);
563
+ this._logDebug(`${colors.blue(`Room ${this.id} size:`)} ${size}`);
543
564
  if (size)
544
565
  return;
545
566
  (_a = this._uninitialize) == null ? void 0 : _a.call(this);
@@ -548,7 +569,7 @@ var IORoom = class {
548
569
  }
549
570
  _onMessage(session, platformEventContext) {
550
571
  return (event) => {
551
- var _a, _b, _c;
572
+ var _a, _b, _c, _d, _e, _f;
552
573
  const baseContext = {
553
574
  context: this._context,
554
575
  doc: this._doc,
@@ -565,10 +586,12 @@ var IORoom = class {
565
586
  const message = this._parseMessage(event);
566
587
  if (!message)
567
588
  return;
568
- const resolver = this._getEventResolverObject(message);
589
+ const procedure = this._getProcedure(message);
590
+ if (!procedure)
591
+ return;
569
592
  let inputs;
570
593
  try {
571
- inputs = this._getEventInputs(message);
594
+ inputs = this._getProcedureInputs(message);
572
595
  } catch (error) {
573
596
  session == null ? void 0 : session.webSocket.handleError({
574
597
  error,
@@ -581,9 +604,9 @@ var IORoom = class {
581
604
  context: __spreadValues(__spreadValues({}, this._context), platformEventContext)
582
605
  });
583
606
  Promise.all([
584
- (_a = resolver.broadcast) == null ? void 0 : _a.call(resolver, inputs, extendedContext),
585
- (_b = resolver.self) == null ? void 0 : _b.call(resolver, inputs, extendedContext),
586
- (_c = resolver.sync) == null ? void 0 : _c.call(resolver, inputs, baseContext)
607
+ (_b = (_a = procedure.config).broadcast) == null ? void 0 : _b.call(_a, inputs, extendedContext),
608
+ (_d = (_c = procedure.config).self) == null ? void 0 : _d.call(_c, inputs, extendedContext),
609
+ (_f = (_e = procedure.config).sync) == null ? void 0 : _f.call(_e, inputs, baseContext)
587
610
  ]).then(([broadcast, self, sync]) => {
588
611
  if (broadcast) {
589
612
  Object.entries(broadcast).forEach(([type, data]) => {
@@ -672,6 +695,7 @@ var IORoom = class {
672
695
  }, message));
673
696
  }
674
697
  _sendSyncMessage(message, sender) {
698
+ var _a;
675
699
  const senderId = sender == null ? void 0 : sender.id;
676
700
  if (!senderId)
677
701
  return;
@@ -682,12 +706,12 @@ var IORoom = class {
682
706
  session: null,
683
707
  sessions: this._sessions
684
708
  };
685
- const resolver = this._getEventResolverObject(message).sync;
709
+ const resolver = (_a = this._getProcedure(message)) == null ? void 0 : _a.config.sync;
686
710
  if (!resolver)
687
711
  return;
688
712
  let inputs;
689
713
  try {
690
- inputs = this._getEventInputs(message);
714
+ inputs = this._getProcedureInputs(message);
691
715
  } catch (e) {
692
716
  return;
693
717
  }
@@ -695,8 +719,8 @@ var IORoom = class {
695
719
  if (!output)
696
720
  return;
697
721
  Object.keys(output).forEach((type) => {
698
- var _a, _b;
699
- const data = (_a = output[type]) != null ? _a : {};
722
+ var _a2, _b;
723
+ const data = (_a2 = output[type]) != null ? _a2 : {};
700
724
  this._platform.pubSub.publish(this.id, {
701
725
  connectionId: senderId,
702
726
  data,
@@ -711,149 +735,45 @@ var IORoom = class {
711
735
  };
712
736
 
713
737
  // src/version.generated.ts
714
- var version = "0.17.2";
738
+ var version = "0.18.0";
715
739
 
716
- // src/PluvIO.ts
717
- var PluvIO = class _PluvIO {
740
+ // src/PluvServer.ts
741
+ var PluvServer = class {
718
742
  constructor(options) {
719
743
  this._rooms = /* @__PURE__ */ new Map();
720
744
  this._authorize = null;
721
745
  this._context = {};
722
- this._events = {
723
- $GET_OTHERS: {
724
- resolver: {
725
- sync: (data, { room, session, sessions }) => {
726
- const others = Array.from(sessions.entries()).filter(([, wsSession]) => wsSession.id !== (session == null ? void 0 : session.id)).reduce(
727
- (acc, [connectionId, { presence, user }]) => __spreadProps(__spreadValues({}, acc), {
728
- [connectionId]: {
729
- connectionId,
730
- presence,
731
- room,
732
- user
733
- }
734
- }),
735
- {}
736
- );
737
- return { $OTHERS_RECEIVED: { others } };
738
- }
739
- }
740
- },
741
- $INITIALIZE_SESSION: {
742
- resolver: {
743
- broadcast: ({ presence }, { session }) => {
744
- if (!session)
745
- return {};
746
- session.presence = presence;
747
- return {
748
- $USER_JOINED: {
749
- connectionId: session.id,
750
- user: session.user,
751
- presence
752
- }
753
- };
754
- },
755
- self: (_0, _1) => __async(this, [_0, _1], function* ({ update }, { context, doc, room }) {
756
- var _a, _b;
757
- const oldState = yield this._platform.persistance.getStorageState(room);
758
- const updates = [
759
- oldState ? null : yield (_a = this._getInitialStorage) == null ? void 0 : _a.call(this, __spreadProps(__spreadValues({}, context), {
760
- room
761
- })),
762
- update
763
- ];
764
- if (updates.some((_update) => !!_update)) {
765
- const encodedState = doc.batchApplyEncodedState(updates).getEncodedState();
766
- yield this._platform.persistance.setStorageState(
767
- room,
768
- encodedState
769
- );
770
- this._listeners.onStorageUpdated(__spreadProps(__spreadValues({}, context), {
771
- encodedState,
772
- room
773
- }));
774
- }
775
- const state = (_b = yield this._platform.persistance.getStorageState(
776
- room
777
- )) != null ? _b : doc.getEncodedState();
778
- return { $STORAGE_RECEIVED: { state } };
779
- })
780
- }
781
- },
782
- $PING: {
783
- resolver: {
784
- self: (data, { session }) => {
785
- if (!session)
786
- return {};
787
- const currentTime = (/* @__PURE__ */ new Date()).getTime();
788
- session.timers.ping = currentTime;
789
- return { $PONG: {} };
790
- }
791
- }
792
- },
793
- $UPDATE_PRESENCE: {
794
- resolver: ({ presence }, { session }) => {
795
- if (!session)
796
- return {};
797
- session.presence = Object.assign(
798
- /* @__PURE__ */ Object.create(null),
799
- session.presence,
800
- presence
801
- );
802
- return { $PRESENCE_UPDATED: { presence } };
803
- }
804
- },
805
- $UPDATE_STORAGE: {
806
- resolver: ({ origin, update }, { context, doc, room }) => {
807
- if (origin === "$INITIALIZED" && Object.keys(doc.toJson()).length) {
808
- return;
809
- }
810
- const updated = doc.applyEncodedState({ update });
811
- const encodedState = updated.getEncodedState();
812
- this._platform.persistance.setStorageState(room, encodedState).then(() => {
813
- this._listeners.onStorageUpdated(__spreadProps(__spreadValues({}, context), {
814
- encodedState,
815
- room
816
- }));
817
- });
818
- return { $STORAGE_UPDATED: { state: encodedState } };
819
- }
820
- }
821
- };
822
- this._getInitialStorage = null;
823
746
  this._version = version;
824
747
  const {
825
748
  authorize: authorize2,
826
749
  context,
827
750
  crdt = noop2,
828
751
  debug = false,
829
- events,
830
- getInitialStorage,
831
752
  onRoomDeleted,
832
753
  onStorageUpdated,
833
- platform
754
+ platform,
755
+ router = new PluvRouter({})
834
756
  } = options;
835
757
  this._crdt = crdt;
836
758
  this._debug = debug;
837
759
  this._platform = platform;
760
+ this._router = router != null ? router : null;
838
761
  if (authorize2)
839
762
  this._authorize = authorize2;
840
763
  if (context)
841
764
  this._context = context;
842
- if (events)
843
- this._events = events;
844
- if (getInitialStorage)
845
- this._getInitialStorage = getInitialStorage;
846
765
  this._listeners = {
847
766
  onRoomDeleted: (event) => onRoomDeleted == null ? void 0 : onRoomDeleted(event),
848
767
  onStorageUpdated: (event) => onStorageUpdated == null ? void 0 : onStorageUpdated(event)
849
768
  };
850
769
  }
770
+ get _events() {
771
+ return this._router._events;
772
+ }
851
773
  createToken(params) {
852
774
  return __async(this, null, function* () {
853
775
  if (!this._authorize) {
854
- throw new Error(
855
- "IO does not specify authorize during initialization."
856
- );
776
+ throw new Error("IO does not specify authorize during initialization.");
857
777
  }
858
778
  const ioAuthorize = typeof this._authorize === "function" ? this._authorize(params) : this._authorize;
859
779
  const secret = ioAuthorize.secret;
@@ -863,22 +783,6 @@ var PluvIO = class _PluvIO {
863
783
  }).encode(params);
864
784
  });
865
785
  }
866
- event(event, config) {
867
- if (event.startsWith("$")) {
868
- throw new Error('Event name must not start with "$".');
869
- }
870
- const newEvent = {
871
- [event]: config
872
- };
873
- return _PluvIO.merge(
874
- this,
875
- new _PluvIO({
876
- crdt: this._crdt,
877
- events: newEvent,
878
- platform: this._platform
879
- })
880
- );
881
- }
882
786
  getRoom(room, options) {
883
787
  var _b;
884
788
  const _a = options, { debug } = _a, platformRoomContext = __objRest(_a, ["debug"]);
@@ -896,11 +800,8 @@ var PluvIO = class _PluvIO {
896
800
  context: roomContext,
897
801
  crdt: this._crdt,
898
802
  debug: debug != null ? debug : this._debug,
899
- events: this._events,
900
803
  onDestroy: ({ encodedState, room: room2 }) => {
901
- this._logDebug(
902
- `${colors2.blue("Deleting empty room:")} ${room2}`
903
- );
804
+ this._logDebug(`${colors2.blue("Deleting empty room:")} ${room2}`);
904
805
  const roomContext2 = __spreadValues({
905
806
  room: room2,
906
807
  encodedState
@@ -910,49 +811,20 @@ var PluvIO = class _PluvIO {
910
811
  if (this._debug) {
911
812
  const rooms = Array.from(this._rooms.keys());
912
813
  this._logDebug(`${colors2.blue("Deleted room:")} ${room2}`);
913
- this._logDebug(
914
- `${colors2.blue("Rooms available:")} ${rooms.join(
915
- ", "
916
- )}`
917
- );
814
+ this._logDebug(`${colors2.blue("Rooms available:")} ${rooms.join(", ")}`);
918
815
  }
919
816
  },
920
- platform
817
+ platform,
818
+ router: this._router
921
819
  });
922
820
  this._rooms.set(room, newRoom);
923
821
  if (this._debug) {
924
822
  const rooms = Array.from(this._rooms.keys());
925
823
  this._logDebug(`${colors2.blue("Created room:")} ${room}`);
926
- this._logDebug(
927
- `${colors2.blue("Rooms available:")} ${rooms.join(", ")}`
928
- );
824
+ this._logDebug(`${colors2.blue("Rooms available:")} ${rooms.join(", ")}`);
929
825
  }
930
826
  return newRoom;
931
827
  }
932
- static merge(first, second) {
933
- var _a;
934
- const authorize2 = (_a = first._authorize) != null ? _a : void 0;
935
- const context = first._context;
936
- const crdt = first._crdt;
937
- const debug = first._debug;
938
- const platform = first._platform;
939
- const getInitialStorage = first._getInitialStorage;
940
- const events1 = first._events;
941
- const events2 = second._events;
942
- const { onRoomDeleted, onStorageUpdated } = first._listeners;
943
- const events = Object.assign(/* @__PURE__ */ Object.create(null), events1, events2);
944
- return new _PluvIO({
945
- authorize: authorize2,
946
- context,
947
- crdt,
948
- debug,
949
- events,
950
- getInitialStorage,
951
- onRoomDeleted,
952
- onStorageUpdated,
953
- platform
954
- });
955
- }
956
828
  _logDebug(...data) {
957
829
  this._debug && console.log(...data);
958
830
  }
@@ -966,18 +838,156 @@ var PluvIO = class _PluvIO {
966
838
  }
967
839
  };
968
840
 
841
+ // src/PluvIO.ts
842
+ var PluvIO = class {
843
+ constructor(options) {
844
+ this._router = new PluvRouter({
845
+ $GET_OTHERS: this.procedure.sync((data, { room, session, sessions }) => {
846
+ const others = Array.from(sessions.entries()).filter(([, wsSession]) => wsSession.id !== (session == null ? void 0 : session.id)).reduce(
847
+ (acc, [connectionId, { presence, user }]) => __spreadProps(__spreadValues({}, acc), {
848
+ [connectionId]: {
849
+ connectionId,
850
+ presence,
851
+ room,
852
+ user
853
+ }
854
+ }),
855
+ {}
856
+ );
857
+ return { $OTHERS_RECEIVED: { others } };
858
+ }),
859
+ $INITIALIZE_SESSION: this.procedure.broadcast((data, { session }) => {
860
+ const presence = data == null ? void 0 : data.presence;
861
+ if (!session)
862
+ return {};
863
+ session.presence = presence;
864
+ return {
865
+ $USER_JOINED: {
866
+ connectionId: session.id,
867
+ user: session.user,
868
+ presence
869
+ }
870
+ };
871
+ }).self((_0, _1) => __async(this, [_0, _1], function* (data, { context, doc, room }) {
872
+ var _a, _b;
873
+ const oldState = yield this._platform.persistance.getStorageState(room);
874
+ const update = data == null ? void 0 : data.update;
875
+ const updates = [
876
+ oldState ? null : yield (_a = this._getInitialStorage) == null ? void 0 : _a.call(this, __spreadProps(__spreadValues({}, context), {
877
+ room
878
+ })),
879
+ update
880
+ ];
881
+ if (updates.some((_update) => !!_update)) {
882
+ const encodedState = doc.batchApplyEncodedState(updates).getEncodedState();
883
+ yield this._platform.persistance.setStorageState(room, encodedState);
884
+ this._listeners.onStorageUpdated(__spreadProps(__spreadValues({}, context), { encodedState, room }));
885
+ }
886
+ const state = (_b = yield this._platform.persistance.getStorageState(room)) != null ? _b : doc.getEncodedState();
887
+ return { $STORAGE_RECEIVED: { state } };
888
+ })),
889
+ $PING: this.procedure.self((data, { session }) => {
890
+ if (!session)
891
+ return {};
892
+ const currentTime = (/* @__PURE__ */ new Date()).getTime();
893
+ session.timers.ping = currentTime;
894
+ return { $PONG: {} };
895
+ }),
896
+ $UPDATE_PRESENCE: this.procedure.broadcast((data, { session }) => {
897
+ const presence = data == null ? void 0 : data.presence;
898
+ if (!session)
899
+ return {};
900
+ session.presence = Object.assign(/* @__PURE__ */ Object.create(null), session.presence, presence);
901
+ return { $PRESENCE_UPDATED: { presence } };
902
+ }),
903
+ $UPDATE_STORAGE: this.procedure.broadcast((data, { context, doc, room }) => {
904
+ var _a;
905
+ const origin = data == null ? void 0 : data.origin;
906
+ const update = (_a = data == null ? void 0 : data.update) != null ? _a : null;
907
+ if (origin === "$INITIALIZED" && Object.keys(doc.toJson()).length) {
908
+ return {};
909
+ }
910
+ const updated = update === null ? doc : doc.applyEncodedState({ update });
911
+ const encodedState = updated.getEncodedState();
912
+ this._platform.persistance.setStorageState(room, encodedState).then(() => {
913
+ this._listeners.onStorageUpdated(__spreadProps(__spreadValues({}, context), {
914
+ encodedState,
915
+ room
916
+ }));
917
+ });
918
+ return { $STORAGE_UPDATED: { state: encodedState } };
919
+ })
920
+ });
921
+ this._authorize = null;
922
+ this._context = {};
923
+ this._getInitialStorage = null;
924
+ this._version = version;
925
+ const {
926
+ authorize: authorize2,
927
+ context,
928
+ crdt = noop3,
929
+ debug = false,
930
+ getInitialStorage,
931
+ onRoomDeleted,
932
+ onStorageUpdated,
933
+ platform
934
+ } = options;
935
+ this._crdt = crdt;
936
+ this._debug = debug;
937
+ this._platform = platform;
938
+ if (authorize2)
939
+ this._authorize = authorize2;
940
+ if (context)
941
+ this._context = context;
942
+ if (getInitialStorage)
943
+ this._getInitialStorage = getInitialStorage;
944
+ this._listeners = {
945
+ onRoomDeleted: (event) => onRoomDeleted == null ? void 0 : onRoomDeleted(event),
946
+ onStorageUpdated: (event) => onStorageUpdated == null ? void 0 : onStorageUpdated(event)
947
+ };
948
+ }
949
+ get _events() {
950
+ return this._router._events;
951
+ }
952
+ get procedure() {
953
+ return new PluvProcedure();
954
+ }
955
+ createToken(params) {
956
+ return __async(this, null, function* () {
957
+ if (!this._authorize) {
958
+ throw new Error("IO does not specify authorize during initialization.");
959
+ }
960
+ const ioAuthorize = typeof this._authorize === "function" ? this._authorize(params) : this._authorize;
961
+ const secret = ioAuthorize.secret;
962
+ return yield authorize({
963
+ platform: this._platform,
964
+ secret
965
+ }).encode(params);
966
+ });
967
+ }
968
+ mergeRouters(...routers) {
969
+ return PluvRouter.merge(...routers);
970
+ }
971
+ router(events) {
972
+ return new PluvRouter(events);
973
+ }
974
+ server(config = {}) {
975
+ var _a;
976
+ const router = config.router ? this.mergeRouters(this._router, config.router) : this._router;
977
+ return new PluvServer(__spreadProps(__spreadValues({}, this._listeners), {
978
+ authorize: (_a = this._authorize) != null ? _a : void 0,
979
+ context: this._context,
980
+ crdt: this._crdt,
981
+ debug: this._debug,
982
+ platform: this._platform,
983
+ router
984
+ }));
985
+ }
986
+ };
987
+
969
988
  // src/createIO.ts
970
989
  var createIO = (params) => {
971
- const {
972
- authorize: authorize2,
973
- context,
974
- crdt,
975
- debug,
976
- getInitialStorage,
977
- onRoomDeleted,
978
- onStorageUpdated,
979
- platform
980
- } = params;
990
+ const { authorize: authorize2, context, crdt, debug, getInitialStorage, onRoomDeleted, onStorageUpdated, platform } = params;
981
991
  return new PluvIO({
982
992
  authorize: authorize2,
983
993
  context,
@@ -995,5 +1005,8 @@ export {
995
1005
  AbstractPubSub,
996
1006
  AbstractWebSocket,
997
1007
  PluvIO,
1008
+ PluvProcedure,
1009
+ PluvRouter,
1010
+ PluvServer,
998
1011
  createIO
999
1012
  };