@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.mjs CHANGED
@@ -353,30 +353,33 @@ var PING_TIMEOUT_MS = 3e4;
353
353
  // src/IORoom.ts
354
354
  var IORoom = class {
355
355
  constructor(id, config) {
356
- this._sessions = /* @__PURE__ */ new Map();
357
- this._uninitialize = null;
358
356
  this._authorize = null;
359
- const { authorize: authorize2, context, crdt = noop, debug, onDestroy, platform, router } = config;
357
+ this._uninitialize = null;
358
+ this._sessions = /* @__PURE__ */ new Map();
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
- onDestroy: (event) => onDestroy == null ? void 0 : onDestroy(event)
367
+ onDestroy: (event) => onDestroy == null ? void 0 : onDestroy(event),
368
+ onMessage: (event) => onMessage == null ? void 0 : onMessage(event)
369
369
  };
370
370
  if (authorize2) this._authorize = authorize2;
371
371
  const webSockets = this._platform.getWebSockets();
372
- if (!webSockets.length) return;
373
372
  webSockets.forEach((webSocket) => {
374
373
  const deserialized = this._platform.getSerializedState(webSocket);
375
374
  const sessionId = this._platform.getSessionId(webSocket);
376
375
  if (!deserialized) return;
377
376
  if (typeof sessionId !== "string") return;
378
- 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);
379
379
  });
380
+ const { doc, uninitialize } = this._initialize();
381
+ this._doc = doc;
382
+ this._uninitialize = uninitialize;
380
383
  }
381
384
  get _events() {
382
385
  return this._router._events;
@@ -392,6 +395,10 @@ var IORoom = class {
392
395
  }
393
396
  });
394
397
  }
398
+ get _initialized() {
399
+ var _a;
400
+ return Promise.resolve(!!((_a = this._uninitialize) == null ? void 0 : _a.then((result) => !!result)));
401
+ }
395
402
  getSize() {
396
403
  const currentTime = (/* @__PURE__ */ new Date()).getTime();
397
404
  return Array.from(this._sessions.values()).reduce((count, pluvWs) => {
@@ -404,25 +411,37 @@ var IORoom = class {
404
411
  onClose(webSocket) {
405
412
  this._ensureDetached();
406
413
  const wsSession = this._getAbstractWs(webSocket);
407
- if (!wsSession) return () => void 0;
414
+ if (!wsSession) return () => __async(this, null, function* () {
415
+ return void 0;
416
+ });
408
417
  return this._onClose(wsSession);
409
418
  }
410
419
  onError(webSocket) {
411
420
  this._ensureDetached();
412
421
  const wsSession = this._getAbstractWs(webSocket);
413
- if (!wsSession) return () => void 0;
422
+ if (!wsSession) return () => __async(this, null, function* () {
423
+ return void 0;
424
+ });
414
425
  return this._onClose(wsSession);
415
426
  }
416
427
  onMessage(webSocket) {
417
428
  this._ensureDetached();
418
429
  const wsSession = this._getAbstractWs(webSocket);
419
- if (!wsSession) return () => void 0;
430
+ if (!wsSession) return () => __async(this, null, function* () {
431
+ return void 0;
432
+ });
420
433
  return this._onMessage(wsSession);
421
434
  }
422
435
  register(_0) {
423
436
  return __async(this, arguments, function* (webSocket, options = {}) {
424
437
  const { token } = options;
425
- 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
+ }
426
445
  const user = yield this._getAuthorizedUser(token);
427
446
  const ioAuthorize = this._getIOAuthorize();
428
447
  const isUnauthorized = !!(ioAuthorize == null ? void 0 : ioAuthorize.required) && !user;
@@ -430,7 +449,7 @@ var IORoom = class {
430
449
  var _a;
431
450
  return ((_a = session.user) == null ? void 0 : _a.id) === user.id;
432
451
  })));
433
- const pluvWs = yield this._platform.convertWebSocket(webSocket, { room: this.id });
452
+ const pluvWs = this._platform.convertWebSocket(webSocket, { room: this.id });
434
453
  this._logDebug(`${colors.blue(`Registering connection for room ${this.id}:`)} ${pluvWs.sessionId}`);
435
454
  yield this._platform.acceptWebSocket(pluvWs);
436
455
  if (isUnauthorized || isTokenInUse) {
@@ -512,13 +531,6 @@ var IORoom = class {
512
531
  const sessions = Array.from(this._sessions.values());
513
532
  return (_b = sessions.find((pluvWs) => pluvWs.webSocket === webSocket)) != null ? _b : null;
514
533
  }
515
- _getSession(webSocket) {
516
- return __async(this, null, function* () {
517
- const pluvWs = this._getAbstractWs(webSocket);
518
- if (!pluvWs) throw new Error("Session could not be found");
519
- return yield pluvWs.getSession();
520
- });
521
- }
522
534
  _getAuthorizedUser(token) {
523
535
  return __async(this, null, function* () {
524
536
  var _a;
@@ -548,6 +560,14 @@ var IORoom = class {
548
560
  }
549
561
  });
550
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
+ }
551
571
  _getIOAuthorize() {
552
572
  if (typeof this._authorize === "function") {
553
573
  return this._authorize(this._context);
@@ -563,6 +583,13 @@ var IORoom = class {
563
583
  if (!procedure) return message.data;
564
584
  return procedure.config.input ? procedure.config.input.parse(message.data) : message.data;
565
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
+ }
566
593
  _getSessions() {
567
594
  return __async(this, null, function* () {
568
595
  const promises = Array.from(this._sessions.values()).map((pluvWs) => __async(this, null, function* () {
@@ -572,45 +599,68 @@ var IORoom = class {
572
599
  });
573
600
  }
574
601
  _initialize() {
575
- return __async(this, null, function* () {
602
+ const promise = (() => __async(this, null, function* () {
576
603
  this._logDebug(`${colors.blue(`Initializing room ${this.id}:`)}`);
577
604
  if (!!this._uninitialize) {
578
- yield this._uninitialize();
605
+ const uninitialize2 = (yield this._uninitialize).bind(this);
606
+ yield uninitialize2();
579
607
  this._uninitialize = null;
580
608
  }
581
609
  const pubSubId = yield this._platform.pubSub.subscribe(
582
610
  this.id,
583
611
  (_a) => __async(this, null, function* () {
584
612
  var _b = _a, { options = {} } = _b, message = __objRest(_b, ["options"]);
585
- const sessionId = message.connectionId;
586
- const user = message.user;
587
- yield this._sendMessage(message, { sessionId, user }, options);
613
+ const sender = {
614
+ sessionId: message.connectionId,
615
+ user: message.user
616
+ };
617
+ switch (options.type) {
618
+ case "self": {
619
+ yield this._sendSelfMessage(message, sender);
620
+ return;
621
+ }
622
+ case "sync": {
623
+ yield this._sendSyncMessage(message, sender);
624
+ return;
625
+ }
626
+ case "broadcast":
627
+ default: {
628
+ const sessionIds = options.sessionIds;
629
+ yield this._sendBroadcastMessage(message, sender, sessionIds);
630
+ }
631
+ }
588
632
  })
589
633
  );
590
- this._uninitialize = () => __async(this, null, function* () {
634
+ const doc = yield this._getInitialDoc();
635
+ const uninitialize = () => __async(this, null, function* () {
591
636
  this._platform.pubSub.unsubscribe(pubSubId);
592
- const encodedState = this._doc.getEncodedState();
593
- this._doc.destroy();
594
- this._doc = this._docFactory.getEmpty();
595
- this._listeners.onDestroy(__spreadProps(__spreadValues({}, this._context), {
637
+ const doc2 = yield this._doc;
638
+ const encodedState = doc2.getEncodedState();
639
+ doc2.destroy();
640
+ this._doc = Promise.resolve(this._docFactory.getEmpty());
641
+ this._listeners.onDestroy({
642
+ context: this._context,
596
643
  encodedState,
597
644
  room: this.id
598
- }));
645
+ });
599
646
  this._uninitialize = null;
600
647
  });
601
- });
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 };
602
653
  }
603
654
  _logDebug(...data) {
604
655
  this._debug && console.log(...data);
605
656
  }
606
657
  _onClose(webSocket) {
607
- return () => {
608
- if (!this._uninitialize) return;
609
- 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 });
610
661
  this._logDebug(`${colors.blue(`Unregistering connection for room ${this.id}:`)} ${webSocket.sessionId}`);
611
662
  this._sessions.delete(webSocket.sessionId);
612
663
  this._platform.persistance.deleteUser(this.id, webSocket.sessionId).finally(() => __async(this, null, function* () {
613
- var _a;
614
664
  yield this._broadcast({
615
665
  message: {
616
666
  type: "$EXIT",
@@ -622,27 +672,31 @@ var IORoom = class {
622
672
  this._logDebug(`${colors.blue(`Unregistered connection for room ${this.id}:`)} ${webSocket.sessionId}`);
623
673
  this._logDebug(`${colors.blue(`Room ${this.id} size:`)} ${size}`);
624
674
  if (size) return;
625
- (_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
+ }
626
679
  }));
627
- };
680
+ });
628
681
  }
629
682
  _onMessage(webSocket) {
630
683
  return (event) => __async(this, null, function* () {
631
684
  var _a, _b, _c, _d, _e, _f;
685
+ if (!(yield this._initialized)) return;
632
686
  const pluvWs = this._getAbstractWs(webSocket);
633
687
  if (!pluvWs) throw new Error("Could not get session");
634
688
  const [session, sessions] = yield Promise.all([
635
689
  this._getSession(pluvWs),
636
690
  this._getSessions()
637
691
  ]);
692
+ const doc = yield this._doc;
638
693
  const baseContext = {
639
694
  context: this._context,
640
- doc: this._doc,
695
+ doc,
641
696
  room: this.id,
642
697
  session,
643
698
  sessions
644
699
  };
645
- if (!this._uninitialize) return;
646
700
  if (pluvWs.state.quit) {
647
701
  pluvWs.close(1011, "WebSocket broken.");
648
702
  return;
@@ -664,30 +718,35 @@ var IORoom = class {
664
718
  return;
665
719
  }
666
720
  const extendedContext = __spreadProps(__spreadValues({}, baseContext), { context: __spreadValues({}, this._context) });
667
- Promise.all([
721
+ yield Promise.all([
668
722
  (_b = (_a = procedure.config).broadcast) == null ? void 0 : _b.call(_a, inputs, extendedContext),
669
723
  (_d = (_c = procedure.config).self) == null ? void 0 : _d.call(_c, inputs, extendedContext),
670
724
  (_f = (_e = procedure.config).sync) == null ? void 0 : _f.call(_e, inputs, baseContext)
671
725
  ]).then((_0) => __async(this, [_0], function* ([broadcast, self, sync]) {
672
726
  const sessionId = session.id;
673
727
  const user = session.user;
674
- if (broadcast) {
675
- Object.entries(broadcast).forEach(([type, data]) => {
676
- this._broadcast({
677
- message: { data, type },
678
- senderId: sessionId
679
- });
680
- });
681
- }
682
- 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;
683
741
  yield Promise.all(
684
742
  Object.entries(self).map((_02) => __async(this, [_02], function* ([type, data]) {
685
743
  yield this._sendSelfMessage({ data, type }, { sessionId, user });
686
744
  }))
687
745
  );
688
- }
689
- if (sync) {
690
- 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({
691
750
  connectionId: session.id,
692
751
  options: { type: "sync" },
693
752
  room: this.id,
@@ -698,7 +757,8 @@ var IORoom = class {
698
757
  yield this._sendSelfMessage({ data, type }, { sessionId, user });
699
758
  }))
700
759
  );
701
- }
760
+ });
761
+ yield Promise.all([handleBroadcast(), handleSelf(), handleSync()]);
702
762
  }));
703
763
  });
704
764
  }
@@ -713,23 +773,19 @@ var IORoom = class {
713
773
  return null;
714
774
  }
715
775
  }
716
- _sendMessage(_0, _1) {
717
- return __async(this, arguments, function* (message, sender, options = {}) {
718
- switch (options.type) {
719
- case "self": {
720
- yield this._sendSelfMessage(message, sender);
721
- return;
722
- }
723
- case "sync": {
724
- yield this._sendSyncMessage(message, sender);
725
- return;
726
- }
727
- case "broadcast":
728
- default: {
729
- const sessionIds = options.sessionIds;
730
- yield this._sendBroadcastMessage(message, sender, sessionIds);
731
- }
732
- }
776
+ _sendMessage(pluvWs, message) {
777
+ return __async(this, null, function* () {
778
+ const { data, type } = message;
779
+ if (!(yield this._initialized)) return;
780
+ const doc = yield this._doc;
781
+ this._listeners.onMessage({
782
+ context: this._context,
783
+ encodedState: doc.getEncodedState(),
784
+ message: { data, type },
785
+ room: this.id,
786
+ user: message.user
787
+ });
788
+ yield Promise.resolve(pluvWs.sendMessage(message));
733
789
  });
734
790
  }
735
791
  _sendBroadcastMessage(message, sender, sessionIds) {
@@ -746,7 +802,7 @@ var IORoom = class {
746
802
  var _a2;
747
803
  const session = yield pluvWs.getSession();
748
804
  const user = (_a2 = session.user) != null ? _a2 : null;
749
- pluvWs.sendMessage({ connectionId, data, room, type, user });
805
+ this._sendMessage(pluvWs, { connectionId, data, room, type, user });
750
806
  }));
751
807
  yield Promise.all(promises);
752
808
  });
@@ -761,7 +817,7 @@ var IORoom = class {
761
817
  if (message.type === "$PONG") yield this._emitQuitters();
762
818
  const session = yield pluvWs.getSession();
763
819
  const user = (_b = session.user) != null ? _b : null;
764
- pluvWs.sendMessage(__spreadValues({
820
+ this._sendMessage(pluvWs, __spreadValues({
765
821
  connectionId: senderId,
766
822
  room: this.id,
767
823
  user
@@ -772,9 +828,10 @@ var IORoom = class {
772
828
  return __async(this, null, function* () {
773
829
  var _a;
774
830
  if (!sender) return;
831
+ const doc = yield this._doc;
775
832
  const context = {
776
833
  context: this._context,
777
- doc: this._doc,
834
+ doc,
778
835
  room: this.id,
779
836
  session: null,
780
837
  sessions: yield this._getSessions()
@@ -807,114 +864,15 @@ var IORoom = class {
807
864
  };
808
865
 
809
866
  // src/version.generated.ts
810
- var version = "0.22.0";
867
+ var version = "0.24.0";
811
868
 
812
869
  // src/PluvServer.ts
813
870
  var PluvServer = class {
814
871
  constructor(options) {
815
- this._rooms = /* @__PURE__ */ new Map();
872
+ this.version = version;
816
873
  this._authorize = null;
817
- this._context = {};
818
- this._version = version;
819
- const {
820
- authorize: authorize2,
821
- context,
822
- crdt = noop2,
823
- debug = false,
824
- onRoomDeleted,
825
- onStorageUpdated,
826
- platform,
827
- router = new PluvRouter({})
828
- } = options;
829
- this._crdt = crdt;
830
- this._debug = debug;
831
- this._platform = platform;
832
- this._router = router != null ? router : null;
833
- if (authorize2) this._authorize = authorize2;
834
- if (context) this._context = context;
835
- this._listeners = {
836
- onRoomDeleted: (event) => onRoomDeleted == null ? void 0 : onRoomDeleted(event),
837
- onStorageUpdated: (event) => onStorageUpdated == null ? void 0 : onStorageUpdated(event)
838
- };
839
- }
840
- get _events() {
841
- return this._router._events;
842
- }
843
- get _registrationMode() {
844
- return this._platform._registrationMode;
845
- }
846
- createToken(params) {
847
- return __async(this, null, function* () {
848
- if (!this._authorize) {
849
- throw new Error("IO does not specify authorize during initialization.");
850
- }
851
- const ioAuthorize = typeof this._authorize === "function" ? this._authorize(params) : this._authorize;
852
- const secret = ioAuthorize.secret;
853
- return yield authorize({
854
- platform: this._platform,
855
- secret
856
- }).encode(params);
857
- });
858
- }
859
- getRoom(room, ...options) {
860
- var _a, _c;
861
- const _b = (_a = options[0]) != null ? _a : {}, { debug } = _b, platformRoomContext = __objRest(_b, ["debug"]);
862
- this._purgeEmptyRooms();
863
- if (!/^[a-z0-9]+[a-z0-9\-_]+[a-z0-9]+$/i.test(room)) {
864
- throw new Error("Unsupported room name");
865
- }
866
- const platform = this._platform;
867
- const oldRoom = this._rooms.get(room);
868
- if (oldRoom) return oldRoom;
869
- const roomContext = __spreadValues(__spreadValues({}, this._context), platformRoomContext);
870
- const newRoom = new IORoom(room, {
871
- authorize: (_c = this._authorize) != null ? _c : void 0,
872
- context: roomContext,
873
- crdt: this._crdt,
874
- debug: debug != null ? debug : this._debug,
875
- onDestroy: (_0) => __async(this, [_0], function* ({ encodedState, room: room2 }) {
876
- this._logDebug(`${colors2.blue("Deleting empty room:")} ${room2}`);
877
- const roomContext2 = __spreadValues({
878
- room: room2,
879
- encodedState
880
- }, platformRoomContext);
881
- this._rooms.delete(room2);
882
- yield Promise.resolve(this._listeners.onRoomDeleted(roomContext2));
883
- yield this._platform.persistance.deleteStorageState(room2);
884
- if (this._debug) {
885
- const rooms = Array.from(this._rooms.keys());
886
- this._logDebug(`${colors2.blue("Deleted room:")} ${room2}`);
887
- this._logDebug(`${colors2.blue("Rooms available:")} ${rooms.join(", ")}`);
888
- }
889
- }),
890
- platform,
891
- router: this._router
892
- });
893
- this._rooms.set(room, newRoom);
894
- if (this._debug) {
895
- const rooms = Array.from(this._rooms.keys());
896
- this._logDebug(`${colors2.blue("Created room:")} ${room}`);
897
- this._logDebug(`${colors2.blue("Rooms available:")} ${rooms.join(", ")}`);
898
- }
899
- return newRoom;
900
- }
901
- _logDebug(...data) {
902
- this._debug && console.log(...data);
903
- }
904
- _purgeEmptyRooms() {
905
- const rooms = Array.from(this._rooms.entries());
906
- rooms.forEach(([id, room]) => {
907
- if (!!(room == null ? void 0 : room.getSize())) return;
908
- this._rooms.delete(id);
909
- });
910
- }
911
- };
912
-
913
- // src/PluvIO.ts
914
- var PluvIO = class {
915
- constructor(options) {
916
- this._router = new PluvRouter({
917
- $GET_OTHERS: this.procedure.sync((data, { room, session, sessions }) => {
874
+ this._baseRouter = new PluvRouter({
875
+ $GET_OTHERS: this._procedure.sync((data, { room, session, sessions }) => {
918
876
  const currentTime = (/* @__PURE__ */ new Date()).getTime();
919
877
  const others = sessions.filter((wsSession) => {
920
878
  if (wsSession.id === (session == null ? void 0 : session.id)) return false;
@@ -934,7 +892,7 @@ var PluvIO = class {
934
892
  );
935
893
  return { $OTHERS_RECEIVED: { others } };
936
894
  }),
937
- $INITIALIZE_SESSION: this.procedure.broadcast((data, { session }) => {
895
+ $INITIALIZE_SESSION: this._procedure.broadcast((data, { session }) => {
938
896
  const presence = data == null ? void 0 : data.presence;
939
897
  if (!session) return {};
940
898
  session.presence = presence;
@@ -950,20 +908,18 @@ var PluvIO = class {
950
908
  const oldState = yield this._platform.persistance.getStorageState(room);
951
909
  const update = data == null ? void 0 : data.update;
952
910
  const updates = [
953
- oldState ? null : yield (_a = this._getInitialStorage) == null ? void 0 : _a.call(this, __spreadProps(__spreadValues({}, context), {
954
- room
955
- })),
911
+ oldState ? null : yield (_a = this._getInitialStorage) == null ? void 0 : _a.call(this, __spreadProps(__spreadValues({}, context), { room })),
956
912
  update
957
913
  ];
958
914
  if (updates.some((_update) => !!_update)) {
959
915
  const encodedState = doc.batchApplyEncodedState(updates).getEncodedState();
960
916
  yield this._platform.persistance.setStorageState(room, encodedState);
961
- this._listeners.onStorageUpdated(__spreadProps(__spreadValues({}, context), { encodedState, room }));
917
+ this._listeners.onStorageUpdated({ context, encodedState, room });
962
918
  }
963
919
  const state = (_b = yield this._platform.persistance.getStorageState(room)) != null ? _b : doc.getEncodedState();
964
920
  return { $STORAGE_RECEIVED: { state } };
965
921
  })),
966
- $PING: this.procedure.self((data, { session }) => {
922
+ $PING: this._procedure.self((data, { session }) => {
967
923
  if (!session) return {};
968
924
  const currentTime = (/* @__PURE__ */ new Date()).getTime();
969
925
  const prevState = session.webSocket.state;
@@ -974,53 +930,54 @@ var PluvIO = class {
974
930
  });
975
931
  return { $PONG: {} };
976
932
  }),
977
- $UPDATE_PRESENCE: this.procedure.broadcast((data, { session }) => {
933
+ $UPDATE_PRESENCE: this._procedure.broadcast((data, { session }) => {
978
934
  const presence = data == null ? void 0 : data.presence;
979
935
  if (!session) return {};
980
936
  const updated = Object.assign(/* @__PURE__ */ Object.create(null), session.presence, presence);
981
937
  session.webSocket.presence = updated;
982
938
  return { $PRESENCE_UPDATED: { presence: updated } };
983
939
  }),
984
- $UPDATE_STORAGE: this.procedure.broadcast((data, { context, doc, room }) => {
940
+ $UPDATE_STORAGE: this._procedure.broadcast((data, { context, doc, room }) => {
985
941
  var _a;
986
942
  const origin = data == null ? void 0 : data.origin;
987
943
  const update = (_a = data == null ? void 0 : data.update) != null ? _a : null;
988
- if (origin === "$INITIALIZED" && Object.keys(doc.toJson()).length) {
989
- return {};
990
- }
944
+ if (origin === "$INITIALIZED" && Object.keys(doc.toJson()).length) return {};
991
945
  const updated = update === null ? doc : doc.applyEncodedState({ update });
992
946
  const encodedState = updated.getEncodedState();
993
947
  this._platform.persistance.setStorageState(room, encodedState).then(() => {
994
- this._listeners.onStorageUpdated(__spreadProps(__spreadValues({}, context), {
948
+ this._listeners.onStorageUpdated({
949
+ context,
995
950
  encodedState,
996
951
  room
997
- }));
952
+ });
998
953
  });
999
954
  return { $STORAGE_UPDATED: { state: encodedState } };
1000
955
  })
1001
956
  });
1002
- this._authorize = null;
1003
957
  this._context = {};
1004
958
  this._getInitialStorage = null;
1005
- this._version = version;
1006
959
  const {
1007
960
  authorize: authorize2,
1008
961
  context,
1009
- crdt = noop3,
962
+ crdt = noop2,
1010
963
  debug = false,
1011
964
  getInitialStorage,
1012
965
  onRoomDeleted,
966
+ onRoomMessage,
1013
967
  onStorageUpdated,
1014
- platform
968
+ platform,
969
+ router = new PluvRouter({})
1015
970
  } = options;
1016
971
  this._crdt = crdt;
1017
972
  this._debug = debug;
1018
973
  this._platform = platform;
974
+ this._router = router ? this._baseRouter : PluvRouter.merge(this._baseRouter, router);
1019
975
  if (authorize2) this._authorize = authorize2;
1020
976
  if (context) this._context = context;
1021
977
  if (getInitialStorage) this._getInitialStorage = getInitialStorage;
1022
978
  this._listeners = {
1023
979
  onRoomDeleted: (event) => onRoomDeleted == null ? void 0 : onRoomDeleted(event),
980
+ onRoomMessage: (event) => onRoomMessage == null ? void 0 : onRoomMessage(event),
1024
981
  onStorageUpdated: (event) => onStorageUpdated == null ? void 0 : onStorageUpdated(event)
1025
982
  };
1026
983
  }
@@ -1030,6 +987,69 @@ var PluvIO = class {
1030
987
  get _registrationMode() {
1031
988
  return this._platform._registrationMode;
1032
989
  }
990
+ get _procedure() {
991
+ return new PluvProcedure();
992
+ }
993
+ createRoom(room, ...options) {
994
+ var _a, _c;
995
+ const _b = (_a = options[0]) != null ? _a : {}, { debug, onDestroy, onMessage } = _b, platformRoomContext = __objRest(_b, ["debug", "onDestroy", "onMessage"]);
996
+ if (!/^[a-z0-9]+[a-z0-9\-_]+[a-z0-9]+$/i.test(room)) {
997
+ throw new Error("Unsupported room name");
998
+ }
999
+ const roomContext = __spreadValues(__spreadValues({}, this._context), platformRoomContext);
1000
+ const newRoom = new IORoom(room, {
1001
+ authorize: (_c = this._authorize) != null ? _c : void 0,
1002
+ context: roomContext,
1003
+ crdt: this._crdt,
1004
+ debug: debug != null ? debug : this._debug,
1005
+ onDestroy: (event) => __async(this, null, function* () {
1006
+ this._logDebug(`${colors2.blue("Deleting empty room:")} ${room}`);
1007
+ yield Promise.resolve(onDestroy == null ? void 0 : onDestroy(event));
1008
+ yield Promise.resolve(this._listeners.onRoomDeleted(event));
1009
+ yield this._platform.persistance.deleteStorageState(room);
1010
+ this._logDebug(`${colors2.blue("Deleted room:")} ${room}`);
1011
+ }),
1012
+ onMessage: (event) => __async(this, null, function* () {
1013
+ yield Promise.resolve(onMessage == null ? void 0 : onMessage(event));
1014
+ yield Promise.resolve(this._listeners.onRoomMessage(event));
1015
+ }),
1016
+ platform: this._platform,
1017
+ router: this._router
1018
+ });
1019
+ this._logDebug(`${colors2.blue("Created room:")} ${room}`);
1020
+ return newRoom;
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
+ }
1035
+ _logDebug(...data) {
1036
+ this._debug && console.log(...data);
1037
+ }
1038
+ };
1039
+
1040
+ // src/PluvIO.ts
1041
+ var PluvIO = class {
1042
+ constructor(options) {
1043
+ this.version = version;
1044
+ this._authorize = null;
1045
+ this._context = {};
1046
+ const { authorize: authorize2, context, crdt = noop3, debug = false, platform } = options;
1047
+ this._crdt = crdt;
1048
+ this._debug = debug;
1049
+ this._platform = platform;
1050
+ if (authorize2) this._authorize = authorize2;
1051
+ if (context) this._context = context;
1052
+ }
1033
1053
  get procedure() {
1034
1054
  return new PluvProcedure();
1035
1055
  }
@@ -1052,29 +1072,24 @@ var PluvIO = class {
1052
1072
  }
1053
1073
  server(config = {}) {
1054
1074
  var _a;
1055
- const router = config.router ? this.mergeRouters(this._router, config.router) : this._router;
1056
- return new PluvServer(__spreadProps(__spreadValues({}, this._listeners), {
1075
+ return new PluvServer(__spreadProps(__spreadValues({}, config), {
1057
1076
  authorize: (_a = this._authorize) != null ? _a : void 0,
1058
1077
  context: this._context,
1059
1078
  crdt: this._crdt,
1060
1079
  debug: this._debug,
1061
- platform: this._platform,
1062
- router
1080
+ platform: this._platform
1063
1081
  }));
1064
1082
  }
1065
1083
  };
1066
1084
 
1067
1085
  // src/createIO.ts
1068
1086
  var createIO = (params) => {
1069
- const { authorize: authorize2, context, crdt, debug, getInitialStorage, onRoomDeleted, onStorageUpdated, platform } = params;
1087
+ const { authorize: authorize2, context, crdt, debug, platform } = params;
1070
1088
  return new PluvIO({
1071
1089
  authorize: authorize2,
1072
1090
  context,
1073
1091
  crdt,
1074
1092
  debug,
1075
- getInitialStorage,
1076
- onRoomDeleted,
1077
- onStorageUpdated,
1078
1093
  platform
1079
1094
  });
1080
1095
  };