@pluv/client 0.17.2 → 0.18.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/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +159 -0
- package/README.md +2 -5
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +59 -129
- package/dist/index.mjs +59 -129
- package/package.json +5 -5
- package/src/AbstractRoom.ts +8 -33
- package/src/CrdtManager.ts +9 -33
- package/src/CrdtNotifier.ts +5 -11
- package/src/EventNotifier.ts +5 -11
- package/src/MockedRoom.ts +14 -57
- package/src/PluvClient.ts +4 -17
- package/src/PluvRoom.ts +87 -203
- package/src/StateNotifier.ts +4 -17
- package/src/UsersManager.ts +4 -20
- package/src/createClient.ts +1 -3
- package/src/index.ts +2 -12
- package/src/types.ts +2 -11
package/dist/index.mjs
CHANGED
|
@@ -57,10 +57,7 @@ import { noop } from "@pluv/crdt";
|
|
|
57
57
|
var CrdtManager = class {
|
|
58
58
|
constructor(options) {
|
|
59
59
|
this.initialized = false;
|
|
60
|
-
const {
|
|
61
|
-
encodedState,
|
|
62
|
-
initialStorage = noop.doc({})
|
|
63
|
-
} = options;
|
|
60
|
+
const { encodedState, initialStorage = noop.doc({}) } = options;
|
|
64
61
|
this._docFactory = initialStorage;
|
|
65
62
|
this.doc = encodedState ? initialStorage.getFresh().applyEncodedState({ update: encodedState }) : initialStorage.getFresh();
|
|
66
63
|
}
|
|
@@ -92,18 +89,10 @@ var CrdtManager = class {
|
|
|
92
89
|
this.doc = this._applyDocUpdates(this.doc, updates, origin).track();
|
|
93
90
|
return this;
|
|
94
91
|
}
|
|
95
|
-
const onEmpty = this._applyDocUpdates(
|
|
96
|
-
this._docFactory.getEmpty(),
|
|
97
|
-
updates,
|
|
98
|
-
origin
|
|
99
|
-
);
|
|
92
|
+
const onEmpty = this._applyDocUpdates(this._docFactory.getEmpty(), updates, origin);
|
|
100
93
|
if (!onEmpty.isEmpty()) {
|
|
101
94
|
onEmpty.destroy();
|
|
102
|
-
this.doc = this._applyDocUpdates(
|
|
103
|
-
this._docFactory.getFresh(),
|
|
104
|
-
updates,
|
|
105
|
-
origin
|
|
106
|
-
).track();
|
|
95
|
+
this.doc = this._applyDocUpdates(this._docFactory.getFresh(), updates, origin).track();
|
|
107
96
|
this.initialized = true;
|
|
108
97
|
onInitialized == null ? void 0 : onInitialized(this.doc.getEncodedState());
|
|
109
98
|
return this;
|
|
@@ -116,9 +105,7 @@ var CrdtManager = class {
|
|
|
116
105
|
}
|
|
117
106
|
_applyDocUpdates(doc, updates, origin) {
|
|
118
107
|
doc.transact(() => {
|
|
119
|
-
doc.batchApplyEncodedState(
|
|
120
|
-
updates.map((update) => ({ origin, update }))
|
|
121
|
-
);
|
|
108
|
+
doc.batchApplyEncodedState(updates.map((update) => ({ origin, update })));
|
|
122
109
|
}, origin);
|
|
123
110
|
return doc;
|
|
124
111
|
}
|
|
@@ -433,9 +420,7 @@ var MockedRoom = class extends AbstractRoom {
|
|
|
433
420
|
});
|
|
434
421
|
}
|
|
435
422
|
getConnection() {
|
|
436
|
-
return Object.freeze(
|
|
437
|
-
JSON.parse(JSON.stringify(this._state.connection))
|
|
438
|
-
);
|
|
423
|
+
return Object.freeze(JSON.parse(JSON.stringify(this._state.connection)));
|
|
439
424
|
}
|
|
440
425
|
getDoc() {
|
|
441
426
|
return this._crdtManager.doc;
|
|
@@ -566,15 +551,37 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
566
551
|
};
|
|
567
552
|
this._windowListeners = null;
|
|
568
553
|
this._wsListeners = null;
|
|
554
|
+
this.broadcast = new Proxy(
|
|
555
|
+
(event, data) => {
|
|
556
|
+
if (!this._state.webSocket)
|
|
557
|
+
return;
|
|
558
|
+
if (this._state.connection.state !== "Open" /* Open */)
|
|
559
|
+
return;
|
|
560
|
+
const type = event.toString();
|
|
561
|
+
this._sendMessage({ data, type });
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
get(fn, prop) {
|
|
565
|
+
return (data) => {
|
|
566
|
+
return fn(prop, data);
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
);
|
|
569
571
|
this.canRedo = () => {
|
|
570
572
|
return !!this._crdtManager.doc.canRedo();
|
|
571
573
|
};
|
|
572
574
|
this.canUndo = () => {
|
|
573
575
|
return !!this._crdtManager.doc.canUndo();
|
|
574
576
|
};
|
|
575
|
-
this.event = (
|
|
576
|
-
|
|
577
|
-
|
|
577
|
+
this.event = new Proxy(
|
|
578
|
+
(event, callback) => this._eventNotifier.subscribe(event, callback),
|
|
579
|
+
{
|
|
580
|
+
get(fn, prop) {
|
|
581
|
+
return (callback) => fn(prop, callback);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
);
|
|
578
585
|
this.getMyPresence = () => {
|
|
579
586
|
return this._usersManager.myPresence;
|
|
580
587
|
};
|
|
@@ -627,10 +634,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
627
634
|
const myself = (_a = this._usersManager.myself) != null ? _a : null;
|
|
628
635
|
this._stateNotifier.subjects["my-presence"].next(myPresence);
|
|
629
636
|
!!myself && this._stateNotifier.subjects["myself"].next(myself);
|
|
630
|
-
this.broadcast(
|
|
631
|
-
"$UPDATE_PRESENCE",
|
|
632
|
-
{ presence }
|
|
633
|
-
);
|
|
637
|
+
this.broadcast("$UPDATE_PRESENCE", { presence });
|
|
634
638
|
};
|
|
635
639
|
this._flattenStorageStore = debounce(
|
|
636
640
|
() => __async(this, null, function* () {
|
|
@@ -658,10 +662,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
658
662
|
this._listeners = {
|
|
659
663
|
onAuthorizationFail: (error) => {
|
|
660
664
|
this._clearTimeout(this._timeouts.reconnect);
|
|
661
|
-
this._timeouts.reconnect = setTimeout(
|
|
662
|
-
this._reconnect.bind(this),
|
|
663
|
-
RECONNECT_TIMEOUT_MS
|
|
664
|
-
);
|
|
665
|
+
this._timeouts.reconnect = setTimeout(this._reconnect.bind(this), RECONNECT_TIMEOUT_MS);
|
|
665
666
|
onAuthorizationFail == null ? void 0 : onAuthorizationFail(error);
|
|
666
667
|
}
|
|
667
668
|
};
|
|
@@ -679,23 +680,14 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
679
680
|
get webSocket() {
|
|
680
681
|
return this._state.webSocket;
|
|
681
682
|
}
|
|
682
|
-
broadcast(event, data) {
|
|
683
|
-
if (!this._state.webSocket)
|
|
684
|
-
return;
|
|
685
|
-
if (this._state.connection.state !== "Open" /* Open */)
|
|
686
|
-
return;
|
|
687
|
-
const type = event.toString();
|
|
688
|
-
this._sendMessage({ data, type });
|
|
689
|
-
}
|
|
690
683
|
connect() {
|
|
691
684
|
return __async(this, null, function* () {
|
|
692
685
|
if (!this._endpoints.wsEndpoint) {
|
|
693
686
|
throw new Error("Must provide an wsEndpoint.");
|
|
694
687
|
}
|
|
695
|
-
const canConnect = [
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
].some((state) => this._state.connection.state === state);
|
|
688
|
+
const canConnect = ["Closed" /* Closed */, "Untouched" /* Untouched */].some(
|
|
689
|
+
(state) => this._state.connection.state === state
|
|
690
|
+
);
|
|
699
691
|
if (!canConnect)
|
|
700
692
|
return;
|
|
701
693
|
this._clearTimeout(this._timeouts.reconnect);
|
|
@@ -733,10 +725,9 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
733
725
|
}
|
|
734
726
|
if (!this._state.webSocket)
|
|
735
727
|
return;
|
|
736
|
-
const canDisconnect = [
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
].some((state) => this._state.connection.state === state);
|
|
728
|
+
const canDisconnect = ["Connecting" /* Connecting */, "Open" /* Open */].some(
|
|
729
|
+
(state) => this._state.connection.state === state
|
|
730
|
+
);
|
|
740
731
|
if (!canDisconnect)
|
|
741
732
|
return;
|
|
742
733
|
this._clearInterval(this._intervals.heartbeat);
|
|
@@ -747,9 +738,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
747
738
|
});
|
|
748
739
|
}
|
|
749
740
|
getConnection() {
|
|
750
|
-
return Object.freeze(
|
|
751
|
-
JSON.parse(JSON.stringify(this._state.connection))
|
|
752
|
-
);
|
|
741
|
+
return Object.freeze(JSON.parse(JSON.stringify(this._state.connection)));
|
|
753
742
|
}
|
|
754
743
|
getDoc() {
|
|
755
744
|
return this._crdtManager.doc;
|
|
@@ -783,14 +772,8 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
783
772
|
onNavigatorOnline: this._onNavigatorOnline.bind(this),
|
|
784
773
|
onVisibilityChange: this._onVisibilityChange.bind(this)
|
|
785
774
|
};
|
|
786
|
-
window.addEventListener(
|
|
787
|
-
|
|
788
|
-
this._windowListeners.onNavigatorOnline
|
|
789
|
-
);
|
|
790
|
-
document.addEventListener(
|
|
791
|
-
"visibilitychange",
|
|
792
|
-
this._windowListeners.onVisibilityChange
|
|
793
|
-
);
|
|
775
|
+
window.addEventListener("online", this._windowListeners.onNavigatorOnline);
|
|
776
|
+
document.addEventListener("visibilitychange", this._windowListeners.onVisibilityChange);
|
|
794
777
|
}
|
|
795
778
|
_attachWsListeners() {
|
|
796
779
|
if (!this._state.webSocket)
|
|
@@ -801,22 +784,10 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
801
784
|
onMessage: this._onMessage.bind(this),
|
|
802
785
|
onOpen: this._onOpen.bind(this)
|
|
803
786
|
};
|
|
804
|
-
this._state.webSocket.addEventListener(
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
);
|
|
808
|
-
this._state.webSocket.addEventListener(
|
|
809
|
-
"error",
|
|
810
|
-
this._wsListeners.onError
|
|
811
|
-
);
|
|
812
|
-
this._state.webSocket.addEventListener(
|
|
813
|
-
"message",
|
|
814
|
-
this._wsListeners.onMessage
|
|
815
|
-
);
|
|
816
|
-
this._state.webSocket.addEventListener(
|
|
817
|
-
"open",
|
|
818
|
-
this._wsListeners.onOpen
|
|
819
|
-
);
|
|
787
|
+
this._state.webSocket.addEventListener("close", this._wsListeners.onClose);
|
|
788
|
+
this._state.webSocket.addEventListener("error", this._wsListeners.onError);
|
|
789
|
+
this._state.webSocket.addEventListener("message", this._wsListeners.onMessage);
|
|
790
|
+
this._state.webSocket.addEventListener("open", this._wsListeners.onOpen);
|
|
820
791
|
}
|
|
821
792
|
_clearInterval(interval) {
|
|
822
793
|
if (Number.isNaN(interval))
|
|
@@ -854,35 +825,17 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
854
825
|
return;
|
|
855
826
|
if (typeof document === "undefined")
|
|
856
827
|
return;
|
|
857
|
-
window.removeEventListener(
|
|
858
|
-
|
|
859
|
-
this._windowListeners.onNavigatorOnline
|
|
860
|
-
);
|
|
861
|
-
document.removeEventListener(
|
|
862
|
-
"visibilitychange",
|
|
863
|
-
this._windowListeners.onVisibilityChange
|
|
864
|
-
);
|
|
828
|
+
window.removeEventListener("online", this._windowListeners.onNavigatorOnline);
|
|
829
|
+
document.removeEventListener("visibilitychange", this._windowListeners.onVisibilityChange);
|
|
865
830
|
this._windowListeners = null;
|
|
866
831
|
}
|
|
867
832
|
_detachWsListeners() {
|
|
868
833
|
if (!this._state.webSocket || !this._wsListeners)
|
|
869
834
|
return;
|
|
870
|
-
this._state.webSocket.removeEventListener(
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
);
|
|
874
|
-
this._state.webSocket.removeEventListener(
|
|
875
|
-
"error",
|
|
876
|
-
this._wsListeners.onError
|
|
877
|
-
);
|
|
878
|
-
this._state.webSocket.removeEventListener(
|
|
879
|
-
"message",
|
|
880
|
-
this._wsListeners.onMessage
|
|
881
|
-
);
|
|
882
|
-
this._state.webSocket.removeEventListener(
|
|
883
|
-
"open",
|
|
884
|
-
this._wsListeners.onOpen
|
|
885
|
-
);
|
|
835
|
+
this._state.webSocket.removeEventListener("close", this._wsListeners.onClose);
|
|
836
|
+
this._state.webSocket.removeEventListener("error", this._wsListeners.onError);
|
|
837
|
+
this._state.webSocket.removeEventListener("message", this._wsListeners.onMessage);
|
|
838
|
+
this._state.webSocket.removeEventListener("open", this._wsListeners.onOpen);
|
|
886
839
|
this._wsListeners = null;
|
|
887
840
|
}
|
|
888
841
|
_emitSharedTypes() {
|
|
@@ -928,9 +881,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
928
881
|
try {
|
|
929
882
|
return yield res.text().then((text) => text.trim());
|
|
930
883
|
} catch (err) {
|
|
931
|
-
throw new Error(
|
|
932
|
-
err instanceof Error ? err.message : "Room is unauthorized"
|
|
933
|
-
);
|
|
884
|
+
throw new Error(err instanceof Error ? err.message : "Room is unauthorized");
|
|
934
885
|
}
|
|
935
886
|
});
|
|
936
887
|
}
|
|
@@ -964,10 +915,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
964
915
|
if (!this._state.webSocket)
|
|
965
916
|
throw new Error("Could not find WebSocket");
|
|
966
917
|
const data = message.data;
|
|
967
|
-
this._usersManager.patchPresence(
|
|
968
|
-
connectionId,
|
|
969
|
-
data.presence
|
|
970
|
-
);
|
|
918
|
+
this._usersManager.patchPresence(connectionId, data.presence);
|
|
971
919
|
const myPresence = this._usersManager.myPresence;
|
|
972
920
|
const myself = (_a = this._usersManager.myself) != null ? _a : null;
|
|
973
921
|
if ((myself == null ? void 0 : myself.connectionId) === connectionId) {
|
|
@@ -992,10 +940,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
992
940
|
return;
|
|
993
941
|
this._usersManager.setUser(connectionId, user);
|
|
994
942
|
const other = this._usersManager.getOther(connectionId);
|
|
995
|
-
!!presence && this._usersManager.patchPresence(
|
|
996
|
-
connectionId,
|
|
997
|
-
presence
|
|
998
|
-
);
|
|
943
|
+
!!presence && this._usersManager.patchPresence(connectionId, presence);
|
|
999
944
|
this._otherNotifier.subject(connectionId).next(other);
|
|
1000
945
|
});
|
|
1001
946
|
const others = this._usersManager.getOthers();
|
|
@@ -1014,10 +959,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1014
959
|
oldState.authorization.user = user;
|
|
1015
960
|
return oldState;
|
|
1016
961
|
});
|
|
1017
|
-
this._usersManager.setMyself(
|
|
1018
|
-
connectionId,
|
|
1019
|
-
user
|
|
1020
|
-
);
|
|
962
|
+
this._usersManager.setMyself(connectionId, user);
|
|
1021
963
|
const presence = this._usersManager.myPresence;
|
|
1022
964
|
const myself = (_a = this._usersManager.myself) != null ? _a : null;
|
|
1023
965
|
this._stateNotifier.subjects["my-presence"].next(presence);
|
|
@@ -1095,11 +1037,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1095
1037
|
if (myself.connectionId === connectionId) {
|
|
1096
1038
|
this._sendMessage({ type: "$GET_OTHERS", data: {} });
|
|
1097
1039
|
}
|
|
1098
|
-
this._usersManager.setUser(
|
|
1099
|
-
connectionId,
|
|
1100
|
-
data.user,
|
|
1101
|
-
data.presence
|
|
1102
|
-
);
|
|
1040
|
+
this._usersManager.setUser(connectionId, data.user, data.presence);
|
|
1103
1041
|
const other = this._usersManager.getOther(connectionId);
|
|
1104
1042
|
const others = this._usersManager.getOthers();
|
|
1105
1043
|
this._otherNotifier.subject(connectionId).next(other);
|
|
@@ -1107,10 +1045,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1107
1045
|
}
|
|
1108
1046
|
_heartbeat() {
|
|
1109
1047
|
this._clearTimeout(this._timeouts.pong);
|
|
1110
|
-
this._timeouts.pong = setTimeout(
|
|
1111
|
-
this._reconnect.bind(this),
|
|
1112
|
-
PONG_TIMEOUT_MS
|
|
1113
|
-
);
|
|
1048
|
+
this._timeouts.pong = setTimeout(this._reconnect.bind(this), PONG_TIMEOUT_MS);
|
|
1114
1049
|
this._sendMessage({ type: "$PING", data: {} });
|
|
1115
1050
|
}
|
|
1116
1051
|
_logDebug(...data) {
|
|
@@ -1240,10 +1175,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1240
1175
|
return oldState;
|
|
1241
1176
|
});
|
|
1242
1177
|
this._clearInterval(this._intervals.heartbeat);
|
|
1243
|
-
this._intervals.heartbeat = setInterval(
|
|
1244
|
-
this._heartbeat.bind(this),
|
|
1245
|
-
HEARTBEAT_INTERVAL_MS
|
|
1246
|
-
);
|
|
1178
|
+
this._intervals.heartbeat = setInterval(this._heartbeat.bind(this), HEARTBEAT_INTERVAL_MS);
|
|
1247
1179
|
}
|
|
1248
1180
|
_onNavigatorOnline() {
|
|
1249
1181
|
return __async(this, null, function* () {
|
|
@@ -1317,9 +1249,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1317
1249
|
_updateState(updater) {
|
|
1318
1250
|
let authorization;
|
|
1319
1251
|
try {
|
|
1320
|
-
authorization = JSON.parse(
|
|
1321
|
-
JSON.stringify(this._state.authorization)
|
|
1322
|
-
);
|
|
1252
|
+
authorization = JSON.parse(JSON.stringify(this._state.authorization));
|
|
1323
1253
|
} catch (e) {
|
|
1324
1254
|
throw new Error("User is not JSON serializable");
|
|
1325
1255
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "@pluv/io frontend client",
|
|
5
5
|
"author": "leedavidcs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,15 +18,15 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"wonka": "^6.3.4",
|
|
21
|
-
"@pluv/crdt": "^0.
|
|
22
|
-
"@pluv/types": "^0.
|
|
21
|
+
"@pluv/crdt": "^0.18.0",
|
|
22
|
+
"@pluv/types": "^0.18.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"eslint": "^8.57.0",
|
|
26
26
|
"tsup": "^8.0.2",
|
|
27
27
|
"typescript": "^5.4.5",
|
|
28
|
-
"@pluv/tsconfig": "^0.
|
|
29
|
-
"eslint-config-pluv": "^0.
|
|
28
|
+
"@pluv/tsconfig": "^0.18.0",
|
|
29
|
+
"eslint-config-pluv": "^0.18.0"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|
package/src/AbstractRoom.ts
CHANGED
|
@@ -1,21 +1,8 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
AbstractCrdtType,
|
|
4
|
-
InferCrdtStorageJson,
|
|
5
|
-
} from "@pluv/crdt";
|
|
6
|
-
import type {
|
|
7
|
-
IOLike,
|
|
8
|
-
Id,
|
|
9
|
-
InferIOInput,
|
|
10
|
-
InferIOOutput,
|
|
11
|
-
JsonObject,
|
|
12
|
-
} from "@pluv/types";
|
|
1
|
+
import type { AbstractCrdtDoc, AbstractCrdtType, InferCrdtStorageJson } from "@pluv/crdt";
|
|
2
|
+
import type { IOLike, Id, InferIOInput, InferIOOutput, JsonObject } from "@pluv/types";
|
|
13
3
|
import type { EventNotifierSubscriptionCallback } from "./EventNotifier";
|
|
14
4
|
import type { OtherNotifierSubscriptionCallback } from "./OtherNotifier";
|
|
15
|
-
import type {
|
|
16
|
-
StateNotifierSubjects,
|
|
17
|
-
SubscriptionCallback,
|
|
18
|
-
} from "./StateNotifier";
|
|
5
|
+
import type { StateNotifierSubjects, SubscriptionCallback } from "./StateNotifier";
|
|
19
6
|
import type { UserInfo, WebSocketConnection } from "./types";
|
|
20
7
|
|
|
21
8
|
export abstract class AbstractRoom<
|
|
@@ -53,20 +40,13 @@ export abstract class AbstractRoom<
|
|
|
53
40
|
|
|
54
41
|
public abstract getMyself(): Id<UserInfo<TIO, TPresence>> | null;
|
|
55
42
|
|
|
56
|
-
public abstract getOther(
|
|
57
|
-
connectionId: string,
|
|
58
|
-
): Id<UserInfo<TIO, TPresence>> | null;
|
|
43
|
+
public abstract getOther(connectionId: string): Id<UserInfo<TIO, TPresence>> | null;
|
|
59
44
|
|
|
60
45
|
public abstract getOthers(): readonly Id<UserInfo<TIO, TPresence>>[];
|
|
61
46
|
|
|
62
|
-
public abstract getStorage<TKey extends keyof TStorage>(
|
|
63
|
-
key: TKey,
|
|
64
|
-
): TStorage[TKey] | null;
|
|
47
|
+
public abstract getStorage<TKey extends keyof TStorage>(key: TKey): TStorage[TKey] | null;
|
|
65
48
|
|
|
66
|
-
public abstract other(
|
|
67
|
-
connectionId: string,
|
|
68
|
-
callback: OtherNotifierSubscriptionCallback<TIO>,
|
|
69
|
-
): () => void;
|
|
49
|
+
public abstract other(connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO>): () => void;
|
|
70
50
|
|
|
71
51
|
public abstract redo(): void;
|
|
72
52
|
|
|
@@ -81,17 +61,12 @@ export abstract class AbstractRoom<
|
|
|
81
61
|
}) => void,
|
|
82
62
|
): () => void;
|
|
83
63
|
|
|
84
|
-
public abstract subscribe<
|
|
85
|
-
TSubject extends keyof StateNotifierSubjects<TIO, TPresence>,
|
|
86
|
-
>(
|
|
64
|
+
public abstract subscribe<TSubject extends keyof StateNotifierSubjects<TIO, TPresence>>(
|
|
87
65
|
name: TSubject,
|
|
88
66
|
callback: SubscriptionCallback<TIO, TPresence, TSubject>,
|
|
89
67
|
): () => void;
|
|
90
68
|
|
|
91
|
-
public abstract transact(
|
|
92
|
-
fn: (storage: TStorage) => void,
|
|
93
|
-
origin?: string,
|
|
94
|
-
): void;
|
|
69
|
+
public abstract transact(fn: (storage: TStorage) => void, origin?: string): void;
|
|
95
70
|
|
|
96
71
|
public abstract undo(): void;
|
|
97
72
|
|
package/src/CrdtManager.ts
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AbstractCrdtDoc,
|
|
3
|
-
AbstractCrdtDocFactory,
|
|
4
|
-
AbstractCrdtType,
|
|
5
|
-
} from "@pluv/crdt";
|
|
1
|
+
import type { AbstractCrdtDoc, AbstractCrdtDocFactory, AbstractCrdtType } from "@pluv/crdt";
|
|
6
2
|
import { noop } from "@pluv/crdt";
|
|
7
3
|
|
|
8
|
-
export type CrdtManagerOptions<
|
|
9
|
-
TStorage extends Record<string, AbstractCrdtType<any, any>> = {},
|
|
10
|
-
> = {
|
|
4
|
+
export type CrdtManagerOptions<TStorage extends Record<string, AbstractCrdtType<any, any>> = {}> = {
|
|
11
5
|
encodedState?: string | Uint8Array | null;
|
|
12
6
|
initialStorage?: AbstractCrdtDocFactory<TStorage>;
|
|
13
7
|
};
|
|
@@ -18,26 +12,19 @@ type CrdtManagerInitializeParams = {
|
|
|
18
12
|
update: string | readonly string[];
|
|
19
13
|
};
|
|
20
14
|
|
|
21
|
-
export class CrdtManager<
|
|
22
|
-
TStorage extends Record<string, AbstractCrdtType<any, any>>,
|
|
23
|
-
> {
|
|
15
|
+
export class CrdtManager<TStorage extends Record<string, AbstractCrdtType<any, any>>> {
|
|
24
16
|
public doc: AbstractCrdtDoc<TStorage>;
|
|
25
17
|
public initialized: boolean = false;
|
|
26
18
|
|
|
27
19
|
private readonly _docFactory: AbstractCrdtDocFactory<TStorage>;
|
|
28
20
|
|
|
29
21
|
constructor(options: CrdtManagerOptions<TStorage>) {
|
|
30
|
-
const {
|
|
31
|
-
encodedState,
|
|
32
|
-
initialStorage = noop.doc({}) as AbstractCrdtDocFactory<TStorage>,
|
|
33
|
-
} = options;
|
|
22
|
+
const { encodedState, initialStorage = noop.doc({}) as AbstractCrdtDocFactory<TStorage> } = options;
|
|
34
23
|
|
|
35
24
|
this._docFactory = initialStorage;
|
|
36
25
|
|
|
37
26
|
this.doc = encodedState
|
|
38
|
-
? initialStorage
|
|
39
|
-
.getFresh()
|
|
40
|
-
.applyEncodedState({ update: encodedState })
|
|
27
|
+
? initialStorage.getFresh().applyEncodedState({ update: encodedState })
|
|
41
28
|
: initialStorage.getFresh();
|
|
42
29
|
}
|
|
43
30
|
|
|
@@ -50,8 +37,7 @@ export class CrdtManager<
|
|
|
50
37
|
public applyUpdate(update: string | readonly string[], origin?: any): this {
|
|
51
38
|
if (!this.initialized) return this;
|
|
52
39
|
|
|
53
|
-
const updates: readonly string[] =
|
|
54
|
-
typeof update === "string" ? [update] : update;
|
|
40
|
+
const updates: readonly string[] = typeof update === "string" ? [update] : update;
|
|
55
41
|
|
|
56
42
|
this._applyDocUpdates(this.doc, updates, origin);
|
|
57
43
|
|
|
@@ -79,20 +65,12 @@ export class CrdtManager<
|
|
|
79
65
|
return this;
|
|
80
66
|
}
|
|
81
67
|
|
|
82
|
-
const onEmpty = this._applyDocUpdates(
|
|
83
|
-
this._docFactory.getEmpty(),
|
|
84
|
-
updates,
|
|
85
|
-
origin,
|
|
86
|
-
);
|
|
68
|
+
const onEmpty = this._applyDocUpdates(this._docFactory.getEmpty(), updates, origin);
|
|
87
69
|
|
|
88
70
|
if (!onEmpty.isEmpty()) {
|
|
89
71
|
onEmpty.destroy();
|
|
90
72
|
|
|
91
|
-
this.doc = this._applyDocUpdates(
|
|
92
|
-
this._docFactory.getFresh(),
|
|
93
|
-
updates,
|
|
94
|
-
origin,
|
|
95
|
-
).track();
|
|
73
|
+
this.doc = this._applyDocUpdates(this._docFactory.getFresh(), updates, origin).track();
|
|
96
74
|
this.initialized = true;
|
|
97
75
|
|
|
98
76
|
onInitialized?.(this.doc.getEncodedState());
|
|
@@ -115,9 +93,7 @@ export class CrdtManager<
|
|
|
115
93
|
origin?: string,
|
|
116
94
|
): AbstractCrdtDoc<TStorage> {
|
|
117
95
|
doc.transact(() => {
|
|
118
|
-
doc.batchApplyEncodedState(
|
|
119
|
-
updates.map((update) => ({ origin, update })),
|
|
120
|
-
);
|
|
96
|
+
doc.batchApplyEncodedState(updates.map((update) => ({ origin, update })));
|
|
121
97
|
}, origin);
|
|
122
98
|
|
|
123
99
|
return doc;
|
package/src/CrdtNotifier.ts
CHANGED
|
@@ -1,21 +1,15 @@
|
|
|
1
1
|
import type { AbstractCrdtType, InferCrdtStorageJson } from "@pluv/crdt";
|
|
2
|
-
import {
|
|
2
|
+
import type { Subject } from "wonka";
|
|
3
|
+
import { makeSubject, subscribe } from "wonka";
|
|
3
4
|
|
|
4
|
-
export class CrdtNotifier<
|
|
5
|
-
TStorage extends Record<string, AbstractCrdtType<any, any>>,
|
|
6
|
-
> {
|
|
5
|
+
export class CrdtNotifier<TStorage extends Record<string, AbstractCrdtType<any, any>>> {
|
|
7
6
|
public rootSubject = makeSubject<{
|
|
8
7
|
[P in keyof TStorage]: InferCrdtStorageJson<TStorage[P]>;
|
|
9
8
|
}>();
|
|
10
9
|
|
|
11
|
-
public subjects = new Map<
|
|
12
|
-
keyof TStorage,
|
|
13
|
-
Subject<InferCrdtStorageJson<TStorage[keyof TStorage]>> | null
|
|
14
|
-
>();
|
|
10
|
+
public subjects = new Map<keyof TStorage, Subject<InferCrdtStorageJson<TStorage[keyof TStorage]>> | null>();
|
|
15
11
|
|
|
16
|
-
public subject<TKey extends keyof TStorage>(
|
|
17
|
-
key: TKey,
|
|
18
|
-
): Subject<InferCrdtStorageJson<TStorage[TKey]>> {
|
|
12
|
+
public subject<TKey extends keyof TStorage>(key: TKey): Subject<InferCrdtStorageJson<TStorage[TKey]>> {
|
|
19
13
|
const subject = this.subjects.get(key);
|
|
20
14
|
|
|
21
15
|
if (subject) {
|
package/src/EventNotifier.ts
CHANGED
|
@@ -2,20 +2,14 @@ import type { Id, InferIOOutput, IOEventMessage, IOLike } from "@pluv/types";
|
|
|
2
2
|
import type { Subject } from "wonka";
|
|
3
3
|
import { makeSubject, subscribe } from "wonka";
|
|
4
4
|
|
|
5
|
-
export type EventNotifierSubscriptionCallback<
|
|
6
|
-
TIO
|
|
7
|
-
|
|
8
|
-
> = (value: Id<IOEventMessage<TIO, TEvent>>) => void;
|
|
5
|
+
export type EventNotifierSubscriptionCallback<TIO extends IOLike, TEvent extends keyof InferIOOutput<TIO>> = (
|
|
6
|
+
value: Id<IOEventMessage<TIO, TEvent>>,
|
|
7
|
+
) => void;
|
|
9
8
|
|
|
10
9
|
export class EventNotifier<TIO extends IOLike> {
|
|
11
|
-
public subjects = new Map<
|
|
12
|
-
keyof InferIOOutput<TIO>,
|
|
13
|
-
Subject<Id<IOEventMessage<TIO, keyof InferIOOutput<TIO>>>>
|
|
14
|
-
>();
|
|
10
|
+
public subjects = new Map<keyof InferIOOutput<TIO>, Subject<Id<IOEventMessage<TIO, keyof InferIOOutput<TIO>>>>>();
|
|
15
11
|
|
|
16
|
-
public subject<TEvent extends keyof InferIOOutput<TIO>>(
|
|
17
|
-
name: TEvent,
|
|
18
|
-
): Subject<Id<IOEventMessage<TIO, TEvent>>> {
|
|
12
|
+
public subject<TEvent extends keyof InferIOOutput<TIO>>(name: TEvent): Subject<Id<IOEventMessage<TIO, TEvent>>> {
|
|
19
13
|
const subject = this.subjects.get(name);
|
|
20
14
|
|
|
21
15
|
if (subject) return subject;
|