@pluv/io 0.22.0 → 0.24.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.js CHANGED
@@ -394,30 +394,33 @@ var PING_TIMEOUT_MS = 3e4;
394
394
  // src/IORoom.ts
395
395
  var IORoom = class {
396
396
  constructor(id, config) {
397
- this._sessions = /* @__PURE__ */ new Map();
398
- this._uninitialize = null;
399
397
  this._authorize = null;
400
- const { authorize: authorize2, context, crdt = import_crdt.noop, debug, onDestroy, platform, router } = config;
398
+ this._uninitialize = null;
399
+ this._sessions = /* @__PURE__ */ new Map();
400
+ const { authorize: authorize2, context, crdt = import_crdt.noop, debug, onDestroy, onMessage, platform, router } = config;
401
+ this.id = id;
401
402
  this._context = context;
402
403
  this._debug = debug;
403
404
  this._docFactory = crdt.doc(() => ({}));
404
- this._doc = this._docFactory.getEmpty();
405
405
  this._router = router;
406
406
  this._platform = platform.initialize({ context });
407
- this.id = id;
408
407
  this._listeners = {
409
- onDestroy: (event) => onDestroy == null ? void 0 : onDestroy(event)
408
+ onDestroy: (event) => onDestroy == null ? void 0 : onDestroy(event),
409
+ onMessage: (event) => onMessage == null ? void 0 : onMessage(event)
410
410
  };
411
411
  if (authorize2) this._authorize = authorize2;
412
412
  const webSockets = this._platform.getWebSockets();
413
- if (!webSockets.length) return;
414
413
  webSockets.forEach((webSocket) => {
415
414
  const deserialized = this._platform.getSerializedState(webSocket);
416
415
  const sessionId = this._platform.getSessionId(webSocket);
417
416
  if (!deserialized) return;
418
417
  if (typeof sessionId !== "string") return;
419
- this._sessions.set(sessionId, this._platform.convertWebSocket(webSocket, { room: this.id }));
418
+ const pluvWs = this._platform.convertWebSocket(webSocket, { room: this.id });
419
+ this._sessions.set(sessionId, pluvWs);
420
420
  });
421
+ const { doc, uninitialize } = this._initialize();
422
+ this._doc = doc;
423
+ this._uninitialize = uninitialize;
421
424
  }
422
425
  get _events() {
423
426
  return this._router._events;
@@ -433,6 +436,10 @@ var IORoom = class {
433
436
  }
434
437
  });
435
438
  }
439
+ get _initialized() {
440
+ var _a;
441
+ return Promise.resolve(!!((_a = this._uninitialize) == null ? void 0 : _a.then((result) => !!result)));
442
+ }
436
443
  getSize() {
437
444
  const currentTime = (/* @__PURE__ */ new Date()).getTime();
438
445
  return Array.from(this._sessions.values()).reduce((count, pluvWs) => {
@@ -445,25 +452,37 @@ var IORoom = class {
445
452
  onClose(webSocket) {
446
453
  this._ensureDetached();
447
454
  const wsSession = this._getAbstractWs(webSocket);
448
- if (!wsSession) return () => void 0;
455
+ if (!wsSession) return () => __async(this, null, function* () {
456
+ return void 0;
457
+ });
449
458
  return this._onClose(wsSession);
450
459
  }
451
460
  onError(webSocket) {
452
461
  this._ensureDetached();
453
462
  const wsSession = this._getAbstractWs(webSocket);
454
- if (!wsSession) return () => void 0;
463
+ if (!wsSession) return () => __async(this, null, function* () {
464
+ return void 0;
465
+ });
455
466
  return this._onClose(wsSession);
456
467
  }
457
468
  onMessage(webSocket) {
458
469
  this._ensureDetached();
459
470
  const wsSession = this._getAbstractWs(webSocket);
460
- if (!wsSession) return () => void 0;
471
+ if (!wsSession) return () => __async(this, null, function* () {
472
+ return void 0;
473
+ });
461
474
  return this._onMessage(wsSession);
462
475
  }
463
476
  register(_0) {
464
477
  return __async(this, arguments, function* (webSocket, options = {}) {
465
478
  const { token } = options;
466
- if (!this._uninitialize) yield this._initialize();
479
+ const sessionId = this._platform.getSessionId(webSocket);
480
+ const sessionExists = typeof sessionId === "string" && this._sessions.has(sessionId);
481
+ if (sessionExists) return;
482
+ if (!(yield this._initialized)) {
483
+ this._initialize();
484
+ yield this._initialized;
485
+ }
467
486
  const user = yield this._getAuthorizedUser(token);
468
487
  const ioAuthorize = this._getIOAuthorize();
469
488
  const isUnauthorized = !!(ioAuthorize == null ? void 0 : ioAuthorize.required) && !user;
@@ -471,7 +490,7 @@ var IORoom = class {
471
490
  var _a;
472
491
  return ((_a = session.user) == null ? void 0 : _a.id) === user.id;
473
492
  })));
474
- const pluvWs = yield this._platform.convertWebSocket(webSocket, { room: this.id });
493
+ const pluvWs = this._platform.convertWebSocket(webSocket, { room: this.id });
475
494
  this._logDebug(`${import_kleur.default.blue(`Registering connection for room ${this.id}:`)} ${pluvWs.sessionId}`);
476
495
  yield this._platform.acceptWebSocket(pluvWs);
477
496
  if (isUnauthorized || isTokenInUse) {
@@ -553,13 +572,6 @@ var IORoom = class {
553
572
  const sessions = Array.from(this._sessions.values());
554
573
  return (_b = sessions.find((pluvWs) => pluvWs.webSocket === webSocket)) != null ? _b : null;
555
574
  }
556
- _getSession(webSocket) {
557
- return __async(this, null, function* () {
558
- const pluvWs = this._getAbstractWs(webSocket);
559
- if (!pluvWs) throw new Error("Session could not be found");
560
- return yield pluvWs.getSession();
561
- });
562
- }
563
575
  _getAuthorizedUser(token) {
564
576
  return __async(this, null, function* () {
565
577
  var _a;
@@ -589,6 +601,14 @@ var IORoom = class {
589
601
  }
590
602
  });
591
603
  }
604
+ _getInitialDoc() {
605
+ return __async(this, null, function* () {
606
+ const doc = this._docFactory.getEmpty();
607
+ const encodedState = yield this._platform.persistance.getStorageState(this.id);
608
+ if (typeof encodedState === "string") doc.applyEncodedState({ update: encodedState });
609
+ return doc;
610
+ });
611
+ }
592
612
  _getIOAuthorize() {
593
613
  if (typeof this._authorize === "function") {
594
614
  return this._authorize(this._context);
@@ -604,6 +624,13 @@ var IORoom = class {
604
624
  if (!procedure) return message.data;
605
625
  return procedure.config.input ? procedure.config.input.parse(message.data) : message.data;
606
626
  }
627
+ _getSession(webSocket) {
628
+ return __async(this, null, function* () {
629
+ const pluvWs = this._getAbstractWs(webSocket);
630
+ if (!pluvWs) throw new Error("Session could not be found");
631
+ return yield pluvWs.getSession();
632
+ });
633
+ }
607
634
  _getSessions() {
608
635
  return __async(this, null, function* () {
609
636
  const promises = Array.from(this._sessions.values()).map((pluvWs) => __async(this, null, function* () {
@@ -613,45 +640,68 @@ var IORoom = class {
613
640
  });
614
641
  }
615
642
  _initialize() {
616
- return __async(this, null, function* () {
643
+ const promise = (() => __async(this, null, function* () {
617
644
  this._logDebug(`${import_kleur.default.blue(`Initializing room ${this.id}:`)}`);
618
645
  if (!!this._uninitialize) {
619
- yield this._uninitialize();
646
+ const uninitialize2 = (yield this._uninitialize).bind(this);
647
+ yield uninitialize2();
620
648
  this._uninitialize = null;
621
649
  }
622
650
  const pubSubId = yield this._platform.pubSub.subscribe(
623
651
  this.id,
624
652
  (_a) => __async(this, null, function* () {
625
653
  var _b = _a, { options = {} } = _b, message = __objRest(_b, ["options"]);
626
- const sessionId = message.connectionId;
627
- const user = message.user;
628
- yield this._sendMessage(message, { sessionId, user }, options);
654
+ const sender = {
655
+ sessionId: message.connectionId,
656
+ user: message.user
657
+ };
658
+ switch (options.type) {
659
+ case "self": {
660
+ yield this._sendSelfMessage(message, sender);
661
+ return;
662
+ }
663
+ case "sync": {
664
+ yield this._sendSyncMessage(message, sender);
665
+ return;
666
+ }
667
+ case "broadcast":
668
+ default: {
669
+ const sessionIds = options.sessionIds;
670
+ yield this._sendBroadcastMessage(message, sender, sessionIds);
671
+ }
672
+ }
629
673
  })
630
674
  );
631
- this._uninitialize = () => __async(this, null, function* () {
675
+ const doc = yield this._getInitialDoc();
676
+ const uninitialize = () => __async(this, null, function* () {
632
677
  this._platform.pubSub.unsubscribe(pubSubId);
633
- const encodedState = this._doc.getEncodedState();
634
- this._doc.destroy();
635
- this._doc = this._docFactory.getEmpty();
636
- this._listeners.onDestroy(__spreadProps(__spreadValues({}, this._context), {
678
+ const doc2 = yield this._doc;
679
+ const encodedState = doc2.getEncodedState();
680
+ doc2.destroy();
681
+ this._doc = Promise.resolve(this._docFactory.getEmpty());
682
+ this._listeners.onDestroy({
683
+ context: this._context,
637
684
  encodedState,
638
685
  room: this.id
639
- }));
686
+ });
640
687
  this._uninitialize = null;
641
688
  });
642
- });
689
+ return { doc, uninitialize };
690
+ }))();
691
+ this._doc = promise.then((result) => result.doc);
692
+ this._uninitialize = promise.then((result) => result.uninitialize);
693
+ return { doc: this._doc, uninitialize: this._uninitialize };
643
694
  }
644
695
  _logDebug(...data) {
645
696
  this._debug && console.log(...data);
646
697
  }
647
698
  _onClose(webSocket) {
648
- return () => {
649
- if (!this._uninitialize) return;
650
- webSocket.state.quit = true;
699
+ return () => __async(this, null, function* () {
700
+ if (!(yield this._initialized)) return;
701
+ webSocket.state = __spreadProps(__spreadValues({}, webSocket.state), { quit: true });
651
702
  this._logDebug(`${import_kleur.default.blue(`Unregistering connection for room ${this.id}:`)} ${webSocket.sessionId}`);
652
703
  this._sessions.delete(webSocket.sessionId);
653
704
  this._platform.persistance.deleteUser(this.id, webSocket.sessionId).finally(() => __async(this, null, function* () {
654
- var _a;
655
705
  yield this._broadcast({
656
706
  message: {
657
707
  type: "$EXIT",
@@ -663,27 +713,31 @@ var IORoom = class {
663
713
  this._logDebug(`${import_kleur.default.blue(`Unregistered connection for room ${this.id}:`)} ${webSocket.sessionId}`);
664
714
  this._logDebug(`${import_kleur.default.blue(`Room ${this.id} size:`)} ${size}`);
665
715
  if (size) return;
666
- (_a = this._uninitialize) == null ? void 0 : _a.call(this);
716
+ if (this._uninitialize) {
717
+ const uninitialize = (yield this._uninitialize).bind(this);
718
+ yield uninitialize();
719
+ }
667
720
  }));
668
- };
721
+ });
669
722
  }
670
723
  _onMessage(webSocket) {
671
724
  return (event) => __async(this, null, function* () {
672
725
  var _a, _b, _c, _d, _e, _f;
726
+ if (!(yield this._initialized)) return;
673
727
  const pluvWs = this._getAbstractWs(webSocket);
674
728
  if (!pluvWs) throw new Error("Could not get session");
675
729
  const [session, sessions] = yield Promise.all([
676
730
  this._getSession(pluvWs),
677
731
  this._getSessions()
678
732
  ]);
733
+ const doc = yield this._doc;
679
734
  const baseContext = {
680
735
  context: this._context,
681
- doc: this._doc,
736
+ doc,
682
737
  room: this.id,
683
738
  session,
684
739
  sessions
685
740
  };
686
- if (!this._uninitialize) return;
687
741
  if (pluvWs.state.quit) {
688
742
  pluvWs.close(1011, "WebSocket broken.");
689
743
  return;
@@ -705,30 +759,35 @@ var IORoom = class {
705
759
  return;
706
760
  }
707
761
  const extendedContext = __spreadProps(__spreadValues({}, baseContext), { context: __spreadValues({}, this._context) });
708
- Promise.all([
762
+ yield Promise.all([
709
763
  (_b = (_a = procedure.config).broadcast) == null ? void 0 : _b.call(_a, inputs, extendedContext),
710
764
  (_d = (_c = procedure.config).self) == null ? void 0 : _d.call(_c, inputs, extendedContext),
711
765
  (_f = (_e = procedure.config).sync) == null ? void 0 : _f.call(_e, inputs, baseContext)
712
766
  ]).then((_0) => __async(this, [_0], function* ([broadcast, self, sync]) {
713
767
  const sessionId = session.id;
714
768
  const user = session.user;
715
- if (broadcast) {
716
- Object.entries(broadcast).forEach(([type, data]) => {
717
- this._broadcast({
718
- message: { data, type },
719
- senderId: sessionId
720
- });
721
- });
722
- }
723
- if (self) {
769
+ const handleBroadcast = () => __async(this, null, function* () {
770
+ if (!broadcast) return;
771
+ yield Promise.all(
772
+ Object.entries(broadcast).map((_02) => __async(this, [_02], function* ([type, data]) {
773
+ yield this._broadcast({
774
+ message: { data, type },
775
+ senderId: sessionId
776
+ });
777
+ }))
778
+ );
779
+ });
780
+ const handleSelf = () => __async(this, null, function* () {
781
+ if (!self) return;
724
782
  yield Promise.all(
725
783
  Object.entries(self).map((_02) => __async(this, [_02], function* ([type, data]) {
726
784
  yield this._sendSelfMessage({ data, type }, { sessionId, user });
727
785
  }))
728
786
  );
729
- }
730
- if (sync) {
731
- this._platform.pubSub.publish(this.id, __spreadValues({
787
+ });
788
+ const handleSync = () => __async(this, null, function* () {
789
+ if (!sync) return;
790
+ yield this._platform.pubSub.publish(this.id, __spreadValues({
732
791
  connectionId: session.id,
733
792
  options: { type: "sync" },
734
793
  room: this.id,
@@ -739,7 +798,8 @@ var IORoom = class {
739
798
  yield this._sendSelfMessage({ data, type }, { sessionId, user });
740
799
  }))
741
800
  );
742
- }
801
+ });
802
+ yield Promise.all([handleBroadcast(), handleSelf(), handleSync()]);
743
803
  }));
744
804
  });
745
805
  }
@@ -754,23 +814,19 @@ var IORoom = class {
754
814
  return null;
755
815
  }
756
816
  }
757
- _sendMessage(_0, _1) {
758
- return __async(this, arguments, function* (message, sender, options = {}) {
759
- switch (options.type) {
760
- case "self": {
761
- yield this._sendSelfMessage(message, sender);
762
- return;
763
- }
764
- case "sync": {
765
- yield this._sendSyncMessage(message, sender);
766
- return;
767
- }
768
- case "broadcast":
769
- default: {
770
- const sessionIds = options.sessionIds;
771
- yield this._sendBroadcastMessage(message, sender, sessionIds);
772
- }
773
- }
817
+ _sendMessage(pluvWs, message) {
818
+ return __async(this, null, function* () {
819
+ const { data, type } = message;
820
+ if (!(yield this._initialized)) return;
821
+ const doc = yield this._doc;
822
+ this._listeners.onMessage({
823
+ context: this._context,
824
+ encodedState: doc.getEncodedState(),
825
+ message: { data, type },
826
+ room: this.id,
827
+ user: message.user
828
+ });
829
+ yield Promise.resolve(pluvWs.sendMessage(message));
774
830
  });
775
831
  }
776
832
  _sendBroadcastMessage(message, sender, sessionIds) {
@@ -787,7 +843,7 @@ var IORoom = class {
787
843
  var _a2;
788
844
  const session = yield pluvWs.getSession();
789
845
  const user = (_a2 = session.user) != null ? _a2 : null;
790
- pluvWs.sendMessage({ connectionId, data, room, type, user });
846
+ this._sendMessage(pluvWs, { connectionId, data, room, type, user });
791
847
  }));
792
848
  yield Promise.all(promises);
793
849
  });
@@ -802,7 +858,7 @@ var IORoom = class {
802
858
  if (message.type === "$PONG") yield this._emitQuitters();
803
859
  const session = yield pluvWs.getSession();
804
860
  const user = (_b = session.user) != null ? _b : null;
805
- pluvWs.sendMessage(__spreadValues({
861
+ this._sendMessage(pluvWs, __spreadValues({
806
862
  connectionId: senderId,
807
863
  room: this.id,
808
864
  user
@@ -813,9 +869,10 @@ var IORoom = class {
813
869
  return __async(this, null, function* () {
814
870
  var _a;
815
871
  if (!sender) return;
872
+ const doc = yield this._doc;
816
873
  const context = {
817
874
  context: this._context,
818
- doc: this._doc,
875
+ doc,
819
876
  room: this.id,
820
877
  session: null,
821
878
  sessions: yield this._getSessions()
@@ -848,114 +905,15 @@ var IORoom = class {
848
905
  };
849
906
 
850
907
  // src/version.generated.ts
851
- var version = "0.22.0";
908
+ var version = "0.24.0";
852
909
 
853
910
  // src/PluvServer.ts
854
911
  var PluvServer = class {
855
912
  constructor(options) {
856
- this._rooms = /* @__PURE__ */ new Map();
913
+ this.version = version;
857
914
  this._authorize = null;
858
- this._context = {};
859
- this._version = version;
860
- const {
861
- authorize: authorize2,
862
- context,
863
- crdt = import_crdt2.noop,
864
- debug = false,
865
- onRoomDeleted,
866
- onStorageUpdated,
867
- platform,
868
- router = new PluvRouter({})
869
- } = options;
870
- this._crdt = crdt;
871
- this._debug = debug;
872
- this._platform = platform;
873
- this._router = router != null ? router : null;
874
- if (authorize2) this._authorize = authorize2;
875
- if (context) this._context = context;
876
- this._listeners = {
877
- onRoomDeleted: (event) => onRoomDeleted == null ? void 0 : onRoomDeleted(event),
878
- onStorageUpdated: (event) => onStorageUpdated == null ? void 0 : onStorageUpdated(event)
879
- };
880
- }
881
- get _events() {
882
- return this._router._events;
883
- }
884
- get _registrationMode() {
885
- return this._platform._registrationMode;
886
- }
887
- createToken(params) {
888
- return __async(this, null, function* () {
889
- if (!this._authorize) {
890
- throw new Error("IO does not specify authorize during initialization.");
891
- }
892
- const ioAuthorize = typeof this._authorize === "function" ? this._authorize(params) : this._authorize;
893
- const secret = ioAuthorize.secret;
894
- return yield authorize({
895
- platform: this._platform,
896
- secret
897
- }).encode(params);
898
- });
899
- }
900
- getRoom(room, ...options) {
901
- var _a, _c;
902
- const _b = (_a = options[0]) != null ? _a : {}, { debug } = _b, platformRoomContext = __objRest(_b, ["debug"]);
903
- this._purgeEmptyRooms();
904
- if (!/^[a-z0-9]+[a-z0-9\-_]+[a-z0-9]+$/i.test(room)) {
905
- throw new Error("Unsupported room name");
906
- }
907
- const platform = this._platform;
908
- const oldRoom = this._rooms.get(room);
909
- if (oldRoom) return oldRoom;
910
- const roomContext = __spreadValues(__spreadValues({}, this._context), platformRoomContext);
911
- const newRoom = new IORoom(room, {
912
- authorize: (_c = this._authorize) != null ? _c : void 0,
913
- context: roomContext,
914
- crdt: this._crdt,
915
- debug: debug != null ? debug : this._debug,
916
- onDestroy: (_0) => __async(this, [_0], function* ({ encodedState, room: room2 }) {
917
- this._logDebug(`${import_kleur2.default.blue("Deleting empty room:")} ${room2}`);
918
- const roomContext2 = __spreadValues({
919
- room: room2,
920
- encodedState
921
- }, platformRoomContext);
922
- this._rooms.delete(room2);
923
- yield Promise.resolve(this._listeners.onRoomDeleted(roomContext2));
924
- yield this._platform.persistance.deleteStorageState(room2);
925
- if (this._debug) {
926
- const rooms = Array.from(this._rooms.keys());
927
- this._logDebug(`${import_kleur2.default.blue("Deleted room:")} ${room2}`);
928
- this._logDebug(`${import_kleur2.default.blue("Rooms available:")} ${rooms.join(", ")}`);
929
- }
930
- }),
931
- platform,
932
- router: this._router
933
- });
934
- this._rooms.set(room, newRoom);
935
- if (this._debug) {
936
- const rooms = Array.from(this._rooms.keys());
937
- this._logDebug(`${import_kleur2.default.blue("Created room:")} ${room}`);
938
- this._logDebug(`${import_kleur2.default.blue("Rooms available:")} ${rooms.join(", ")}`);
939
- }
940
- return newRoom;
941
- }
942
- _logDebug(...data) {
943
- this._debug && console.log(...data);
944
- }
945
- _purgeEmptyRooms() {
946
- const rooms = Array.from(this._rooms.entries());
947
- rooms.forEach(([id, room]) => {
948
- if (!!(room == null ? void 0 : room.getSize())) return;
949
- this._rooms.delete(id);
950
- });
951
- }
952
- };
953
-
954
- // src/PluvIO.ts
955
- var PluvIO = class {
956
- constructor(options) {
957
- this._router = new PluvRouter({
958
- $GET_OTHERS: this.procedure.sync((data, { room, session, sessions }) => {
915
+ this._baseRouter = new PluvRouter({
916
+ $GET_OTHERS: this._procedure.sync((data, { room, session, sessions }) => {
959
917
  const currentTime = (/* @__PURE__ */ new Date()).getTime();
960
918
  const others = sessions.filter((wsSession) => {
961
919
  if (wsSession.id === (session == null ? void 0 : session.id)) return false;
@@ -975,7 +933,7 @@ var PluvIO = class {
975
933
  );
976
934
  return { $OTHERS_RECEIVED: { others } };
977
935
  }),
978
- $INITIALIZE_SESSION: this.procedure.broadcast((data, { session }) => {
936
+ $INITIALIZE_SESSION: this._procedure.broadcast((data, { session }) => {
979
937
  const presence = data == null ? void 0 : data.presence;
980
938
  if (!session) return {};
981
939
  session.presence = presence;
@@ -991,20 +949,18 @@ var PluvIO = class {
991
949
  const oldState = yield this._platform.persistance.getStorageState(room);
992
950
  const update = data == null ? void 0 : data.update;
993
951
  const updates = [
994
- oldState ? null : yield (_a = this._getInitialStorage) == null ? void 0 : _a.call(this, __spreadProps(__spreadValues({}, context), {
995
- room
996
- })),
952
+ oldState ? null : yield (_a = this._getInitialStorage) == null ? void 0 : _a.call(this, __spreadProps(__spreadValues({}, context), { room })),
997
953
  update
998
954
  ];
999
955
  if (updates.some((_update) => !!_update)) {
1000
956
  const encodedState = doc.batchApplyEncodedState(updates).getEncodedState();
1001
957
  yield this._platform.persistance.setStorageState(room, encodedState);
1002
- this._listeners.onStorageUpdated(__spreadProps(__spreadValues({}, context), { encodedState, room }));
958
+ this._listeners.onStorageUpdated({ context, encodedState, room });
1003
959
  }
1004
960
  const state = (_b = yield this._platform.persistance.getStorageState(room)) != null ? _b : doc.getEncodedState();
1005
961
  return { $STORAGE_RECEIVED: { state } };
1006
962
  })),
1007
- $PING: this.procedure.self((data, { session }) => {
963
+ $PING: this._procedure.self((data, { session }) => {
1008
964
  if (!session) return {};
1009
965
  const currentTime = (/* @__PURE__ */ new Date()).getTime();
1010
966
  const prevState = session.webSocket.state;
@@ -1015,53 +971,54 @@ var PluvIO = class {
1015
971
  });
1016
972
  return { $PONG: {} };
1017
973
  }),
1018
- $UPDATE_PRESENCE: this.procedure.broadcast((data, { session }) => {
974
+ $UPDATE_PRESENCE: this._procedure.broadcast((data, { session }) => {
1019
975
  const presence = data == null ? void 0 : data.presence;
1020
976
  if (!session) return {};
1021
977
  const updated = Object.assign(/* @__PURE__ */ Object.create(null), session.presence, presence);
1022
978
  session.webSocket.presence = updated;
1023
979
  return { $PRESENCE_UPDATED: { presence: updated } };
1024
980
  }),
1025
- $UPDATE_STORAGE: this.procedure.broadcast((data, { context, doc, room }) => {
981
+ $UPDATE_STORAGE: this._procedure.broadcast((data, { context, doc, room }) => {
1026
982
  var _a;
1027
983
  const origin = data == null ? void 0 : data.origin;
1028
984
  const update = (_a = data == null ? void 0 : data.update) != null ? _a : null;
1029
- if (origin === "$INITIALIZED" && Object.keys(doc.toJson()).length) {
1030
- return {};
1031
- }
985
+ if (origin === "$INITIALIZED" && Object.keys(doc.toJson()).length) return {};
1032
986
  const updated = update === null ? doc : doc.applyEncodedState({ update });
1033
987
  const encodedState = updated.getEncodedState();
1034
988
  this._platform.persistance.setStorageState(room, encodedState).then(() => {
1035
- this._listeners.onStorageUpdated(__spreadProps(__spreadValues({}, context), {
989
+ this._listeners.onStorageUpdated({
990
+ context,
1036
991
  encodedState,
1037
992
  room
1038
- }));
993
+ });
1039
994
  });
1040
995
  return { $STORAGE_UPDATED: { state: encodedState } };
1041
996
  })
1042
997
  });
1043
- this._authorize = null;
1044
998
  this._context = {};
1045
999
  this._getInitialStorage = null;
1046
- this._version = version;
1047
1000
  const {
1048
1001
  authorize: authorize2,
1049
1002
  context,
1050
- crdt = import_crdt3.noop,
1003
+ crdt = import_crdt2.noop,
1051
1004
  debug = false,
1052
1005
  getInitialStorage,
1053
1006
  onRoomDeleted,
1007
+ onRoomMessage,
1054
1008
  onStorageUpdated,
1055
- platform
1009
+ platform,
1010
+ router = new PluvRouter({})
1056
1011
  } = options;
1057
1012
  this._crdt = crdt;
1058
1013
  this._debug = debug;
1059
1014
  this._platform = platform;
1015
+ this._router = router ? this._baseRouter : PluvRouter.merge(this._baseRouter, router);
1060
1016
  if (authorize2) this._authorize = authorize2;
1061
1017
  if (context) this._context = context;
1062
1018
  if (getInitialStorage) this._getInitialStorage = getInitialStorage;
1063
1019
  this._listeners = {
1064
1020
  onRoomDeleted: (event) => onRoomDeleted == null ? void 0 : onRoomDeleted(event),
1021
+ onRoomMessage: (event) => onRoomMessage == null ? void 0 : onRoomMessage(event),
1065
1022
  onStorageUpdated: (event) => onStorageUpdated == null ? void 0 : onStorageUpdated(event)
1066
1023
  };
1067
1024
  }
@@ -1071,6 +1028,69 @@ var PluvIO = class {
1071
1028
  get _registrationMode() {
1072
1029
  return this._platform._registrationMode;
1073
1030
  }
1031
+ get _procedure() {
1032
+ return new PluvProcedure();
1033
+ }
1034
+ createRoom(room, ...options) {
1035
+ var _a, _c;
1036
+ const _b = (_a = options[0]) != null ? _a : {}, { debug, onDestroy, onMessage } = _b, platformRoomContext = __objRest(_b, ["debug", "onDestroy", "onMessage"]);
1037
+ if (!/^[a-z0-9]+[a-z0-9\-_]+[a-z0-9]+$/i.test(room)) {
1038
+ throw new Error("Unsupported room name");
1039
+ }
1040
+ const roomContext = __spreadValues(__spreadValues({}, this._context), platformRoomContext);
1041
+ const newRoom = new IORoom(room, {
1042
+ authorize: (_c = this._authorize) != null ? _c : void 0,
1043
+ context: roomContext,
1044
+ crdt: this._crdt,
1045
+ debug: debug != null ? debug : this._debug,
1046
+ onDestroy: (event) => __async(this, null, function* () {
1047
+ this._logDebug(`${import_kleur2.default.blue("Deleting empty room:")} ${room}`);
1048
+ yield Promise.resolve(onDestroy == null ? void 0 : onDestroy(event));
1049
+ yield Promise.resolve(this._listeners.onRoomDeleted(event));
1050
+ yield this._platform.persistance.deleteStorageState(room);
1051
+ this._logDebug(`${import_kleur2.default.blue("Deleted room:")} ${room}`);
1052
+ }),
1053
+ onMessage: (event) => __async(this, null, function* () {
1054
+ yield Promise.resolve(onMessage == null ? void 0 : onMessage(event));
1055
+ yield Promise.resolve(this._listeners.onRoomMessage(event));
1056
+ }),
1057
+ platform: this._platform,
1058
+ router: this._router
1059
+ });
1060
+ this._logDebug(`${import_kleur2.default.blue("Created room:")} ${room}`);
1061
+ return newRoom;
1062
+ }
1063
+ createToken(params) {
1064
+ return __async(this, null, function* () {
1065
+ if (!this._authorize) {
1066
+ throw new Error("IO does not specify authorize during initialization.");
1067
+ }
1068
+ const ioAuthorize = typeof this._authorize === "function" ? this._authorize(params) : this._authorize;
1069
+ const secret = ioAuthorize.secret;
1070
+ return yield authorize({
1071
+ platform: this._platform,
1072
+ secret
1073
+ }).encode(params);
1074
+ });
1075
+ }
1076
+ _logDebug(...data) {
1077
+ this._debug && console.log(...data);
1078
+ }
1079
+ };
1080
+
1081
+ // src/PluvIO.ts
1082
+ var PluvIO = class {
1083
+ constructor(options) {
1084
+ this.version = version;
1085
+ this._authorize = null;
1086
+ this._context = {};
1087
+ const { authorize: authorize2, context, crdt = import_crdt3.noop, debug = false, platform } = options;
1088
+ this._crdt = crdt;
1089
+ this._debug = debug;
1090
+ this._platform = platform;
1091
+ if (authorize2) this._authorize = authorize2;
1092
+ if (context) this._context = context;
1093
+ }
1074
1094
  get procedure() {
1075
1095
  return new PluvProcedure();
1076
1096
  }
@@ -1093,29 +1113,24 @@ var PluvIO = class {
1093
1113
  }
1094
1114
  server(config = {}) {
1095
1115
  var _a;
1096
- const router = config.router ? this.mergeRouters(this._router, config.router) : this._router;
1097
- return new PluvServer(__spreadProps(__spreadValues({}, this._listeners), {
1116
+ return new PluvServer(__spreadProps(__spreadValues({}, config), {
1098
1117
  authorize: (_a = this._authorize) != null ? _a : void 0,
1099
1118
  context: this._context,
1100
1119
  crdt: this._crdt,
1101
1120
  debug: this._debug,
1102
- platform: this._platform,
1103
- router
1121
+ platform: this._platform
1104
1122
  }));
1105
1123
  }
1106
1124
  };
1107
1125
 
1108
1126
  // src/createIO.ts
1109
1127
  var createIO = (params) => {
1110
- const { authorize: authorize2, context, crdt, debug, getInitialStorage, onRoomDeleted, onStorageUpdated, platform } = params;
1128
+ const { authorize: authorize2, context, crdt, debug, platform } = params;
1111
1129
  return new PluvIO({
1112
1130
  authorize: authorize2,
1113
1131
  context,
1114
1132
  crdt,
1115
1133
  debug,
1116
- getInitialStorage,
1117
- onRoomDeleted,
1118
- onStorageUpdated,
1119
1134
  platform
1120
1135
  });
1121
1136
  };