@pluv/io 0.21.1 → 0.23.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,10 +353,10 @@ 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
360
  this._context = context;
361
361
  this._debug = debug;
362
362
  this._docFactory = crdt.doc(() => ({}));
@@ -365,7 +365,8 @@ var IORoom = class {
365
365
  this._platform = platform.initialize({ context });
366
366
  this.id = id;
367
367
  this._listeners = {
368
- onDestroy: (event) => onDestroy == null ? void 0 : onDestroy(event)
368
+ onDestroy: (event) => onDestroy == null ? void 0 : onDestroy(event),
369
+ onMessage: (event) => onMessage == null ? void 0 : onMessage(event)
369
370
  };
370
371
  if (authorize2) this._authorize = authorize2;
371
372
  const webSockets = this._platform.getWebSockets();
@@ -582,9 +583,25 @@ var IORoom = class {
582
583
  this.id,
583
584
  (_a) => __async(this, null, function* () {
584
585
  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);
586
+ const sender = {
587
+ sessionId: message.connectionId,
588
+ user: message.user
589
+ };
590
+ switch (options.type) {
591
+ case "self": {
592
+ yield this._sendSelfMessage(message, sender);
593
+ return;
594
+ }
595
+ case "sync": {
596
+ yield this._sendSyncMessage(message, sender);
597
+ return;
598
+ }
599
+ case "broadcast":
600
+ default: {
601
+ const sessionIds = options.sessionIds;
602
+ yield this._sendBroadcastMessage(message, sender, sessionIds);
603
+ }
604
+ }
588
605
  })
589
606
  );
590
607
  this._uninitialize = () => __async(this, null, function* () {
@@ -592,10 +609,11 @@ var IORoom = class {
592
609
  const encodedState = this._doc.getEncodedState();
593
610
  this._doc.destroy();
594
611
  this._doc = this._docFactory.getEmpty();
595
- this._listeners.onDestroy(__spreadProps(__spreadValues({}, this._context), {
612
+ this._listeners.onDestroy({
613
+ context: this._context,
596
614
  encodedState,
597
615
  room: this.id
598
- }));
616
+ });
599
617
  this._uninitialize = null;
600
618
  });
601
619
  });
@@ -713,23 +731,17 @@ var IORoom = class {
713
731
  return null;
714
732
  }
715
733
  }
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
- }
734
+ _sendMessage(pluvWs, message) {
735
+ return __async(this, null, function* () {
736
+ const { data, type } = message;
737
+ this._listeners.onMessage({
738
+ context: this._context,
739
+ encodedState: this._doc.getEncodedState(),
740
+ message: { data, type },
741
+ room: this.id,
742
+ user: message.user
743
+ });
744
+ yield Promise.resolve(pluvWs.sendMessage(message));
733
745
  });
734
746
  }
735
747
  _sendBroadcastMessage(message, sender, sessionIds) {
@@ -746,7 +758,7 @@ var IORoom = class {
746
758
  var _a2;
747
759
  const session = yield pluvWs.getSession();
748
760
  const user = (_a2 = session.user) != null ? _a2 : null;
749
- pluvWs.sendMessage({ connectionId, data, room, type, user });
761
+ this._sendMessage(pluvWs, { connectionId, data, room, type, user });
750
762
  }));
751
763
  yield Promise.all(promises);
752
764
  });
@@ -761,7 +773,7 @@ var IORoom = class {
761
773
  if (message.type === "$PONG") yield this._emitQuitters();
762
774
  const session = yield pluvWs.getSession();
763
775
  const user = (_b = session.user) != null ? _b : null;
764
- pluvWs.sendMessage(__spreadValues({
776
+ this._sendMessage(pluvWs, __spreadValues({
765
777
  connectionId: senderId,
766
778
  room: this.id,
767
779
  user
@@ -807,114 +819,15 @@ var IORoom = class {
807
819
  };
808
820
 
809
821
  // src/version.generated.ts
810
- var version = "0.21.1";
822
+ var version = "0.23.0";
811
823
 
812
824
  // src/PluvServer.ts
813
825
  var PluvServer = class {
814
826
  constructor(options) {
815
- this._rooms = /* @__PURE__ */ new Map();
827
+ this.version = version;
816
828
  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.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 }) => {
829
+ this._baseRouter = new PluvRouter({
830
+ $GET_OTHERS: this._procedure.sync((data, { room, session, sessions }) => {
918
831
  const currentTime = (/* @__PURE__ */ new Date()).getTime();
919
832
  const others = sessions.filter((wsSession) => {
920
833
  if (wsSession.id === (session == null ? void 0 : session.id)) return false;
@@ -934,7 +847,7 @@ var PluvIO = class {
934
847
  );
935
848
  return { $OTHERS_RECEIVED: { others } };
936
849
  }),
937
- $INITIALIZE_SESSION: this.procedure.broadcast((data, { session }) => {
850
+ $INITIALIZE_SESSION: this._procedure.broadcast((data, { session }) => {
938
851
  const presence = data == null ? void 0 : data.presence;
939
852
  if (!session) return {};
940
853
  session.presence = presence;
@@ -958,25 +871,30 @@ var PluvIO = class {
958
871
  if (updates.some((_update) => !!_update)) {
959
872
  const encodedState = doc.batchApplyEncodedState(updates).getEncodedState();
960
873
  yield this._platform.persistance.setStorageState(room, encodedState);
961
- this._listeners.onStorageUpdated(__spreadProps(__spreadValues({}, context), { encodedState, room }));
874
+ this._listeners.onStorageUpdated({ context, encodedState, room });
962
875
  }
963
876
  const state = (_b = yield this._platform.persistance.getStorageState(room)) != null ? _b : doc.getEncodedState();
964
877
  return { $STORAGE_RECEIVED: { state } };
965
878
  })),
966
- $PING: this.procedure.self((data, { session }) => {
879
+ $PING: this._procedure.self((data, { session }) => {
967
880
  if (!session) return {};
968
881
  const currentTime = (/* @__PURE__ */ new Date()).getTime();
969
- session.timers.ping = currentTime;
882
+ const prevState = session.webSocket.state;
883
+ session.webSocket.state = __spreadProps(__spreadValues({}, prevState), {
884
+ timers: __spreadProps(__spreadValues({}, prevState.timers), {
885
+ ping: currentTime
886
+ })
887
+ });
970
888
  return { $PONG: {} };
971
889
  }),
972
- $UPDATE_PRESENCE: this.procedure.broadcast((data, { session }) => {
890
+ $UPDATE_PRESENCE: this._procedure.broadcast((data, { session }) => {
973
891
  const presence = data == null ? void 0 : data.presence;
974
892
  if (!session) return {};
975
893
  const updated = Object.assign(/* @__PURE__ */ Object.create(null), session.presence, presence);
976
894
  session.webSocket.presence = updated;
977
895
  return { $PRESENCE_UPDATED: { presence: updated } };
978
896
  }),
979
- $UPDATE_STORAGE: this.procedure.broadcast((data, { context, doc, room }) => {
897
+ $UPDATE_STORAGE: this._procedure.broadcast((data, { context, doc, room }) => {
980
898
  var _a;
981
899
  const origin = data == null ? void 0 : data.origin;
982
900
  const update = (_a = data == null ? void 0 : data.update) != null ? _a : null;
@@ -986,36 +904,40 @@ var PluvIO = class {
986
904
  const updated = update === null ? doc : doc.applyEncodedState({ update });
987
905
  const encodedState = updated.getEncodedState();
988
906
  this._platform.persistance.setStorageState(room, encodedState).then(() => {
989
- this._listeners.onStorageUpdated(__spreadProps(__spreadValues({}, context), {
907
+ this._listeners.onStorageUpdated({
908
+ context,
990
909
  encodedState,
991
910
  room
992
- }));
911
+ });
993
912
  });
994
913
  return { $STORAGE_UPDATED: { state: encodedState } };
995
914
  })
996
915
  });
997
- this._authorize = null;
998
916
  this._context = {};
999
917
  this._getInitialStorage = null;
1000
- this._version = version;
918
+ this._rooms = /* @__PURE__ */ new Map();
1001
919
  const {
1002
920
  authorize: authorize2,
1003
921
  context,
1004
- crdt = noop3,
922
+ crdt = noop2,
1005
923
  debug = false,
1006
924
  getInitialStorage,
1007
925
  onRoomDeleted,
926
+ onRoomMessage,
1008
927
  onStorageUpdated,
1009
- platform
928
+ platform,
929
+ router = new PluvRouter({})
1010
930
  } = options;
1011
931
  this._crdt = crdt;
1012
932
  this._debug = debug;
1013
933
  this._platform = platform;
934
+ this._router = router ? this._baseRouter : PluvRouter.merge(this._baseRouter, router);
1014
935
  if (authorize2) this._authorize = authorize2;
1015
936
  if (context) this._context = context;
1016
937
  if (getInitialStorage) this._getInitialStorage = getInitialStorage;
1017
938
  this._listeners = {
1018
939
  onRoomDeleted: (event) => onRoomDeleted == null ? void 0 : onRoomDeleted(event),
940
+ onRoomMessage: (event) => onRoomMessage == null ? void 0 : onRoomMessage(event),
1019
941
  onStorageUpdated: (event) => onStorageUpdated == null ? void 0 : onStorageUpdated(event)
1020
942
  };
1021
943
  }
@@ -1025,6 +947,88 @@ var PluvIO = class {
1025
947
  get _registrationMode() {
1026
948
  return this._platform._registrationMode;
1027
949
  }
950
+ get _procedure() {
951
+ return new PluvProcedure();
952
+ }
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) {
967
+ var _a, _c;
968
+ const _b = (_a = options[0]) != null ? _a : {}, { debug } = _b, platformRoomContext = __objRest(_b, ["debug"]);
969
+ this._purgeEmptyRooms();
970
+ if (!/^[a-z0-9]+[a-z0-9\-_]+[a-z0-9]+$/i.test(room)) {
971
+ throw new Error("Unsupported room name");
972
+ }
973
+ const platform = this._platform;
974
+ const oldRoom = this._rooms.get(room);
975
+ if (oldRoom) return oldRoom;
976
+ const roomContext = __spreadValues(__spreadValues({}, this._context), platformRoomContext);
977
+ const newRoom = new IORoom(room, {
978
+ authorize: (_c = this._authorize) != null ? _c : void 0,
979
+ context: roomContext,
980
+ crdt: this._crdt,
981
+ debug: debug != null ? debug : this._debug,
982
+ onDestroy: (event) => __async(this, null, function* () {
983
+ this._logDebug(`${colors2.blue("Deleting empty room:")} ${room}`);
984
+ this._rooms.delete(room);
985
+ yield Promise.resolve(this._listeners.onRoomDeleted(event));
986
+ 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
+ }
992
+ }),
993
+ onMessage: (event) => __async(this, null, function* () {
994
+ yield Promise.resolve(this._listeners.onRoomMessage(event));
995
+ }),
996
+ platform,
997
+ router: this._router
998
+ });
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
+ }
1005
+ return newRoom;
1006
+ }
1007
+ _logDebug(...data) {
1008
+ this._debug && console.log(...data);
1009
+ }
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
+ };
1018
+
1019
+ // src/PluvIO.ts
1020
+ var PluvIO = class {
1021
+ constructor(options) {
1022
+ this.version = version;
1023
+ this._authorize = null;
1024
+ this._context = {};
1025
+ const { authorize: authorize2, context, crdt = noop3, debug = false, platform } = options;
1026
+ this._crdt = crdt;
1027
+ this._debug = debug;
1028
+ this._platform = platform;
1029
+ if (authorize2) this._authorize = authorize2;
1030
+ if (context) this._context = context;
1031
+ }
1028
1032
  get procedure() {
1029
1033
  return new PluvProcedure();
1030
1034
  }
@@ -1047,29 +1051,24 @@ var PluvIO = class {
1047
1051
  }
1048
1052
  server(config = {}) {
1049
1053
  var _a;
1050
- const router = config.router ? this.mergeRouters(this._router, config.router) : this._router;
1051
- return new PluvServer(__spreadProps(__spreadValues({}, this._listeners), {
1054
+ return new PluvServer(__spreadProps(__spreadValues({}, config), {
1052
1055
  authorize: (_a = this._authorize) != null ? _a : void 0,
1053
1056
  context: this._context,
1054
1057
  crdt: this._crdt,
1055
1058
  debug: this._debug,
1056
- platform: this._platform,
1057
- router
1059
+ platform: this._platform
1058
1060
  }));
1059
1061
  }
1060
1062
  };
1061
1063
 
1062
1064
  // src/createIO.ts
1063
1065
  var createIO = (params) => {
1064
- const { authorize: authorize2, context, crdt, debug, getInitialStorage, onRoomDeleted, onStorageUpdated, platform } = params;
1066
+ const { authorize: authorize2, context, crdt, debug, platform } = params;
1065
1067
  return new PluvIO({
1066
1068
  authorize: authorize2,
1067
1069
  context,
1068
1070
  crdt,
1069
1071
  debug,
1070
- getInitialStorage,
1071
- onRoomDeleted,
1072
- onStorageUpdated,
1073
1072
  platform
1074
1073
  });
1075
1074
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluv/io",
3
- "version": "0.21.1",
3
+ "version": "0.23.0",
4
4
  "description": "@pluv/io server-side websocket manager",
5
5
  "author": "leedavidcs",
6
6
  "license": "MIT",
@@ -21,16 +21,16 @@
21
21
  "jose": "^5.6.3",
22
22
  "kleur": "^4.1.5",
23
23
  "wonka": "^6.3.4",
24
- "@pluv/crdt": "^0.21.1",
25
- "@pluv/types": "^0.21.1"
24
+ "@pluv/crdt": "^0.23.0",
25
+ "@pluv/types": "^0.23.0"
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.21.1",
33
- "eslint-config-pluv": "^0.21.1"
32
+ "@pluv/tsconfig": "^0.23.0",
33
+ "eslint-config-pluv": "^0.23.0"
34
34
  },
35
35
  "scripts": {
36
36
  "build": "pnpm run version && tsup src/index.ts --format esm,cjs --dts",
@@ -39,16 +39,16 @@ export abstract class AbstractPlatform<
39
39
  TPlatformContext extends Record<string, any> = {},
40
40
  TRoomContext extends Record<string, any> = {},
41
41
  > {
42
- private _initialized: boolean = false;
43
-
44
- readonly _ioContext: TPlatformContext | undefined;
45
- readonly _roomContext: TRoomContext | undefined;
42
+ protected readonly _ioContext: TPlatformContext | undefined;
43
+ protected readonly _roomContext: TRoomContext | undefined;
46
44
 
47
- abstract readonly _registrationMode: WebSocketRegistrationMode;
45
+ private _initialized: boolean = false;
48
46
 
49
47
  public persistance: AbstractPersistance;
50
48
  public pubSub: AbstractPubSub;
51
49
 
50
+ public abstract readonly _registrationMode: WebSocketRegistrationMode;
51
+
52
52
  constructor(config: AbstractPlatformConfig<TPlatformContext, TRoomContext> = {}) {
53
53
  const { context, persistance, pubSub } = config;
54
54
 
@@ -68,7 +68,7 @@ export abstract class AbstractPlatform<
68
68
 
69
69
  public abstract getLastPing(webSocket: AbstractWebSocket): number | null;
70
70
 
71
- public abstract getSerializedState(webSocket: AbstractWebSocket): WebSocketSerializedState | null;
71
+ public abstract getSerializedState(webSocket: InferWebSocketSource<TWebSocket>): WebSocketSerializedState | null;
72
72
 
73
73
  public abstract getSessionId(webSocket: InferWebSocketSource<TWebSocket>): string | null;
74
74
 
@@ -72,6 +72,7 @@ export abstract class AbstractWebSocket<TWebSocket = any> {
72
72
  public abstract get readyState(): 0 | 1 | 2 | 3;
73
73
  public abstract get sessionId(): string;
74
74
  public abstract get state(): WebSocketSerializedState;
75
+ public abstract set state(state: WebSocketSerializedState);
75
76
 
76
77
  constructor(webSocket: TWebSocket, config: AbstractWebSocketConfig) {
77
78
  const { persistance, room } = config;