@pluv/client 1.0.1 → 1.0.2
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 +8 -0
- package/dist/index.d.mts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +63 -59
- package/dist/index.mjs +63 -59
- package/package.json +5 -5
- package/src/CrdtManager.ts +17 -7
- package/src/PluvRoom.ts +39 -42
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @pluv/client@1.0.
|
|
2
|
+
> @pluv/client@1.0.2 build /home/runner/work/pluv/pluv/packages/client
|
|
3
3
|
> tsup src/index.ts --format esm,cjs --dts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
[34mCLI[39m Target: es6
|
|
9
9
|
[34mESM[39m Build start
|
|
10
10
|
[34mCJS[39m Build start
|
|
11
|
-
[
|
|
12
|
-
[
|
|
13
|
-
[
|
|
14
|
-
[
|
|
11
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m57.31 KB[39m
|
|
12
|
+
[32mESM[39m ⚡️ Build success in 126ms
|
|
13
|
+
[32mCJS[39m [1mdist/index.js [22m[32m58.63 KB[39m
|
|
14
|
+
[32mCJS[39m ⚡️ Build success in 126ms
|
|
15
15
|
[34mDTS[39m Build start
|
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
|
17
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[32m25.
|
|
18
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m25.
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 3638ms
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m25.31 KB[39m
|
|
18
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m25.31 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @pluv/client
|
|
2
2
|
|
|
3
|
+
## 1.0.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d87159c: Restored `@pluv/addon-indexeddb` functionality, and fixed `@pluv/addon-indexeddb` sometimes duplicating storage operations based on `initialStorage` values.
|
|
8
|
+
- @pluv/crdt@1.0.2
|
|
9
|
+
- @pluv/types@1.0.2
|
|
10
|
+
|
|
3
11
|
## 1.0.1
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -188,7 +188,6 @@ declare class PluvRoom<TIO extends IOLike<any, any>, TMetadata extends JsonObjec
|
|
|
188
188
|
undo: () => void;
|
|
189
189
|
updateMyPresence: (presence: UpdateMyPresenceAction<TPresence>) => void;
|
|
190
190
|
private _addToStorageStore;
|
|
191
|
-
private _applyStorageStore;
|
|
192
191
|
private _attachWindowListeners;
|
|
193
192
|
private _attachWsListeners;
|
|
194
193
|
private _clearInterval;
|
package/dist/index.d.ts
CHANGED
|
@@ -188,7 +188,6 @@ declare class PluvRoom<TIO extends IOLike<any, any>, TMetadata extends JsonObjec
|
|
|
188
188
|
undo: () => void;
|
|
189
189
|
updateMyPresence: (presence: UpdateMyPresenceAction<TPresence>) => void;
|
|
190
190
|
private _addToStorageStore;
|
|
191
|
-
private _applyStorageStore;
|
|
192
191
|
private _attachWindowListeners;
|
|
193
192
|
private _attachWsListeners;
|
|
194
193
|
private _clearInterval;
|
package/dist/index.js
CHANGED
|
@@ -136,14 +136,17 @@ var CrdtManager = class {
|
|
|
136
136
|
* update. This unfortunately means updates can be dropped entirely
|
|
137
137
|
* @date June 13, 2023
|
|
138
138
|
*/
|
|
139
|
-
applyUpdate(
|
|
139
|
+
applyUpdate(params) {
|
|
140
|
+
const { origin, update } = params;
|
|
140
141
|
if (!this.initialized) return this;
|
|
141
142
|
const updates = typeof update === "string" ? [update] : update;
|
|
142
143
|
this._applyDocUpdates(this.doc, updates, origin);
|
|
143
144
|
return this;
|
|
144
145
|
}
|
|
145
146
|
destroy() {
|
|
147
|
+
this.initialized = false;
|
|
146
148
|
this.doc.destroy();
|
|
149
|
+
this.doc = this._docFactory.getEmpty();
|
|
147
150
|
}
|
|
148
151
|
get(key) {
|
|
149
152
|
return this.doc.get(key);
|
|
@@ -152,7 +155,7 @@ var CrdtManager = class {
|
|
|
152
155
|
return this._docFactory.getInitialized().getEncodedState();
|
|
153
156
|
}
|
|
154
157
|
initialize(params) {
|
|
155
|
-
const {
|
|
158
|
+
const { origin, update } = params;
|
|
156
159
|
if (this.initialized) {
|
|
157
160
|
console.warn("Attempted to initialize storage multiple times");
|
|
158
161
|
return this;
|
|
@@ -172,9 +175,11 @@ var CrdtManager = class {
|
|
|
172
175
|
).rebuildStorage(reference);
|
|
173
176
|
this.initialized = true;
|
|
174
177
|
initialized.destroy();
|
|
175
|
-
onInitialized == null ? void 0 : onInitialized(this.doc.getEncodedState());
|
|
176
178
|
return this;
|
|
177
179
|
}
|
|
180
|
+
resolveEncodedState(updates) {
|
|
181
|
+
return this._docFactory.resolveEncodedState(updates);
|
|
182
|
+
}
|
|
178
183
|
_applyDocUpdates(doc, updates, origin) {
|
|
179
184
|
doc.transact(() => {
|
|
180
185
|
doc.batchApplyEncodedState({ origin, updates });
|
|
@@ -734,7 +739,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
734
739
|
const shouldFlatten = yield this._storageStore.getShouldFlatten();
|
|
735
740
|
if (!shouldFlatten) return;
|
|
736
741
|
const updates = yield this._storageStore.getUpdates();
|
|
737
|
-
this._crdtManager.applyUpdate(updates, this);
|
|
742
|
+
this._crdtManager.applyUpdate({ update: updates, origin: this });
|
|
738
743
|
const encodedState = this._crdtManager.doc.getEncodedState();
|
|
739
744
|
yield this._storageStore.flatten(encodedState);
|
|
740
745
|
}),
|
|
@@ -791,6 +796,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
791
796
|
oldState.connection.state = ConnectionState.Connecting;
|
|
792
797
|
return oldState;
|
|
793
798
|
});
|
|
799
|
+
yield this._storageStore.initialize();
|
|
794
800
|
const wsEndpoint = this._getWsEndpoint(this.id, params);
|
|
795
801
|
const url = new URL(wsEndpoint);
|
|
796
802
|
let authToken = null;
|
|
@@ -855,20 +861,6 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
855
861
|
this._flattenStorageStore();
|
|
856
862
|
});
|
|
857
863
|
}
|
|
858
|
-
_applyStorageStore() {
|
|
859
|
-
return __async(this, null, function* () {
|
|
860
|
-
const updates = yield this._storageStore.getUpdates();
|
|
861
|
-
this._crdtManager.initialize({
|
|
862
|
-
onInitialized: () => {
|
|
863
|
-
this._stateNotifier.subjects["storage-loaded"].next(true);
|
|
864
|
-
this._observeCrdt();
|
|
865
|
-
},
|
|
866
|
-
origin: ORIGIN_INITIALIZED,
|
|
867
|
-
update: updates
|
|
868
|
-
});
|
|
869
|
-
this._emitSharedTypes();
|
|
870
|
-
});
|
|
871
|
-
}
|
|
872
864
|
_attachWindowListeners() {
|
|
873
865
|
if (typeof window === "undefined") return;
|
|
874
866
|
if (typeof document === "undefined") return;
|
|
@@ -1059,33 +1051,35 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1059
1051
|
this._stateNotifier.subjects.others.next(others);
|
|
1060
1052
|
}
|
|
1061
1053
|
_handleRegisteredMessage(message) {
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
oldState
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1054
|
+
return __async(this, null, function* () {
|
|
1055
|
+
var _a, _b, _c;
|
|
1056
|
+
const { connectionId } = message;
|
|
1057
|
+
const user = message.user;
|
|
1058
|
+
if (!connectionId) return;
|
|
1059
|
+
if (!this._state.webSocket) throw new Error("Could not find WebSocket");
|
|
1060
|
+
const data = message.data;
|
|
1061
|
+
const state = data.state;
|
|
1062
|
+
this._updateState((oldState) => {
|
|
1063
|
+
oldState.connection.count += 1;
|
|
1064
|
+
oldState.connection.id = connectionId;
|
|
1065
|
+
oldState.authorization.user = user != null ? user : null;
|
|
1066
|
+
return oldState;
|
|
1067
|
+
});
|
|
1068
|
+
const userInfo = {
|
|
1069
|
+
connectionId,
|
|
1070
|
+
presence: (_a = data.presence) != null ? _a : void 0,
|
|
1071
|
+
user
|
|
1072
|
+
};
|
|
1073
|
+
this._usersManager.setMyself(userInfo);
|
|
1074
|
+
const presence = this._usersManager.myPresence;
|
|
1075
|
+
const myself = (_b = this._usersManager.myself) != null ? _b : null;
|
|
1076
|
+
this._stateNotifier.subjects["my-presence"].next(presence);
|
|
1077
|
+
this._stateNotifier.subjects.myself.next(myself);
|
|
1078
|
+
const update = !state ? (_c = this._crdtManager.resolveEncodedState(yield this._storageStore.getUpdates())) != null ? _c : this._crdtManager.getInitialState() : this._crdtManager.getInitialState();
|
|
1079
|
+
this._sendMessage({
|
|
1080
|
+
type: "$initializeSession",
|
|
1081
|
+
data: { presence, update }
|
|
1082
|
+
});
|
|
1089
1083
|
});
|
|
1090
1084
|
}
|
|
1091
1085
|
_handleStorageReceivedMessage(message) {
|
|
@@ -1094,24 +1088,34 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1094
1088
|
if (!connectionId) return;
|
|
1095
1089
|
if (!this._state.webSocket) throw new Error("Could not find WebSocket");
|
|
1096
1090
|
const data = message.data;
|
|
1091
|
+
const changeKind = data.changeKind;
|
|
1097
1092
|
const state = data.state;
|
|
1098
|
-
this.
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
origin:
|
|
1106
|
-
|
|
1107
|
-
|
|
1093
|
+
const updates = yield this._storageStore.getUpdates();
|
|
1094
|
+
const origin = ORIGIN_INITIALIZED;
|
|
1095
|
+
const updateStorage = (update) => {
|
|
1096
|
+
return this._crdtManager.initialized ? this._crdtManager.applyUpdate({ update, origin }) : this._crdtManager.initialize({ update, origin });
|
|
1097
|
+
};
|
|
1098
|
+
if (changeKind === "empty") {
|
|
1099
|
+
this._crdtManager.destroy();
|
|
1100
|
+
this._crdtManager.initialize({ origin, update: updates });
|
|
1101
|
+
} else if (changeKind === "initialized") {
|
|
1102
|
+
if (!!updates.length) updateStorage(updates);
|
|
1103
|
+
else {
|
|
1104
|
+
const encodedState2 = updateStorage(state).doc.getEncodedState();
|
|
1105
|
+
this._addToStorageStore(encodedState2);
|
|
1106
|
+
}
|
|
1107
|
+
} else {
|
|
1108
|
+
const encodedState2 = updateStorage(state).doc.getEncodedState();
|
|
1109
|
+
if (!!updates.length) this._crdtManager.applyUpdate({ update: updates, origin });
|
|
1110
|
+
yield this._addToStorageStore(encodedState2);
|
|
1111
|
+
}
|
|
1108
1112
|
const encodedState = this._crdtManager.doc.getEncodedState();
|
|
1109
|
-
yield this._storageStore.addUpdate(encodedState);
|
|
1110
1113
|
this._emitSharedTypes();
|
|
1111
|
-
|
|
1114
|
+
this._observeCrdt();
|
|
1115
|
+
this._stateNotifier.subjects["storage-loaded"].next(true);
|
|
1112
1116
|
this._sendMessage({
|
|
1113
1117
|
type: "$updateStorage",
|
|
1114
|
-
data: { origin
|
|
1118
|
+
data: { origin, update: encodedState }
|
|
1115
1119
|
});
|
|
1116
1120
|
});
|
|
1117
1121
|
}
|
|
@@ -1190,11 +1194,11 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1190
1194
|
const unsubscribe = this._crdtManager.doc.subscribe((event) => {
|
|
1191
1195
|
var _a2;
|
|
1192
1196
|
const origin = (_a2 = event.origin) != null ? _a2 : null;
|
|
1193
|
-
this._addToStorageStore(event.update);
|
|
1194
1197
|
this._emitSharedTypes();
|
|
1195
1198
|
if (origin === ORIGIN_INITIALIZED || origin === ORIGIN_STORAGE_UPDATED) {
|
|
1196
1199
|
return;
|
|
1197
1200
|
}
|
|
1201
|
+
this._addToStorageStore(event.update);
|
|
1198
1202
|
if (!this._state.webSocket) return;
|
|
1199
1203
|
if (!this._state.connection.id) return;
|
|
1200
1204
|
if (this._state.webSocket.readyState !== WebSocket.OPEN) return;
|
package/dist/index.mjs
CHANGED
|
@@ -105,14 +105,17 @@ var CrdtManager = class {
|
|
|
105
105
|
* update. This unfortunately means updates can be dropped entirely
|
|
106
106
|
* @date June 13, 2023
|
|
107
107
|
*/
|
|
108
|
-
applyUpdate(
|
|
108
|
+
applyUpdate(params) {
|
|
109
|
+
const { origin, update } = params;
|
|
109
110
|
if (!this.initialized) return this;
|
|
110
111
|
const updates = typeof update === "string" ? [update] : update;
|
|
111
112
|
this._applyDocUpdates(this.doc, updates, origin);
|
|
112
113
|
return this;
|
|
113
114
|
}
|
|
114
115
|
destroy() {
|
|
116
|
+
this.initialized = false;
|
|
115
117
|
this.doc.destroy();
|
|
118
|
+
this.doc = this._docFactory.getEmpty();
|
|
116
119
|
}
|
|
117
120
|
get(key) {
|
|
118
121
|
return this.doc.get(key);
|
|
@@ -121,7 +124,7 @@ var CrdtManager = class {
|
|
|
121
124
|
return this._docFactory.getInitialized().getEncodedState();
|
|
122
125
|
}
|
|
123
126
|
initialize(params) {
|
|
124
|
-
const {
|
|
127
|
+
const { origin, update } = params;
|
|
125
128
|
if (this.initialized) {
|
|
126
129
|
console.warn("Attempted to initialize storage multiple times");
|
|
127
130
|
return this;
|
|
@@ -141,9 +144,11 @@ var CrdtManager = class {
|
|
|
141
144
|
).rebuildStorage(reference);
|
|
142
145
|
this.initialized = true;
|
|
143
146
|
initialized.destroy();
|
|
144
|
-
onInitialized == null ? void 0 : onInitialized(this.doc.getEncodedState());
|
|
145
147
|
return this;
|
|
146
148
|
}
|
|
149
|
+
resolveEncodedState(updates) {
|
|
150
|
+
return this._docFactory.resolveEncodedState(updates);
|
|
151
|
+
}
|
|
147
152
|
_applyDocUpdates(doc, updates, origin) {
|
|
148
153
|
doc.transact(() => {
|
|
149
154
|
doc.batchApplyEncodedState({ origin, updates });
|
|
@@ -703,7 +708,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
703
708
|
const shouldFlatten = yield this._storageStore.getShouldFlatten();
|
|
704
709
|
if (!shouldFlatten) return;
|
|
705
710
|
const updates = yield this._storageStore.getUpdates();
|
|
706
|
-
this._crdtManager.applyUpdate(updates, this);
|
|
711
|
+
this._crdtManager.applyUpdate({ update: updates, origin: this });
|
|
707
712
|
const encodedState = this._crdtManager.doc.getEncodedState();
|
|
708
713
|
yield this._storageStore.flatten(encodedState);
|
|
709
714
|
}),
|
|
@@ -760,6 +765,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
760
765
|
oldState.connection.state = ConnectionState.Connecting;
|
|
761
766
|
return oldState;
|
|
762
767
|
});
|
|
768
|
+
yield this._storageStore.initialize();
|
|
763
769
|
const wsEndpoint = this._getWsEndpoint(this.id, params);
|
|
764
770
|
const url = new URL(wsEndpoint);
|
|
765
771
|
let authToken = null;
|
|
@@ -824,20 +830,6 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
824
830
|
this._flattenStorageStore();
|
|
825
831
|
});
|
|
826
832
|
}
|
|
827
|
-
_applyStorageStore() {
|
|
828
|
-
return __async(this, null, function* () {
|
|
829
|
-
const updates = yield this._storageStore.getUpdates();
|
|
830
|
-
this._crdtManager.initialize({
|
|
831
|
-
onInitialized: () => {
|
|
832
|
-
this._stateNotifier.subjects["storage-loaded"].next(true);
|
|
833
|
-
this._observeCrdt();
|
|
834
|
-
},
|
|
835
|
-
origin: ORIGIN_INITIALIZED,
|
|
836
|
-
update: updates
|
|
837
|
-
});
|
|
838
|
-
this._emitSharedTypes();
|
|
839
|
-
});
|
|
840
|
-
}
|
|
841
833
|
_attachWindowListeners() {
|
|
842
834
|
if (typeof window === "undefined") return;
|
|
843
835
|
if (typeof document === "undefined") return;
|
|
@@ -1028,33 +1020,35 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1028
1020
|
this._stateNotifier.subjects.others.next(others);
|
|
1029
1021
|
}
|
|
1030
1022
|
_handleRegisteredMessage(message) {
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
oldState
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1023
|
+
return __async(this, null, function* () {
|
|
1024
|
+
var _a, _b, _c;
|
|
1025
|
+
const { connectionId } = message;
|
|
1026
|
+
const user = message.user;
|
|
1027
|
+
if (!connectionId) return;
|
|
1028
|
+
if (!this._state.webSocket) throw new Error("Could not find WebSocket");
|
|
1029
|
+
const data = message.data;
|
|
1030
|
+
const state = data.state;
|
|
1031
|
+
this._updateState((oldState) => {
|
|
1032
|
+
oldState.connection.count += 1;
|
|
1033
|
+
oldState.connection.id = connectionId;
|
|
1034
|
+
oldState.authorization.user = user != null ? user : null;
|
|
1035
|
+
return oldState;
|
|
1036
|
+
});
|
|
1037
|
+
const userInfo = {
|
|
1038
|
+
connectionId,
|
|
1039
|
+
presence: (_a = data.presence) != null ? _a : void 0,
|
|
1040
|
+
user
|
|
1041
|
+
};
|
|
1042
|
+
this._usersManager.setMyself(userInfo);
|
|
1043
|
+
const presence = this._usersManager.myPresence;
|
|
1044
|
+
const myself = (_b = this._usersManager.myself) != null ? _b : null;
|
|
1045
|
+
this._stateNotifier.subjects["my-presence"].next(presence);
|
|
1046
|
+
this._stateNotifier.subjects.myself.next(myself);
|
|
1047
|
+
const update = !state ? (_c = this._crdtManager.resolveEncodedState(yield this._storageStore.getUpdates())) != null ? _c : this._crdtManager.getInitialState() : this._crdtManager.getInitialState();
|
|
1048
|
+
this._sendMessage({
|
|
1049
|
+
type: "$initializeSession",
|
|
1050
|
+
data: { presence, update }
|
|
1051
|
+
});
|
|
1058
1052
|
});
|
|
1059
1053
|
}
|
|
1060
1054
|
_handleStorageReceivedMessage(message) {
|
|
@@ -1063,24 +1057,34 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1063
1057
|
if (!connectionId) return;
|
|
1064
1058
|
if (!this._state.webSocket) throw new Error("Could not find WebSocket");
|
|
1065
1059
|
const data = message.data;
|
|
1060
|
+
const changeKind = data.changeKind;
|
|
1066
1061
|
const state = data.state;
|
|
1067
|
-
this.
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
origin:
|
|
1075
|
-
|
|
1076
|
-
|
|
1062
|
+
const updates = yield this._storageStore.getUpdates();
|
|
1063
|
+
const origin = ORIGIN_INITIALIZED;
|
|
1064
|
+
const updateStorage = (update) => {
|
|
1065
|
+
return this._crdtManager.initialized ? this._crdtManager.applyUpdate({ update, origin }) : this._crdtManager.initialize({ update, origin });
|
|
1066
|
+
};
|
|
1067
|
+
if (changeKind === "empty") {
|
|
1068
|
+
this._crdtManager.destroy();
|
|
1069
|
+
this._crdtManager.initialize({ origin, update: updates });
|
|
1070
|
+
} else if (changeKind === "initialized") {
|
|
1071
|
+
if (!!updates.length) updateStorage(updates);
|
|
1072
|
+
else {
|
|
1073
|
+
const encodedState2 = updateStorage(state).doc.getEncodedState();
|
|
1074
|
+
this._addToStorageStore(encodedState2);
|
|
1075
|
+
}
|
|
1076
|
+
} else {
|
|
1077
|
+
const encodedState2 = updateStorage(state).doc.getEncodedState();
|
|
1078
|
+
if (!!updates.length) this._crdtManager.applyUpdate({ update: updates, origin });
|
|
1079
|
+
yield this._addToStorageStore(encodedState2);
|
|
1080
|
+
}
|
|
1077
1081
|
const encodedState = this._crdtManager.doc.getEncodedState();
|
|
1078
|
-
yield this._storageStore.addUpdate(encodedState);
|
|
1079
1082
|
this._emitSharedTypes();
|
|
1080
|
-
|
|
1083
|
+
this._observeCrdt();
|
|
1084
|
+
this._stateNotifier.subjects["storage-loaded"].next(true);
|
|
1081
1085
|
this._sendMessage({
|
|
1082
1086
|
type: "$updateStorage",
|
|
1083
|
-
data: { origin
|
|
1087
|
+
data: { origin, update: encodedState }
|
|
1084
1088
|
});
|
|
1085
1089
|
});
|
|
1086
1090
|
}
|
|
@@ -1159,11 +1163,11 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1159
1163
|
const unsubscribe = this._crdtManager.doc.subscribe((event) => {
|
|
1160
1164
|
var _a2;
|
|
1161
1165
|
const origin = (_a2 = event.origin) != null ? _a2 : null;
|
|
1162
|
-
this._addToStorageStore(event.update);
|
|
1163
1166
|
this._emitSharedTypes();
|
|
1164
1167
|
if (origin === ORIGIN_INITIALIZED || origin === ORIGIN_STORAGE_UPDATED) {
|
|
1165
1168
|
return;
|
|
1166
1169
|
}
|
|
1170
|
+
this._addToStorageStore(event.update);
|
|
1167
1171
|
if (!this._state.webSocket) return;
|
|
1168
1172
|
if (!this._state.connection.id) return;
|
|
1169
1173
|
if (this._state.webSocket.readyState !== WebSocket.OPEN) return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
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.5",
|
|
21
|
-
"@pluv/crdt": "^1.0.
|
|
22
|
-
"@pluv/types": "^1.0.
|
|
21
|
+
"@pluv/crdt": "^1.0.2",
|
|
22
|
+
"@pluv/types": "^1.0.2"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"eslint": "^9.25.1",
|
|
26
26
|
"tsup": "^8.4.0",
|
|
27
27
|
"typescript": "^5.8.3",
|
|
28
|
-
"@pluv/tsconfig": "^1.0.
|
|
29
|
-
"eslint-config-pluv": "^1.0.
|
|
28
|
+
"@pluv/tsconfig": "^1.0.2",
|
|
29
|
+
"eslint-config-pluv": "^1.0.2"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|
package/src/CrdtManager.ts
CHANGED
|
@@ -5,11 +5,15 @@ export type CrdtManagerOptions<TStorage extends Record<string, CrdtType<any, any
|
|
|
5
5
|
initialStorage?: AbstractCrdtDocFactory<TStorage>;
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
onInitialized?: (state: string) => void;
|
|
8
|
+
interface CrdtManagerInitializeParams {
|
|
10
9
|
origin?: any;
|
|
11
10
|
update: string | readonly string[];
|
|
12
|
-
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface ApplyUpdateParams {
|
|
14
|
+
origin?: any;
|
|
15
|
+
update: string | readonly string[];
|
|
16
|
+
}
|
|
13
17
|
|
|
14
18
|
export class CrdtManager<TStorage extends Record<string, CrdtType<any, any>>> {
|
|
15
19
|
public doc: AbstractCrdtDoc<TStorage>;
|
|
@@ -30,7 +34,9 @@ export class CrdtManager<TStorage extends Record<string, CrdtType<any, any>>> {
|
|
|
30
34
|
* update. This unfortunately means updates can be dropped entirely
|
|
31
35
|
* @date June 13, 2023
|
|
32
36
|
*/
|
|
33
|
-
public applyUpdate(
|
|
37
|
+
public applyUpdate(params: ApplyUpdateParams): this {
|
|
38
|
+
const { origin, update } = params;
|
|
39
|
+
|
|
34
40
|
if (!this.initialized) return this;
|
|
35
41
|
|
|
36
42
|
const updates: readonly string[] = typeof update === "string" ? [update] : update;
|
|
@@ -41,7 +47,9 @@ export class CrdtManager<TStorage extends Record<string, CrdtType<any, any>>> {
|
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
public destroy(): void {
|
|
50
|
+
this.initialized = false;
|
|
44
51
|
this.doc.destroy();
|
|
52
|
+
this.doc = this._docFactory.getEmpty();
|
|
45
53
|
}
|
|
46
54
|
|
|
47
55
|
public get<TKey extends keyof TStorage>(key: TKey): TStorage[TKey] {
|
|
@@ -53,7 +61,7 @@ export class CrdtManager<TStorage extends Record<string, CrdtType<any, any>>> {
|
|
|
53
61
|
}
|
|
54
62
|
|
|
55
63
|
public initialize(params: CrdtManagerInitializeParams): this {
|
|
56
|
-
const {
|
|
64
|
+
const { origin, update } = params;
|
|
57
65
|
|
|
58
66
|
/**
|
|
59
67
|
* !HACK
|
|
@@ -94,11 +102,13 @@ export class CrdtManager<TStorage extends Record<string, CrdtType<any, any>>> {
|
|
|
94
102
|
this.initialized = true;
|
|
95
103
|
initialized.destroy();
|
|
96
104
|
|
|
97
|
-
onInitialized?.(this.doc.getEncodedState());
|
|
98
|
-
|
|
99
105
|
return this;
|
|
100
106
|
}
|
|
101
107
|
|
|
108
|
+
public resolveEncodedState(updates: string | string[] | readonly string[]): string | null {
|
|
109
|
+
return this._docFactory.resolveEncodedState(updates);
|
|
110
|
+
}
|
|
111
|
+
|
|
102
112
|
private _applyDocUpdates(
|
|
103
113
|
doc: AbstractCrdtDoc<TStorage>,
|
|
104
114
|
updates: readonly string[],
|
package/src/PluvRoom.ts
CHANGED
|
@@ -389,8 +389,7 @@ export class PluvRoom<
|
|
|
389
389
|
return oldState;
|
|
390
390
|
});
|
|
391
391
|
|
|
392
|
-
|
|
393
|
-
// await this._applyStorageStore();
|
|
392
|
+
await this._storageStore.initialize();
|
|
394
393
|
|
|
395
394
|
const wsEndpoint = this._getWsEndpoint(this.id, params);
|
|
396
395
|
const url = new URL(wsEndpoint);
|
|
@@ -612,22 +611,6 @@ export class PluvRoom<
|
|
|
612
611
|
this._flattenStorageStore();
|
|
613
612
|
}
|
|
614
613
|
|
|
615
|
-
private async _applyStorageStore(): Promise<void> {
|
|
616
|
-
const updates = await this._storageStore.getUpdates();
|
|
617
|
-
|
|
618
|
-
this._crdtManager.initialize({
|
|
619
|
-
onInitialized: () => {
|
|
620
|
-
this._stateNotifier.subjects["storage-loaded"].next(true);
|
|
621
|
-
|
|
622
|
-
this._observeCrdt();
|
|
623
|
-
},
|
|
624
|
-
origin: ORIGIN_INITIALIZED,
|
|
625
|
-
update: updates,
|
|
626
|
-
});
|
|
627
|
-
|
|
628
|
-
this._emitSharedTypes();
|
|
629
|
-
}
|
|
630
|
-
|
|
631
614
|
private _attachWindowListeners(): void {
|
|
632
615
|
if (typeof window === "undefined") return;
|
|
633
616
|
if (typeof document === "undefined") return;
|
|
@@ -738,7 +721,7 @@ export class PluvRoom<
|
|
|
738
721
|
|
|
739
722
|
const updates = await this._storageStore.getUpdates();
|
|
740
723
|
|
|
741
|
-
this._crdtManager.applyUpdate(updates, this);
|
|
724
|
+
this._crdtManager.applyUpdate({ update: updates, origin: this });
|
|
742
725
|
|
|
743
726
|
const encodedState = this._crdtManager.doc.getEncodedState();
|
|
744
727
|
|
|
@@ -941,7 +924,7 @@ export class PluvRoom<
|
|
|
941
924
|
this._stateNotifier.subjects.others.next(others);
|
|
942
925
|
}
|
|
943
926
|
|
|
944
|
-
private _handleRegisteredMessage(message: IOEventMessage<TIO>): void {
|
|
927
|
+
private async _handleRegisteredMessage(message: IOEventMessage<TIO>): Promise<void> {
|
|
945
928
|
const { connectionId } = message;
|
|
946
929
|
const user = message.user as Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>>;
|
|
947
930
|
|
|
@@ -950,11 +933,6 @@ export class PluvRoom<
|
|
|
950
933
|
if (!this._state.webSocket) throw new Error("Could not find WebSocket");
|
|
951
934
|
|
|
952
935
|
const data = message.data as BaseIOEventRecord<InferIOAuthorize<TIO>>["$registered"];
|
|
953
|
-
/**
|
|
954
|
-
* TODO
|
|
955
|
-
* @description Maybe we can use this to resolve storage initialization more efficiently
|
|
956
|
-
* @date May 7, 2025
|
|
957
|
-
*/
|
|
958
936
|
const state = data.state;
|
|
959
937
|
|
|
960
938
|
this._updateState((oldState) => {
|
|
@@ -978,7 +956,10 @@ export class PluvRoom<
|
|
|
978
956
|
this._stateNotifier.subjects["my-presence"].next(presence);
|
|
979
957
|
this._stateNotifier.subjects.myself.next(myself);
|
|
980
958
|
|
|
981
|
-
const update =
|
|
959
|
+
const update = !state
|
|
960
|
+
? (this._crdtManager.resolveEncodedState(await this._storageStore.getUpdates()) ??
|
|
961
|
+
this._crdtManager.getInitialState())
|
|
962
|
+
: this._crdtManager.getInitialState();
|
|
982
963
|
|
|
983
964
|
this._sendMessage({
|
|
984
965
|
type: "$initializeSession",
|
|
@@ -994,30 +975,45 @@ export class PluvRoom<
|
|
|
994
975
|
if (!this._state.webSocket) throw new Error("Could not find WebSocket");
|
|
995
976
|
|
|
996
977
|
const data = message.data as BaseIOEventRecord<InferIOAuthorize<TIO>>["$storageReceived"];
|
|
978
|
+
const changeKind = data.changeKind;
|
|
997
979
|
const state = data.state;
|
|
998
980
|
|
|
999
|
-
this.
|
|
1000
|
-
|
|
1001
|
-
await this._addToStorageStore(update);
|
|
1002
|
-
this._emitSharedTypes();
|
|
1003
|
-
this._observeCrdt();
|
|
1004
|
-
this._stateNotifier.subjects["storage-loaded"].next(true);
|
|
1005
|
-
},
|
|
1006
|
-
origin: ORIGIN_INITIALIZED,
|
|
1007
|
-
update: state,
|
|
1008
|
-
});
|
|
981
|
+
const updates = await this._storageStore.getUpdates();
|
|
982
|
+
const origin = ORIGIN_INITIALIZED;
|
|
1009
983
|
|
|
1010
|
-
const
|
|
984
|
+
const updateStorage = (update: string | readonly string[]) => {
|
|
985
|
+
return this._crdtManager.initialized
|
|
986
|
+
? this._crdtManager.applyUpdate({ update, origin })
|
|
987
|
+
: this._crdtManager.initialize({ update, origin });
|
|
988
|
+
};
|
|
1011
989
|
|
|
1012
|
-
|
|
990
|
+
if (changeKind === "empty") {
|
|
991
|
+
this._crdtManager.destroy();
|
|
992
|
+
this._crdtManager.initialize({ origin, update: updates });
|
|
993
|
+
} else if (changeKind === "initialized") {
|
|
994
|
+
if (!!updates.length) updateStorage(updates);
|
|
995
|
+
else {
|
|
996
|
+
const encodedState = updateStorage(state).doc.getEncodedState();
|
|
1013
997
|
|
|
1014
|
-
|
|
998
|
+
this._addToStorageStore(encodedState);
|
|
999
|
+
}
|
|
1000
|
+
} else {
|
|
1001
|
+
const encodedState = updateStorage(state).doc.getEncodedState();
|
|
1002
|
+
|
|
1003
|
+
if (!!updates.length) this._crdtManager.applyUpdate({ update: updates, origin });
|
|
1004
|
+
|
|
1005
|
+
await this._addToStorageStore(encodedState);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
const encodedState = this._crdtManager.doc.getEncodedState();
|
|
1015
1009
|
|
|
1016
|
-
|
|
1010
|
+
this._emitSharedTypes();
|
|
1011
|
+
this._observeCrdt();
|
|
1012
|
+
this._stateNotifier.subjects["storage-loaded"].next(true);
|
|
1017
1013
|
|
|
1018
1014
|
this._sendMessage({
|
|
1019
1015
|
type: "$updateStorage",
|
|
1020
|
-
data: { origin
|
|
1016
|
+
data: { origin, update: encodedState },
|
|
1021
1017
|
});
|
|
1022
1018
|
}
|
|
1023
1019
|
|
|
@@ -1135,13 +1131,14 @@ export class PluvRoom<
|
|
|
1135
1131
|
const unsubscribe = this._crdtManager.doc.subscribe((event) => {
|
|
1136
1132
|
const origin = event.origin ?? null;
|
|
1137
1133
|
|
|
1138
|
-
this._addToStorageStore(event.update);
|
|
1139
1134
|
this._emitSharedTypes();
|
|
1140
1135
|
|
|
1141
1136
|
if (origin === ORIGIN_INITIALIZED || origin === ORIGIN_STORAGE_UPDATED) {
|
|
1142
1137
|
return;
|
|
1143
1138
|
}
|
|
1144
1139
|
|
|
1140
|
+
this._addToStorageStore(event.update);
|
|
1141
|
+
|
|
1145
1142
|
if (!this._state.webSocket) return;
|
|
1146
1143
|
if (!this._state.connection.id) return;
|
|
1147
1144
|
if (this._state.webSocket.readyState !== WebSocket.OPEN) return;
|