@pluv/io 0.23.0 → 0.24.1

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
@@ -357,27 +357,29 @@ var IORoom = class {
357
357
  this._uninitialize = null;
358
358
  this._sessions = /* @__PURE__ */ new Map();
359
359
  const { authorize: authorize2, context, crdt = noop, debug, onDestroy, onMessage, platform, router } = config;
360
+ this.id = id;
360
361
  this._context = context;
361
362
  this._debug = debug;
362
363
  this._docFactory = crdt.doc(() => ({}));
363
- this._doc = this._docFactory.getEmpty();
364
364
  this._router = router;
365
365
  this._platform = platform.initialize({ context });
366
- this.id = id;
367
366
  this._listeners = {
368
367
  onDestroy: (event) => onDestroy == null ? void 0 : onDestroy(event),
369
368
  onMessage: (event) => onMessage == null ? void 0 : onMessage(event)
370
369
  };
371
370
  if (authorize2) this._authorize = authorize2;
372
371
  const webSockets = this._platform.getWebSockets();
373
- if (!webSockets.length) return;
374
372
  webSockets.forEach((webSocket) => {
375
373
  const deserialized = this._platform.getSerializedState(webSocket);
376
374
  const sessionId = this._platform.getSessionId(webSocket);
377
375
  if (!deserialized) return;
378
376
  if (typeof sessionId !== "string") return;
379
- this._sessions.set(sessionId, this._platform.convertWebSocket(webSocket, { room: this.id }));
377
+ const pluvWs = this._platform.convertWebSocket(webSocket, { room: this.id });
378
+ this._sessions.set(sessionId, pluvWs);
380
379
  });
380
+ const { doc, uninitialize } = this._initialize();
381
+ this._doc = doc;
382
+ this._uninitialize = uninitialize;
381
383
  }
382
384
  get _events() {
383
385
  return this._router._events;
@@ -393,6 +395,10 @@ var IORoom = class {
393
395
  }
394
396
  });
395
397
  }
398
+ get _initialized() {
399
+ var _a;
400
+ return Promise.resolve(!!((_a = this._uninitialize) == null ? void 0 : _a.then((result) => !!result)));
401
+ }
396
402
  getSize() {
397
403
  const currentTime = (/* @__PURE__ */ new Date()).getTime();
398
404
  return Array.from(this._sessions.values()).reduce((count, pluvWs) => {
@@ -405,25 +411,37 @@ var IORoom = class {
405
411
  onClose(webSocket) {
406
412
  this._ensureDetached();
407
413
  const wsSession = this._getAbstractWs(webSocket);
408
- if (!wsSession) return () => void 0;
414
+ if (!wsSession) return () => __async(this, null, function* () {
415
+ return void 0;
416
+ });
409
417
  return this._onClose(wsSession);
410
418
  }
411
419
  onError(webSocket) {
412
420
  this._ensureDetached();
413
421
  const wsSession = this._getAbstractWs(webSocket);
414
- if (!wsSession) return () => void 0;
422
+ if (!wsSession) return () => __async(this, null, function* () {
423
+ return void 0;
424
+ });
415
425
  return this._onClose(wsSession);
416
426
  }
417
427
  onMessage(webSocket) {
418
428
  this._ensureDetached();
419
429
  const wsSession = this._getAbstractWs(webSocket);
420
- if (!wsSession) return () => void 0;
430
+ if (!wsSession) return () => __async(this, null, function* () {
431
+ return void 0;
432
+ });
421
433
  return this._onMessage(wsSession);
422
434
  }
423
435
  register(_0) {
424
436
  return __async(this, arguments, function* (webSocket, options = {}) {
425
437
  const { token } = options;
426
- if (!this._uninitialize) yield this._initialize();
438
+ const sessionId = this._platform.getSessionId(webSocket);
439
+ const sessionExists = typeof sessionId === "string" && this._sessions.has(sessionId);
440
+ if (sessionExists) return;
441
+ if (!(yield this._initialized)) {
442
+ this._initialize();
443
+ yield this._initialized;
444
+ }
427
445
  const user = yield this._getAuthorizedUser(token);
428
446
  const ioAuthorize = this._getIOAuthorize();
429
447
  const isUnauthorized = !!(ioAuthorize == null ? void 0 : ioAuthorize.required) && !user;
@@ -431,7 +449,7 @@ var IORoom = class {
431
449
  var _a;
432
450
  return ((_a = session.user) == null ? void 0 : _a.id) === user.id;
433
451
  })));
434
- const pluvWs = yield this._platform.convertWebSocket(webSocket, { room: this.id });
452
+ const pluvWs = this._platform.convertWebSocket(webSocket, { room: this.id });
435
453
  this._logDebug(`${colors.blue(`Registering connection for room ${this.id}:`)} ${pluvWs.sessionId}`);
436
454
  yield this._platform.acceptWebSocket(pluvWs);
437
455
  if (isUnauthorized || isTokenInUse) {
@@ -513,13 +531,6 @@ var IORoom = class {
513
531
  const sessions = Array.from(this._sessions.values());
514
532
  return (_b = sessions.find((pluvWs) => pluvWs.webSocket === webSocket)) != null ? _b : null;
515
533
  }
516
- _getSession(webSocket) {
517
- return __async(this, null, function* () {
518
- const pluvWs = this._getAbstractWs(webSocket);
519
- if (!pluvWs) throw new Error("Session could not be found");
520
- return yield pluvWs.getSession();
521
- });
522
- }
523
534
  _getAuthorizedUser(token) {
524
535
  return __async(this, null, function* () {
525
536
  var _a;
@@ -549,6 +560,14 @@ var IORoom = class {
549
560
  }
550
561
  });
551
562
  }
563
+ _getInitialDoc() {
564
+ return __async(this, null, function* () {
565
+ const doc = this._docFactory.getEmpty();
566
+ const encodedState = yield this._platform.persistance.getStorageState(this.id);
567
+ if (typeof encodedState === "string") doc.applyEncodedState({ update: encodedState });
568
+ return doc;
569
+ });
570
+ }
552
571
  _getIOAuthorize() {
553
572
  if (typeof this._authorize === "function") {
554
573
  return this._authorize(this._context);
@@ -564,6 +583,13 @@ var IORoom = class {
564
583
  if (!procedure) return message.data;
565
584
  return procedure.config.input ? procedure.config.input.parse(message.data) : message.data;
566
585
  }
586
+ _getSession(webSocket) {
587
+ return __async(this, null, function* () {
588
+ const pluvWs = this._getAbstractWs(webSocket);
589
+ if (!pluvWs) throw new Error("Session could not be found");
590
+ return yield pluvWs.getSession();
591
+ });
592
+ }
567
593
  _getSessions() {
568
594
  return __async(this, null, function* () {
569
595
  const promises = Array.from(this._sessions.values()).map((pluvWs) => __async(this, null, function* () {
@@ -573,10 +599,11 @@ var IORoom = class {
573
599
  });
574
600
  }
575
601
  _initialize() {
576
- return __async(this, null, function* () {
602
+ const promise = (() => __async(this, null, function* () {
577
603
  this._logDebug(`${colors.blue(`Initializing room ${this.id}:`)}`);
578
604
  if (!!this._uninitialize) {
579
- yield this._uninitialize();
605
+ const uninitialize2 = (yield this._uninitialize).bind(this);
606
+ yield uninitialize2();
580
607
  this._uninitialize = null;
581
608
  }
582
609
  const pubSubId = yield this._platform.pubSub.subscribe(
@@ -604,11 +631,13 @@ var IORoom = class {
604
631
  }
605
632
  })
606
633
  );
607
- this._uninitialize = () => __async(this, null, function* () {
634
+ const doc = yield this._getInitialDoc();
635
+ const uninitialize = () => __async(this, null, function* () {
608
636
  this._platform.pubSub.unsubscribe(pubSubId);
609
- const encodedState = this._doc.getEncodedState();
610
- this._doc.destroy();
611
- this._doc = this._docFactory.getEmpty();
637
+ const doc2 = yield this._doc;
638
+ const encodedState = doc2.getEncodedState();
639
+ doc2.destroy();
640
+ this._doc = Promise.resolve(this._docFactory.getEmpty());
612
641
  this._listeners.onDestroy({
613
642
  context: this._context,
614
643
  encodedState,
@@ -616,19 +645,22 @@ var IORoom = class {
616
645
  });
617
646
  this._uninitialize = null;
618
647
  });
619
- });
648
+ return { doc, uninitialize };
649
+ }))();
650
+ this._doc = promise.then((result) => result.doc);
651
+ this._uninitialize = promise.then((result) => result.uninitialize);
652
+ return { doc: this._doc, uninitialize: this._uninitialize };
620
653
  }
621
654
  _logDebug(...data) {
622
655
  this._debug && console.log(...data);
623
656
  }
624
657
  _onClose(webSocket) {
625
- return () => {
626
- if (!this._uninitialize) return;
627
- webSocket.state.quit = true;
658
+ return () => __async(this, null, function* () {
659
+ if (!(yield this._initialized)) return;
660
+ webSocket.state = __spreadProps(__spreadValues({}, webSocket.state), { quit: true });
628
661
  this._logDebug(`${colors.blue(`Unregistering connection for room ${this.id}:`)} ${webSocket.sessionId}`);
629
662
  this._sessions.delete(webSocket.sessionId);
630
663
  this._platform.persistance.deleteUser(this.id, webSocket.sessionId).finally(() => __async(this, null, function* () {
631
- var _a;
632
664
  yield this._broadcast({
633
665
  message: {
634
666
  type: "$EXIT",
@@ -640,27 +672,31 @@ var IORoom = class {
640
672
  this._logDebug(`${colors.blue(`Unregistered connection for room ${this.id}:`)} ${webSocket.sessionId}`);
641
673
  this._logDebug(`${colors.blue(`Room ${this.id} size:`)} ${size}`);
642
674
  if (size) return;
643
- (_a = this._uninitialize) == null ? void 0 : _a.call(this);
675
+ if (this._uninitialize) {
676
+ const uninitialize = (yield this._uninitialize).bind(this);
677
+ yield uninitialize();
678
+ }
644
679
  }));
645
- };
680
+ });
646
681
  }
647
682
  _onMessage(webSocket) {
648
683
  return (event) => __async(this, null, function* () {
649
684
  var _a, _b, _c, _d, _e, _f;
685
+ if (!(yield this._initialized)) return;
650
686
  const pluvWs = this._getAbstractWs(webSocket);
651
687
  if (!pluvWs) throw new Error("Could not get session");
652
688
  const [session, sessions] = yield Promise.all([
653
689
  this._getSession(pluvWs),
654
690
  this._getSessions()
655
691
  ]);
692
+ const doc = yield this._doc;
656
693
  const baseContext = {
657
694
  context: this._context,
658
- doc: this._doc,
695
+ doc,
659
696
  room: this.id,
660
697
  session,
661
698
  sessions
662
699
  };
663
- if (!this._uninitialize) return;
664
700
  if (pluvWs.state.quit) {
665
701
  pluvWs.close(1011, "WebSocket broken.");
666
702
  return;
@@ -682,30 +718,35 @@ var IORoom = class {
682
718
  return;
683
719
  }
684
720
  const extendedContext = __spreadProps(__spreadValues({}, baseContext), { context: __spreadValues({}, this._context) });
685
- Promise.all([
721
+ yield Promise.all([
686
722
  (_b = (_a = procedure.config).broadcast) == null ? void 0 : _b.call(_a, inputs, extendedContext),
687
723
  (_d = (_c = procedure.config).self) == null ? void 0 : _d.call(_c, inputs, extendedContext),
688
724
  (_f = (_e = procedure.config).sync) == null ? void 0 : _f.call(_e, inputs, baseContext)
689
725
  ]).then((_0) => __async(this, [_0], function* ([broadcast, self, sync]) {
690
726
  const sessionId = session.id;
691
727
  const user = session.user;
692
- if (broadcast) {
693
- Object.entries(broadcast).forEach(([type, data]) => {
694
- this._broadcast({
695
- message: { data, type },
696
- senderId: sessionId
697
- });
698
- });
699
- }
700
- if (self) {
728
+ const handleBroadcast = () => __async(this, null, function* () {
729
+ if (!broadcast) return;
730
+ yield Promise.all(
731
+ Object.entries(broadcast).map((_02) => __async(this, [_02], function* ([type, data]) {
732
+ yield this._broadcast({
733
+ message: { data, type },
734
+ senderId: sessionId
735
+ });
736
+ }))
737
+ );
738
+ });
739
+ const handleSelf = () => __async(this, null, function* () {
740
+ if (!self) return;
701
741
  yield Promise.all(
702
742
  Object.entries(self).map((_02) => __async(this, [_02], function* ([type, data]) {
703
743
  yield this._sendSelfMessage({ data, type }, { sessionId, user });
704
744
  }))
705
745
  );
706
- }
707
- if (sync) {
708
- this._platform.pubSub.publish(this.id, __spreadValues({
746
+ });
747
+ const handleSync = () => __async(this, null, function* () {
748
+ if (!sync) return;
749
+ yield this._platform.pubSub.publish(this.id, __spreadValues({
709
750
  connectionId: session.id,
710
751
  options: { type: "sync" },
711
752
  room: this.id,
@@ -716,7 +757,8 @@ var IORoom = class {
716
757
  yield this._sendSelfMessage({ data, type }, { sessionId, user });
717
758
  }))
718
759
  );
719
- }
760
+ });
761
+ yield Promise.all([handleBroadcast(), handleSelf(), handleSync()]);
720
762
  }));
721
763
  });
722
764
  }
@@ -734,9 +776,11 @@ var IORoom = class {
734
776
  _sendMessage(pluvWs, message) {
735
777
  return __async(this, null, function* () {
736
778
  const { data, type } = message;
779
+ if (!(yield this._initialized)) return;
780
+ const doc = yield this._doc;
737
781
  this._listeners.onMessage({
738
782
  context: this._context,
739
- encodedState: this._doc.getEncodedState(),
783
+ encodedState: doc.getEncodedState(),
740
784
  message: { data, type },
741
785
  room: this.id,
742
786
  user: message.user
@@ -784,9 +828,10 @@ var IORoom = class {
784
828
  return __async(this, null, function* () {
785
829
  var _a;
786
830
  if (!sender) return;
831
+ const doc = yield this._doc;
787
832
  const context = {
788
833
  context: this._context,
789
- doc: this._doc,
834
+ doc,
790
835
  room: this.id,
791
836
  session: null,
792
837
  sessions: yield this._getSessions()
@@ -819,7 +864,7 @@ var IORoom = class {
819
864
  };
820
865
 
821
866
  // src/version.generated.ts
822
- var version = "0.23.0";
867
+ var version = "0.24.1";
823
868
 
824
869
  // src/PluvServer.ts
825
870
  var PluvServer = class {
@@ -863,9 +908,7 @@ var PluvServer = class {
863
908
  const oldState = yield this._platform.persistance.getStorageState(room);
864
909
  const update = data == null ? void 0 : data.update;
865
910
  const updates = [
866
- oldState ? null : yield (_a = this._getInitialStorage) == null ? void 0 : _a.call(this, __spreadProps(__spreadValues({}, context), {
867
- room
868
- })),
911
+ oldState ? null : yield (_a = this._getInitialStorage) == null ? void 0 : _a.call(this, __spreadProps(__spreadValues({}, context), { room })),
869
912
  update
870
913
  ];
871
914
  if (updates.some((_update) => !!_update)) {
@@ -898,9 +941,7 @@ var PluvServer = class {
898
941
  var _a;
899
942
  const origin = data == null ? void 0 : data.origin;
900
943
  const update = (_a = data == null ? void 0 : data.update) != null ? _a : null;
901
- if (origin === "$INITIALIZED" && Object.keys(doc.toJson()).length) {
902
- return {};
903
- }
944
+ if (origin === "$INITIALIZED" && Object.keys(doc.toJson()).length) return {};
904
945
  const updated = update === null ? doc : doc.applyEncodedState({ update });
905
946
  const encodedState = updated.getEncodedState();
906
947
  this._platform.persistance.setStorageState(room, encodedState).then(() => {
@@ -915,7 +956,6 @@ var PluvServer = class {
915
956
  });
916
957
  this._context = {};
917
958
  this._getInitialStorage = null;
918
- this._rooms = /* @__PURE__ */ new Map();
919
959
  const {
920
960
  authorize: authorize2,
921
961
  context,
@@ -950,29 +990,12 @@ var PluvServer = class {
950
990
  get _procedure() {
951
991
  return new PluvProcedure();
952
992
  }
953
- createToken(params) {
954
- return __async(this, null, function* () {
955
- if (!this._authorize) {
956
- throw new Error("IO does not specify authorize during initialization.");
957
- }
958
- const ioAuthorize = typeof this._authorize === "function" ? this._authorize(params) : this._authorize;
959
- const secret = ioAuthorize.secret;
960
- return yield authorize({
961
- platform: this._platform,
962
- secret
963
- }).encode(params);
964
- });
965
- }
966
- getRoom(room, ...options) {
993
+ createRoom(room, ...options) {
967
994
  var _a, _c;
968
- const _b = (_a = options[0]) != null ? _a : {}, { debug } = _b, platformRoomContext = __objRest(_b, ["debug"]);
969
- this._purgeEmptyRooms();
995
+ const _b = (_a = options[0]) != null ? _a : {}, { debug, onDestroy, onMessage } = _b, platformRoomContext = __objRest(_b, ["debug", "onDestroy", "onMessage"]);
970
996
  if (!/^[a-z0-9]+[a-z0-9\-_]+[a-z0-9]+$/i.test(room)) {
971
997
  throw new Error("Unsupported room name");
972
998
  }
973
- const platform = this._platform;
974
- const oldRoom = this._rooms.get(room);
975
- if (oldRoom) return oldRoom;
976
999
  const roomContext = __spreadValues(__spreadValues({}, this._context), platformRoomContext);
977
1000
  const newRoom = new IORoom(room, {
978
1001
  authorize: (_c = this._authorize) != null ? _c : void 0,
@@ -981,39 +1004,37 @@ var PluvServer = class {
981
1004
  debug: debug != null ? debug : this._debug,
982
1005
  onDestroy: (event) => __async(this, null, function* () {
983
1006
  this._logDebug(`${colors2.blue("Deleting empty room:")} ${room}`);
984
- this._rooms.delete(room);
1007
+ yield Promise.resolve(onDestroy == null ? void 0 : onDestroy(event));
985
1008
  yield Promise.resolve(this._listeners.onRoomDeleted(event));
986
1009
  yield this._platform.persistance.deleteStorageState(room);
987
- if (this._debug) {
988
- const rooms = Array.from(this._rooms.keys());
989
- this._logDebug(`${colors2.blue("Deleted room:")} ${room}`);
990
- this._logDebug(`${colors2.blue("Rooms available:")} ${rooms.join(", ")}`);
991
- }
1010
+ this._logDebug(`${colors2.blue("Deleted room:")} ${room}`);
992
1011
  }),
993
1012
  onMessage: (event) => __async(this, null, function* () {
1013
+ yield Promise.resolve(onMessage == null ? void 0 : onMessage(event));
994
1014
  yield Promise.resolve(this._listeners.onRoomMessage(event));
995
1015
  }),
996
- platform,
1016
+ platform: this._platform,
997
1017
  router: this._router
998
1018
  });
999
- this._rooms.set(room, newRoom);
1000
- if (this._debug) {
1001
- const rooms = Array.from(this._rooms.keys());
1002
- this._logDebug(`${colors2.blue("Created room:")} ${room}`);
1003
- this._logDebug(`${colors2.blue("Rooms available:")} ${rooms.join(", ")}`);
1004
- }
1019
+ this._logDebug(`${colors2.blue("Created room:")} ${room}`);
1005
1020
  return newRoom;
1006
1021
  }
1022
+ createToken(params) {
1023
+ return __async(this, null, function* () {
1024
+ if (!this._authorize) {
1025
+ throw new Error("IO does not specify authorize during initialization.");
1026
+ }
1027
+ const ioAuthorize = typeof this._authorize === "function" ? this._authorize(params) : this._authorize;
1028
+ const secret = ioAuthorize.secret;
1029
+ return yield authorize({
1030
+ platform: this._platform,
1031
+ secret
1032
+ }).encode(params);
1033
+ });
1034
+ }
1007
1035
  _logDebug(...data) {
1008
1036
  this._debug && console.log(...data);
1009
1037
  }
1010
- _purgeEmptyRooms() {
1011
- const rooms = Array.from(this._rooms.entries());
1012
- rooms.forEach(([id, room]) => {
1013
- if (!!(room == null ? void 0 : room.getSize())) return;
1014
- this._rooms.delete(id);
1015
- });
1016
- }
1017
1038
  };
1018
1039
 
1019
1040
  // src/PluvIO.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluv/io",
3
- "version": "0.23.0",
3
+ "version": "0.24.1",
4
4
  "description": "@pluv/io server-side websocket manager",
5
5
  "author": "leedavidcs",
6
6
  "license": "MIT",
@@ -18,19 +18,19 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "@panva/hkdf": "^1.2.1",
21
- "jose": "^5.6.3",
21
+ "jose": "^5.7.0",
22
22
  "kleur": "^4.1.5",
23
23
  "wonka": "^6.3.4",
24
- "@pluv/crdt": "^0.23.0",
25
- "@pluv/types": "^0.23.0"
24
+ "@pluv/crdt": "^0.24.1",
25
+ "@pluv/types": "^0.24.1"
26
26
  },
27
27
  "devDependencies": {
28
28
  "eslint": "^8.57.0",
29
29
  "genversion": "^3.2.0",
30
30
  "tsup": "^8.2.4",
31
31
  "typescript": "^5.5.4",
32
- "@pluv/tsconfig": "^0.23.0",
33
- "eslint-config-pluv": "^0.23.0"
32
+ "@pluv/tsconfig": "^0.24.1",
33
+ "eslint-config-pluv": "^0.24.1"
34
34
  },
35
35
  "scripts": {
36
36
  "build": "pnpm run version && tsup src/index.ts --format esm,cjs --dts",