@pluv/io 0.23.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
@@ -398,27 +398,29 @@ var IORoom = class {
398
398
  this._uninitialize = null;
399
399
  this._sessions = /* @__PURE__ */ new Map();
400
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
408
  onDestroy: (event) => onDestroy == null ? void 0 : onDestroy(event),
410
409
  onMessage: (event) => onMessage == null ? void 0 : onMessage(event)
411
410
  };
412
411
  if (authorize2) this._authorize = authorize2;
413
412
  const webSockets = this._platform.getWebSockets();
414
- if (!webSockets.length) return;
415
413
  webSockets.forEach((webSocket) => {
416
414
  const deserialized = this._platform.getSerializedState(webSocket);
417
415
  const sessionId = this._platform.getSessionId(webSocket);
418
416
  if (!deserialized) return;
419
417
  if (typeof sessionId !== "string") return;
420
- 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);
421
420
  });
421
+ const { doc, uninitialize } = this._initialize();
422
+ this._doc = doc;
423
+ this._uninitialize = uninitialize;
422
424
  }
423
425
  get _events() {
424
426
  return this._router._events;
@@ -434,6 +436,10 @@ var IORoom = class {
434
436
  }
435
437
  });
436
438
  }
439
+ get _initialized() {
440
+ var _a;
441
+ return Promise.resolve(!!((_a = this._uninitialize) == null ? void 0 : _a.then((result) => !!result)));
442
+ }
437
443
  getSize() {
438
444
  const currentTime = (/* @__PURE__ */ new Date()).getTime();
439
445
  return Array.from(this._sessions.values()).reduce((count, pluvWs) => {
@@ -446,25 +452,37 @@ var IORoom = class {
446
452
  onClose(webSocket) {
447
453
  this._ensureDetached();
448
454
  const wsSession = this._getAbstractWs(webSocket);
449
- if (!wsSession) return () => void 0;
455
+ if (!wsSession) return () => __async(this, null, function* () {
456
+ return void 0;
457
+ });
450
458
  return this._onClose(wsSession);
451
459
  }
452
460
  onError(webSocket) {
453
461
  this._ensureDetached();
454
462
  const wsSession = this._getAbstractWs(webSocket);
455
- if (!wsSession) return () => void 0;
463
+ if (!wsSession) return () => __async(this, null, function* () {
464
+ return void 0;
465
+ });
456
466
  return this._onClose(wsSession);
457
467
  }
458
468
  onMessage(webSocket) {
459
469
  this._ensureDetached();
460
470
  const wsSession = this._getAbstractWs(webSocket);
461
- if (!wsSession) return () => void 0;
471
+ if (!wsSession) return () => __async(this, null, function* () {
472
+ return void 0;
473
+ });
462
474
  return this._onMessage(wsSession);
463
475
  }
464
476
  register(_0) {
465
477
  return __async(this, arguments, function* (webSocket, options = {}) {
466
478
  const { token } = options;
467
- 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
+ }
468
486
  const user = yield this._getAuthorizedUser(token);
469
487
  const ioAuthorize = this._getIOAuthorize();
470
488
  const isUnauthorized = !!(ioAuthorize == null ? void 0 : ioAuthorize.required) && !user;
@@ -472,7 +490,7 @@ var IORoom = class {
472
490
  var _a;
473
491
  return ((_a = session.user) == null ? void 0 : _a.id) === user.id;
474
492
  })));
475
- const pluvWs = yield this._platform.convertWebSocket(webSocket, { room: this.id });
493
+ const pluvWs = this._platform.convertWebSocket(webSocket, { room: this.id });
476
494
  this._logDebug(`${import_kleur.default.blue(`Registering connection for room ${this.id}:`)} ${pluvWs.sessionId}`);
477
495
  yield this._platform.acceptWebSocket(pluvWs);
478
496
  if (isUnauthorized || isTokenInUse) {
@@ -554,13 +572,6 @@ var IORoom = class {
554
572
  const sessions = Array.from(this._sessions.values());
555
573
  return (_b = sessions.find((pluvWs) => pluvWs.webSocket === webSocket)) != null ? _b : null;
556
574
  }
557
- _getSession(webSocket) {
558
- return __async(this, null, function* () {
559
- const pluvWs = this._getAbstractWs(webSocket);
560
- if (!pluvWs) throw new Error("Session could not be found");
561
- return yield pluvWs.getSession();
562
- });
563
- }
564
575
  _getAuthorizedUser(token) {
565
576
  return __async(this, null, function* () {
566
577
  var _a;
@@ -590,6 +601,14 @@ var IORoom = class {
590
601
  }
591
602
  });
592
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
+ }
593
612
  _getIOAuthorize() {
594
613
  if (typeof this._authorize === "function") {
595
614
  return this._authorize(this._context);
@@ -605,6 +624,13 @@ var IORoom = class {
605
624
  if (!procedure) return message.data;
606
625
  return procedure.config.input ? procedure.config.input.parse(message.data) : message.data;
607
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
+ }
608
634
  _getSessions() {
609
635
  return __async(this, null, function* () {
610
636
  const promises = Array.from(this._sessions.values()).map((pluvWs) => __async(this, null, function* () {
@@ -614,10 +640,11 @@ var IORoom = class {
614
640
  });
615
641
  }
616
642
  _initialize() {
617
- return __async(this, null, function* () {
643
+ const promise = (() => __async(this, null, function* () {
618
644
  this._logDebug(`${import_kleur.default.blue(`Initializing room ${this.id}:`)}`);
619
645
  if (!!this._uninitialize) {
620
- yield this._uninitialize();
646
+ const uninitialize2 = (yield this._uninitialize).bind(this);
647
+ yield uninitialize2();
621
648
  this._uninitialize = null;
622
649
  }
623
650
  const pubSubId = yield this._platform.pubSub.subscribe(
@@ -645,11 +672,13 @@ var IORoom = class {
645
672
  }
646
673
  })
647
674
  );
648
- this._uninitialize = () => __async(this, null, function* () {
675
+ const doc = yield this._getInitialDoc();
676
+ const uninitialize = () => __async(this, null, function* () {
649
677
  this._platform.pubSub.unsubscribe(pubSubId);
650
- const encodedState = this._doc.getEncodedState();
651
- this._doc.destroy();
652
- this._doc = this._docFactory.getEmpty();
678
+ const doc2 = yield this._doc;
679
+ const encodedState = doc2.getEncodedState();
680
+ doc2.destroy();
681
+ this._doc = Promise.resolve(this._docFactory.getEmpty());
653
682
  this._listeners.onDestroy({
654
683
  context: this._context,
655
684
  encodedState,
@@ -657,19 +686,22 @@ var IORoom = class {
657
686
  });
658
687
  this._uninitialize = null;
659
688
  });
660
- });
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 };
661
694
  }
662
695
  _logDebug(...data) {
663
696
  this._debug && console.log(...data);
664
697
  }
665
698
  _onClose(webSocket) {
666
- return () => {
667
- if (!this._uninitialize) return;
668
- 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 });
669
702
  this._logDebug(`${import_kleur.default.blue(`Unregistering connection for room ${this.id}:`)} ${webSocket.sessionId}`);
670
703
  this._sessions.delete(webSocket.sessionId);
671
704
  this._platform.persistance.deleteUser(this.id, webSocket.sessionId).finally(() => __async(this, null, function* () {
672
- var _a;
673
705
  yield this._broadcast({
674
706
  message: {
675
707
  type: "$EXIT",
@@ -681,27 +713,31 @@ var IORoom = class {
681
713
  this._logDebug(`${import_kleur.default.blue(`Unregistered connection for room ${this.id}:`)} ${webSocket.sessionId}`);
682
714
  this._logDebug(`${import_kleur.default.blue(`Room ${this.id} size:`)} ${size}`);
683
715
  if (size) return;
684
- (_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
+ }
685
720
  }));
686
- };
721
+ });
687
722
  }
688
723
  _onMessage(webSocket) {
689
724
  return (event) => __async(this, null, function* () {
690
725
  var _a, _b, _c, _d, _e, _f;
726
+ if (!(yield this._initialized)) return;
691
727
  const pluvWs = this._getAbstractWs(webSocket);
692
728
  if (!pluvWs) throw new Error("Could not get session");
693
729
  const [session, sessions] = yield Promise.all([
694
730
  this._getSession(pluvWs),
695
731
  this._getSessions()
696
732
  ]);
733
+ const doc = yield this._doc;
697
734
  const baseContext = {
698
735
  context: this._context,
699
- doc: this._doc,
736
+ doc,
700
737
  room: this.id,
701
738
  session,
702
739
  sessions
703
740
  };
704
- if (!this._uninitialize) return;
705
741
  if (pluvWs.state.quit) {
706
742
  pluvWs.close(1011, "WebSocket broken.");
707
743
  return;
@@ -723,30 +759,35 @@ var IORoom = class {
723
759
  return;
724
760
  }
725
761
  const extendedContext = __spreadProps(__spreadValues({}, baseContext), { context: __spreadValues({}, this._context) });
726
- Promise.all([
762
+ yield Promise.all([
727
763
  (_b = (_a = procedure.config).broadcast) == null ? void 0 : _b.call(_a, inputs, extendedContext),
728
764
  (_d = (_c = procedure.config).self) == null ? void 0 : _d.call(_c, inputs, extendedContext),
729
765
  (_f = (_e = procedure.config).sync) == null ? void 0 : _f.call(_e, inputs, baseContext)
730
766
  ]).then((_0) => __async(this, [_0], function* ([broadcast, self, sync]) {
731
767
  const sessionId = session.id;
732
768
  const user = session.user;
733
- if (broadcast) {
734
- Object.entries(broadcast).forEach(([type, data]) => {
735
- this._broadcast({
736
- message: { data, type },
737
- senderId: sessionId
738
- });
739
- });
740
- }
741
- 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;
742
782
  yield Promise.all(
743
783
  Object.entries(self).map((_02) => __async(this, [_02], function* ([type, data]) {
744
784
  yield this._sendSelfMessage({ data, type }, { sessionId, user });
745
785
  }))
746
786
  );
747
- }
748
- if (sync) {
749
- 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({
750
791
  connectionId: session.id,
751
792
  options: { type: "sync" },
752
793
  room: this.id,
@@ -757,7 +798,8 @@ var IORoom = class {
757
798
  yield this._sendSelfMessage({ data, type }, { sessionId, user });
758
799
  }))
759
800
  );
760
- }
801
+ });
802
+ yield Promise.all([handleBroadcast(), handleSelf(), handleSync()]);
761
803
  }));
762
804
  });
763
805
  }
@@ -775,9 +817,11 @@ var IORoom = class {
775
817
  _sendMessage(pluvWs, message) {
776
818
  return __async(this, null, function* () {
777
819
  const { data, type } = message;
820
+ if (!(yield this._initialized)) return;
821
+ const doc = yield this._doc;
778
822
  this._listeners.onMessage({
779
823
  context: this._context,
780
- encodedState: this._doc.getEncodedState(),
824
+ encodedState: doc.getEncodedState(),
781
825
  message: { data, type },
782
826
  room: this.id,
783
827
  user: message.user
@@ -825,9 +869,10 @@ var IORoom = class {
825
869
  return __async(this, null, function* () {
826
870
  var _a;
827
871
  if (!sender) return;
872
+ const doc = yield this._doc;
828
873
  const context = {
829
874
  context: this._context,
830
- doc: this._doc,
875
+ doc,
831
876
  room: this.id,
832
877
  session: null,
833
878
  sessions: yield this._getSessions()
@@ -860,7 +905,7 @@ var IORoom = class {
860
905
  };
861
906
 
862
907
  // src/version.generated.ts
863
- var version = "0.23.0";
908
+ var version = "0.24.0";
864
909
 
865
910
  // src/PluvServer.ts
866
911
  var PluvServer = class {
@@ -904,9 +949,7 @@ var PluvServer = class {
904
949
  const oldState = yield this._platform.persistance.getStorageState(room);
905
950
  const update = data == null ? void 0 : data.update;
906
951
  const updates = [
907
- oldState ? null : yield (_a = this._getInitialStorage) == null ? void 0 : _a.call(this, __spreadProps(__spreadValues({}, context), {
908
- room
909
- })),
952
+ oldState ? null : yield (_a = this._getInitialStorage) == null ? void 0 : _a.call(this, __spreadProps(__spreadValues({}, context), { room })),
910
953
  update
911
954
  ];
912
955
  if (updates.some((_update) => !!_update)) {
@@ -939,9 +982,7 @@ var PluvServer = class {
939
982
  var _a;
940
983
  const origin = data == null ? void 0 : data.origin;
941
984
  const update = (_a = data == null ? void 0 : data.update) != null ? _a : null;
942
- if (origin === "$INITIALIZED" && Object.keys(doc.toJson()).length) {
943
- return {};
944
- }
985
+ if (origin === "$INITIALIZED" && Object.keys(doc.toJson()).length) return {};
945
986
  const updated = update === null ? doc : doc.applyEncodedState({ update });
946
987
  const encodedState = updated.getEncodedState();
947
988
  this._platform.persistance.setStorageState(room, encodedState).then(() => {
@@ -956,7 +997,6 @@ var PluvServer = class {
956
997
  });
957
998
  this._context = {};
958
999
  this._getInitialStorage = null;
959
- this._rooms = /* @__PURE__ */ new Map();
960
1000
  const {
961
1001
  authorize: authorize2,
962
1002
  context,
@@ -991,29 +1031,12 @@ var PluvServer = class {
991
1031
  get _procedure() {
992
1032
  return new PluvProcedure();
993
1033
  }
994
- createToken(params) {
995
- return __async(this, null, function* () {
996
- if (!this._authorize) {
997
- throw new Error("IO does not specify authorize during initialization.");
998
- }
999
- const ioAuthorize = typeof this._authorize === "function" ? this._authorize(params) : this._authorize;
1000
- const secret = ioAuthorize.secret;
1001
- return yield authorize({
1002
- platform: this._platform,
1003
- secret
1004
- }).encode(params);
1005
- });
1006
- }
1007
- getRoom(room, ...options) {
1034
+ createRoom(room, ...options) {
1008
1035
  var _a, _c;
1009
- const _b = (_a = options[0]) != null ? _a : {}, { debug } = _b, platformRoomContext = __objRest(_b, ["debug"]);
1010
- this._purgeEmptyRooms();
1036
+ const _b = (_a = options[0]) != null ? _a : {}, { debug, onDestroy, onMessage } = _b, platformRoomContext = __objRest(_b, ["debug", "onDestroy", "onMessage"]);
1011
1037
  if (!/^[a-z0-9]+[a-z0-9\-_]+[a-z0-9]+$/i.test(room)) {
1012
1038
  throw new Error("Unsupported room name");
1013
1039
  }
1014
- const platform = this._platform;
1015
- const oldRoom = this._rooms.get(room);
1016
- if (oldRoom) return oldRoom;
1017
1040
  const roomContext = __spreadValues(__spreadValues({}, this._context), platformRoomContext);
1018
1041
  const newRoom = new IORoom(room, {
1019
1042
  authorize: (_c = this._authorize) != null ? _c : void 0,
@@ -1022,39 +1045,37 @@ var PluvServer = class {
1022
1045
  debug: debug != null ? debug : this._debug,
1023
1046
  onDestroy: (event) => __async(this, null, function* () {
1024
1047
  this._logDebug(`${import_kleur2.default.blue("Deleting empty room:")} ${room}`);
1025
- this._rooms.delete(room);
1048
+ yield Promise.resolve(onDestroy == null ? void 0 : onDestroy(event));
1026
1049
  yield Promise.resolve(this._listeners.onRoomDeleted(event));
1027
1050
  yield this._platform.persistance.deleteStorageState(room);
1028
- if (this._debug) {
1029
- const rooms = Array.from(this._rooms.keys());
1030
- this._logDebug(`${import_kleur2.default.blue("Deleted room:")} ${room}`);
1031
- this._logDebug(`${import_kleur2.default.blue("Rooms available:")} ${rooms.join(", ")}`);
1032
- }
1051
+ this._logDebug(`${import_kleur2.default.blue("Deleted room:")} ${room}`);
1033
1052
  }),
1034
1053
  onMessage: (event) => __async(this, null, function* () {
1054
+ yield Promise.resolve(onMessage == null ? void 0 : onMessage(event));
1035
1055
  yield Promise.resolve(this._listeners.onRoomMessage(event));
1036
1056
  }),
1037
- platform,
1057
+ platform: this._platform,
1038
1058
  router: this._router
1039
1059
  });
1040
- this._rooms.set(room, newRoom);
1041
- if (this._debug) {
1042
- const rooms = Array.from(this._rooms.keys());
1043
- this._logDebug(`${import_kleur2.default.blue("Created room:")} ${room}`);
1044
- this._logDebug(`${import_kleur2.default.blue("Rooms available:")} ${rooms.join(", ")}`);
1045
- }
1060
+ this._logDebug(`${import_kleur2.default.blue("Created room:")} ${room}`);
1046
1061
  return newRoom;
1047
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
+ }
1048
1076
  _logDebug(...data) {
1049
1077
  this._debug && console.log(...data);
1050
1078
  }
1051
- _purgeEmptyRooms() {
1052
- const rooms = Array.from(this._rooms.entries());
1053
- rooms.forEach(([id, room]) => {
1054
- if (!!(room == null ? void 0 : room.getSize())) return;
1055
- this._rooms.delete(id);
1056
- });
1057
- }
1058
1079
  };
1059
1080
 
1060
1081
  // src/PluvIO.ts