@pluv/client 2.0.2 → 2.2.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 +141 -0
- package/dist/index.d.mts +74 -79
- package/dist/index.d.ts +74 -79
- package/dist/index.js +267 -68
- package/dist/index.mjs +269 -70
- package/package.json +5 -5
- package/src/CrdtManager.ts +9 -13
- package/src/CrdtNotifier.ts +2 -1
- package/src/ListenerManager.ts +21 -0
- package/src/MockedRoom.ts +118 -48
- package/src/PluvClient.ts +8 -8
- package/src/PluvProcedure.ts +27 -25
- package/src/PluvRoom.ts +235 -82
- package/src/PluvRouter.ts +31 -22
- package/src/StateNotifier.ts +13 -19
- package/src/UsersManager.ts +18 -4
- package/src/UsersNotifier.ts +66 -0
- package/src/constants.ts +1 -0
- package/src/createClient.ts +2 -2
- package/src/index.ts +2 -1
- package/src/types.ts +10 -31
- package/src/OtherNotifier.ts +0 -50
package/dist/index.mjs
CHANGED
|
@@ -50,6 +50,7 @@ var AbstractStorageStore = class {
|
|
|
50
50
|
|
|
51
51
|
// src/constants.ts
|
|
52
52
|
var MAX_PRESENCE_SIZE_BYTES = 512;
|
|
53
|
+
var PLUV_PRESENCE_META_KEY = "__pluv";
|
|
53
54
|
|
|
54
55
|
// src/PluvProcedure.ts
|
|
55
56
|
var PluvProcedure = class _PluvProcedure {
|
|
@@ -87,7 +88,7 @@ var PluvProcedure = class _PluvProcedure {
|
|
|
87
88
|
};
|
|
88
89
|
|
|
89
90
|
// src/PluvRoom.ts
|
|
90
|
-
import { ConnectionState } from "@pluv/types";
|
|
91
|
+
import { ConnectionState, StorageState } from "@pluv/types";
|
|
91
92
|
|
|
92
93
|
// src/CrdtManager.ts
|
|
93
94
|
import { noop } from "@pluv/crdt";
|
|
@@ -96,7 +97,7 @@ var CrdtManager = class {
|
|
|
96
97
|
this.initialized = false;
|
|
97
98
|
const { initialStorage = noop.doc({}) } = options;
|
|
98
99
|
this._docFactory = initialStorage;
|
|
99
|
-
this.doc =
|
|
100
|
+
this.doc = this._docFactory.getEmpty();
|
|
100
101
|
}
|
|
101
102
|
/**
|
|
102
103
|
* !HACK
|
|
@@ -136,11 +137,7 @@ var CrdtManager = class {
|
|
|
136
137
|
if (!updates.length) return this;
|
|
137
138
|
const initialized = this._docFactory.getInitialized();
|
|
138
139
|
const reference = initialized.get();
|
|
139
|
-
this.doc = this._applyDocUpdates(
|
|
140
|
-
this._docFactory.getEmpty(),
|
|
141
|
-
updates,
|
|
142
|
-
origin
|
|
143
|
-
).rebuildStorage(reference);
|
|
140
|
+
this.doc = this._applyDocUpdates(this.doc, updates, origin).rebuildStorage(reference);
|
|
144
141
|
this.initialized = true;
|
|
145
142
|
initialized.destroy();
|
|
146
143
|
return this;
|
|
@@ -200,31 +197,21 @@ var EventNotifier = class {
|
|
|
200
197
|
}
|
|
201
198
|
};
|
|
202
199
|
|
|
203
|
-
// src/
|
|
200
|
+
// src/ListenerManager.ts
|
|
204
201
|
import { makeSubject as makeSubject3, subscribe as subscribe3 } from "wonka";
|
|
205
|
-
var
|
|
202
|
+
var ListenerManager = class {
|
|
206
203
|
constructor() {
|
|
207
|
-
this.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
this._subjects.clear();
|
|
214
|
-
}
|
|
215
|
-
delete(clientId) {
|
|
216
|
-
this.subject(clientId).next(null);
|
|
217
|
-
this._subjects.delete(clientId);
|
|
218
|
-
}
|
|
219
|
-
subject(clientId) {
|
|
220
|
-
const subject = this._subjects.get(clientId);
|
|
221
|
-
if (subject) return subject;
|
|
222
|
-
const newSubject = makeSubject3();
|
|
223
|
-
this._subjects.set(clientId, newSubject);
|
|
224
|
-
return newSubject;
|
|
204
|
+
this.subjects = {
|
|
205
|
+
close: makeSubject3(),
|
|
206
|
+
error: makeSubject3(),
|
|
207
|
+
message: makeSubject3(),
|
|
208
|
+
open: makeSubject3()
|
|
209
|
+
};
|
|
225
210
|
}
|
|
226
|
-
subscribe(
|
|
227
|
-
|
|
211
|
+
subscribe(kind, callback) {
|
|
212
|
+
var _a;
|
|
213
|
+
const source = (_a = this.subjects[kind]) == null ? void 0 : _a.source;
|
|
214
|
+
if (!source) return () => void 0;
|
|
228
215
|
return subscribe3(callback)(source).unsubscribe;
|
|
229
216
|
}
|
|
230
217
|
};
|
|
@@ -445,6 +432,9 @@ var UsersManager = class {
|
|
|
445
432
|
);
|
|
446
433
|
const presence = __spreadValues(__spreadValues(__spreadValues({}, this.initialPresence), cleanedPresence), cleanedPatch);
|
|
447
434
|
const validated = this._presence ? this._presence.parse(presence) : presence;
|
|
435
|
+
if (!!presence[PLUV_PRESENCE_META_KEY]) {
|
|
436
|
+
validated[PLUV_PRESENCE_META_KEY] = presence[PLUV_PRESENCE_META_KEY];
|
|
437
|
+
}
|
|
448
438
|
this._others.set(clientId, __spreadProps(__spreadValues({}, other), { presence: validated }));
|
|
449
439
|
return validated;
|
|
450
440
|
}
|
|
@@ -522,6 +512,43 @@ var UsersManager = class {
|
|
|
522
512
|
}
|
|
523
513
|
};
|
|
524
514
|
|
|
515
|
+
// src/UsersNotifier.ts
|
|
516
|
+
import { makeSubject as makeSubject5, subscribe as subscribe5 } from "wonka";
|
|
517
|
+
var UsersNotifier = class {
|
|
518
|
+
constructor() {
|
|
519
|
+
this.others = makeSubject5();
|
|
520
|
+
this._otherSubjects = /* @__PURE__ */ new Map();
|
|
521
|
+
}
|
|
522
|
+
clear() {
|
|
523
|
+
this._otherSubjects.forEach((subject) => {
|
|
524
|
+
subject.next(null);
|
|
525
|
+
});
|
|
526
|
+
this._otherSubjects.clear();
|
|
527
|
+
}
|
|
528
|
+
delete(clientId) {
|
|
529
|
+
this.other(clientId).next(null);
|
|
530
|
+
this._otherSubjects.delete(clientId);
|
|
531
|
+
}
|
|
532
|
+
other(clientId) {
|
|
533
|
+
const subject = this._otherSubjects.get(clientId);
|
|
534
|
+
if (subject) return subject;
|
|
535
|
+
const newSubject = makeSubject5();
|
|
536
|
+
this._otherSubjects.set(clientId, newSubject);
|
|
537
|
+
return newSubject;
|
|
538
|
+
}
|
|
539
|
+
subscribeOther(clientId, callback) {
|
|
540
|
+
const source = this.other(clientId).source;
|
|
541
|
+
const subscription = subscribe5(callback)(source);
|
|
542
|
+
return subscription.unsubscribe;
|
|
543
|
+
}
|
|
544
|
+
subscribeOthers(callback) {
|
|
545
|
+
const subscription = subscribe5(
|
|
546
|
+
({ others, event }) => callback(others, event)
|
|
547
|
+
)(this.others.source);
|
|
548
|
+
return subscription.unsubscribe;
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
|
|
525
552
|
// src/PluvRoom.ts
|
|
526
553
|
var ADD_TO_STORAGE_STATE_DEBOUNCE_MS = 1e3;
|
|
527
554
|
var HEARTBEAT_INTERVAL_MS = 1e4;
|
|
@@ -541,7 +568,7 @@ var PluvRoom = class {
|
|
|
541
568
|
this._intervals = {
|
|
542
569
|
heartbeat: null
|
|
543
570
|
};
|
|
544
|
-
this.
|
|
571
|
+
this._listenerManager = new ListenerManager();
|
|
545
572
|
this._publicKey = null;
|
|
546
573
|
this._stateNotifier = new StateNotifier();
|
|
547
574
|
this._subscriptions = {
|
|
@@ -551,6 +578,7 @@ var PluvRoom = class {
|
|
|
551
578
|
pong: null,
|
|
552
579
|
reconnect: null
|
|
553
580
|
};
|
|
581
|
+
this._usersNotifier = new UsersNotifier();
|
|
554
582
|
this._lastMetadata = null;
|
|
555
583
|
this._state = {
|
|
556
584
|
authorization: {
|
|
@@ -559,10 +587,12 @@ var PluvRoom = class {
|
|
|
559
587
|
},
|
|
560
588
|
connection: {
|
|
561
589
|
attempts: 0,
|
|
562
|
-
count: 0,
|
|
563
590
|
id: null,
|
|
564
591
|
state: ConnectionState.Untouched
|
|
565
592
|
},
|
|
593
|
+
storage: {
|
|
594
|
+
state: StorageState.Unavailable
|
|
595
|
+
},
|
|
566
596
|
webSocket: null
|
|
567
597
|
};
|
|
568
598
|
this._windowListeners = null;
|
|
@@ -605,6 +635,9 @@ var PluvRoom = class {
|
|
|
605
635
|
this.canUndo = () => {
|
|
606
636
|
return !!this._crdtManager.doc.canUndo();
|
|
607
637
|
};
|
|
638
|
+
/**
|
|
639
|
+
* @deprecated To be removed in v3. Use PluvRoom.subscribe.event instead
|
|
640
|
+
*/
|
|
608
641
|
this.event = new Proxy(
|
|
609
642
|
(event, callback) => this._eventNotifier.subscribe(event, callback),
|
|
610
643
|
{
|
|
@@ -636,23 +669,80 @@ var PluvRoom = class {
|
|
|
636
669
|
if (typeof sharedType === "undefined") return null;
|
|
637
670
|
return sharedType;
|
|
638
671
|
};
|
|
672
|
+
this.getStorageLoaded = () => {
|
|
673
|
+
return this._state.storage.state === StorageState.Offline || this._state.storage.state === StorageState.Synced;
|
|
674
|
+
};
|
|
675
|
+
/**
|
|
676
|
+
* @deprecated To be removed in v3. Use PluvRoom.subscribe.other instead
|
|
677
|
+
*/
|
|
639
678
|
this.other = (connectionId, callback) => {
|
|
640
679
|
const clientId = this._usersManager.getClientId(connectionId);
|
|
641
680
|
if (!clientId) return () => void 0;
|
|
642
|
-
return this.
|
|
681
|
+
return this._usersNotifier.subscribeOther(clientId, callback);
|
|
643
682
|
};
|
|
644
683
|
this.redo = () => {
|
|
645
684
|
this._crdtManager.doc.redo();
|
|
646
685
|
};
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
this.
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
686
|
+
/**
|
|
687
|
+
* @deprecated To be removed in v3. Use PluvRoom.subscribe.storage instead
|
|
688
|
+
*/
|
|
689
|
+
this.storage = new Proxy(
|
|
690
|
+
(key, callback) => this._crdtNotifier.subscribe(key, callback),
|
|
691
|
+
{
|
|
692
|
+
get: (fn, prop) => {
|
|
693
|
+
if (!!prop) {
|
|
694
|
+
return (callback) => {
|
|
695
|
+
return this._crdtNotifier.subcribeRoot(callback);
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
return (callback) => {
|
|
699
|
+
return fn(prop, callback);
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
);
|
|
704
|
+
/**
|
|
705
|
+
* @deprecated To be removed in v3. Use PluvRoom.subscribe.storage instead
|
|
706
|
+
* @description Subscribes to the root storage object (serialized)
|
|
707
|
+
*/
|
|
708
|
+
this.storageRoot = (callback) => {
|
|
709
|
+
return this._crdtNotifier.subcribeRoot(callback);
|
|
655
710
|
};
|
|
711
|
+
this.subscribe = new Proxy(
|
|
712
|
+
(name, callback) => this._stateNotifier.subscribe(name, callback),
|
|
713
|
+
{
|
|
714
|
+
get: (fn, prop) => {
|
|
715
|
+
if (prop === "connection") {
|
|
716
|
+
return (callback) => {
|
|
717
|
+
return fn("connection", callback);
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
if (prop === "myPresence") {
|
|
721
|
+
return (callback) => {
|
|
722
|
+
return fn("my-presence", callback);
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
if (prop === "myself") {
|
|
726
|
+
return (callback) => {
|
|
727
|
+
return fn("myself", callback);
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
if (prop === "others") {
|
|
731
|
+
return (callback) => {
|
|
732
|
+
return this._usersNotifier.subscribeOthers(callback);
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
if (prop === "storageLoaded") {
|
|
736
|
+
return (callback) => {
|
|
737
|
+
return fn("storage-loaded", callback);
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
if (prop === "event") return this.event;
|
|
741
|
+
if (prop === "other") return this.other;
|
|
742
|
+
if (prop === "storage") return this.storage;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
);
|
|
656
746
|
this.transact = (fn, origin) => {
|
|
657
747
|
const _origin = origin != null ? origin : this._state.connection.id;
|
|
658
748
|
if (typeof _origin !== "string") return;
|
|
@@ -732,12 +822,18 @@ var PluvRoom = class {
|
|
|
732
822
|
});
|
|
733
823
|
this._crdtManager = new CrdtManager({ initialStorage });
|
|
734
824
|
}
|
|
825
|
+
/**
|
|
826
|
+
* @deprecated To be removed in v3. Use `getStorageLoaded` instead.
|
|
827
|
+
*/
|
|
735
828
|
get storageLoaded() {
|
|
736
|
-
return this.
|
|
829
|
+
return this.getStorageLoaded();
|
|
737
830
|
}
|
|
738
831
|
get webSocket() {
|
|
739
832
|
return this._state.webSocket;
|
|
740
833
|
}
|
|
834
|
+
addEventListener(kind, handler) {
|
|
835
|
+
return this._listenerManager.subscribe(kind, handler);
|
|
836
|
+
}
|
|
741
837
|
connect(...args) {
|
|
742
838
|
return __async(this, null, function* () {
|
|
743
839
|
var _a;
|
|
@@ -779,6 +875,7 @@ var PluvRoom = class {
|
|
|
779
875
|
this._updateState((oldState) => {
|
|
780
876
|
oldState.connection.attempts = 0;
|
|
781
877
|
oldState.authorization.token = authToken;
|
|
878
|
+
oldState.storage.state = StorageState.Loading;
|
|
782
879
|
oldState.webSocket = webSocket;
|
|
783
880
|
return oldState;
|
|
784
881
|
});
|
|
@@ -799,6 +896,7 @@ var PluvRoom = class {
|
|
|
799
896
|
this._updateState((oldState) => {
|
|
800
897
|
oldState.authorization.token = null;
|
|
801
898
|
oldState.connection.state = ConnectionState.Closed;
|
|
899
|
+
oldState.storage.state = oldState.storage.state === StorageState.Synced ? StorageState.Offline : StorageState.Unavailable;
|
|
802
900
|
oldState.webSocket = null;
|
|
803
901
|
return oldState;
|
|
804
902
|
});
|
|
@@ -863,9 +961,10 @@ var PluvRoom = class {
|
|
|
863
961
|
this._detachWindowListeners();
|
|
864
962
|
this._usersManager.removeMyself();
|
|
865
963
|
this._usersManager.clearConnections();
|
|
866
|
-
this.
|
|
964
|
+
this._usersNotifier.clear();
|
|
867
965
|
this._stateNotifier.subjects.myself.next(null);
|
|
868
966
|
this._stateNotifier.subjects.others.next([]);
|
|
967
|
+
this._usersNotifier.others.next({ others: [], event: { kind: "clear" } });
|
|
869
968
|
(_c = this._state.webSocket) == null ? void 0 : _c.close();
|
|
870
969
|
this._detachWsListeners();
|
|
871
970
|
}
|
|
@@ -956,7 +1055,16 @@ var PluvRoom = class {
|
|
|
956
1055
|
const deleted = this._usersManager.deleteConnection(connectionId);
|
|
957
1056
|
const others = this._usersManager.getOthers();
|
|
958
1057
|
this._stateNotifier.subjects.others.next(others);
|
|
959
|
-
if (!
|
|
1058
|
+
if (!deleted) {
|
|
1059
|
+
console.warn("Could not identify exited connection");
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
const { data: user, remaining } = deleted;
|
|
1063
|
+
this._usersNotifier.others.next({
|
|
1064
|
+
others,
|
|
1065
|
+
event: { kind: "leave", user }
|
|
1066
|
+
});
|
|
1067
|
+
if (!remaining && !!clientId) this._usersNotifier.delete(clientId);
|
|
960
1068
|
}
|
|
961
1069
|
_handlePresenceUpdatedMessage(message) {
|
|
962
1070
|
var _a;
|
|
@@ -975,19 +1083,31 @@ var PluvRoom = class {
|
|
|
975
1083
|
return;
|
|
976
1084
|
}
|
|
977
1085
|
if (!!clientId) {
|
|
978
|
-
const
|
|
979
|
-
this.
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1086
|
+
const other2 = this._usersManager.getOther(connectionId);
|
|
1087
|
+
const others2 = this._usersManager.getOthers();
|
|
1088
|
+
this._usersNotifier.other(clientId).next(other2);
|
|
1089
|
+
this._stateNotifier.subjects.others.next(others2);
|
|
1090
|
+
if (!!other2) {
|
|
1091
|
+
this._usersNotifier.others.next({
|
|
1092
|
+
others: others2,
|
|
1093
|
+
event: { kind: "update", user: other2 }
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
return;
|
|
988
1097
|
}
|
|
1098
|
+
const added = this._usersManager.addConnection({
|
|
1099
|
+
connectionId,
|
|
1100
|
+
presence: data.presence,
|
|
1101
|
+
user: message.user
|
|
1102
|
+
});
|
|
1103
|
+
const other = this._usersManager.getOther(connectionId);
|
|
989
1104
|
const others = this._usersManager.getOthers();
|
|
1105
|
+
this._usersNotifier.other(added.clientId).next(other);
|
|
990
1106
|
this._stateNotifier.subjects.others.next(others);
|
|
1107
|
+
this._usersNotifier.others.next({
|
|
1108
|
+
others,
|
|
1109
|
+
event: { kind: "update", user: added.data }
|
|
1110
|
+
});
|
|
991
1111
|
}
|
|
992
1112
|
_handleReceiveOthers(message) {
|
|
993
1113
|
if (!message.connectionId) return;
|
|
@@ -1004,10 +1124,14 @@ var PluvRoom = class {
|
|
|
1004
1124
|
if (result.isMyself) return;
|
|
1005
1125
|
const clientId = result.clientId;
|
|
1006
1126
|
const other = this._usersManager.getOther(connectionId);
|
|
1007
|
-
this.
|
|
1127
|
+
this._usersNotifier.other(clientId).next(other);
|
|
1008
1128
|
});
|
|
1009
1129
|
const others = this._usersManager.getOthers();
|
|
1010
1130
|
this._stateNotifier.subjects.others.next(others);
|
|
1131
|
+
this._usersNotifier.others.next({
|
|
1132
|
+
others,
|
|
1133
|
+
event: { kind: "sync", users: others }
|
|
1134
|
+
});
|
|
1011
1135
|
}
|
|
1012
1136
|
_handleRegisteredMessage(message) {
|
|
1013
1137
|
return __async(this, null, function* () {
|
|
@@ -1019,7 +1143,6 @@ var PluvRoom = class {
|
|
|
1019
1143
|
const data = message.data;
|
|
1020
1144
|
const state = data.state;
|
|
1021
1145
|
this._updateState((oldState) => {
|
|
1022
|
-
oldState.connection.count += 1;
|
|
1023
1146
|
oldState.connection.id = connectionId;
|
|
1024
1147
|
oldState.authorization.user = user != null ? user : null;
|
|
1025
1148
|
return oldState;
|
|
@@ -1071,6 +1194,10 @@ var PluvRoom = class {
|
|
|
1071
1194
|
const encodedState = this._crdtManager.doc.getEncodedState();
|
|
1072
1195
|
this._emitSharedTypes();
|
|
1073
1196
|
this._observeCrdt();
|
|
1197
|
+
this._updateState((oldState) => {
|
|
1198
|
+
oldState.storage.state = StorageState.Synced;
|
|
1199
|
+
return oldState;
|
|
1200
|
+
});
|
|
1074
1201
|
this._stateNotifier.subjects["storage-loaded"].next(true);
|
|
1075
1202
|
this._sendMessage({
|
|
1076
1203
|
type: "$updateStorage",
|
|
@@ -1109,6 +1236,11 @@ var PluvRoom = class {
|
|
|
1109
1236
|
const quitters = this._usersManager.getOthers().filter((other) => !active.has(other.connectionId));
|
|
1110
1237
|
quitters.forEach((quitter) => {
|
|
1111
1238
|
this._usersManager.deleteConnection(quitter.connectionId);
|
|
1239
|
+
const remaining2 = this._usersManager.getOthers();
|
|
1240
|
+
this._usersNotifier.others.next({
|
|
1241
|
+
others: remaining2,
|
|
1242
|
+
event: { kind: "leave", user: quitter }
|
|
1243
|
+
});
|
|
1112
1244
|
});
|
|
1113
1245
|
const remaining = this._usersManager.getOthers();
|
|
1114
1246
|
this._stateNotifier.subjects.others.next(remaining);
|
|
@@ -1131,8 +1263,12 @@ var PluvRoom = class {
|
|
|
1131
1263
|
});
|
|
1132
1264
|
const other = this._usersManager.getOther(connectionId);
|
|
1133
1265
|
const others = this._usersManager.getOthers();
|
|
1134
|
-
this.
|
|
1266
|
+
this._usersNotifier.other(added.clientId).next(other);
|
|
1135
1267
|
this._stateNotifier.subjects.others.next(others);
|
|
1268
|
+
this._usersNotifier.others.next({
|
|
1269
|
+
others,
|
|
1270
|
+
event: { kind: "enter", user: added.data }
|
|
1271
|
+
});
|
|
1136
1272
|
}
|
|
1137
1273
|
_heartbeat() {
|
|
1138
1274
|
this._clearTimeout(this._timeouts.pong);
|
|
@@ -1174,11 +1310,13 @@ var PluvRoom = class {
|
|
|
1174
1310
|
this._listeners.onAuthorizationFail(authError);
|
|
1175
1311
|
this._updateState((oldState) => {
|
|
1176
1312
|
oldState.connection.state = ConnectionState.Unavailable;
|
|
1313
|
+
oldState.storage.state = StorageState.Unavailable;
|
|
1177
1314
|
return oldState;
|
|
1178
1315
|
});
|
|
1179
1316
|
}
|
|
1180
1317
|
_onClose(event) {
|
|
1181
1318
|
return __async(this, null, function* () {
|
|
1319
|
+
this._listenerManager.subjects.close.next(event);
|
|
1182
1320
|
this._logDebug("WebSocket closed");
|
|
1183
1321
|
if (!!event.reason) this._logDebug(event.reason);
|
|
1184
1322
|
const shouldRetry = [
|
|
@@ -1206,6 +1344,7 @@ var PluvRoom = class {
|
|
|
1206
1344
|
*/
|
|
1207
1345
|
ConnectionState.Closed
|
|
1208
1346
|
);
|
|
1347
|
+
oldState.storage.state = oldState.storage.state === StorageState.Synced ? StorageState.Offline : StorageState.Unavailable;
|
|
1209
1348
|
oldState.webSocket = null;
|
|
1210
1349
|
return oldState;
|
|
1211
1350
|
});
|
|
@@ -1222,9 +1361,11 @@ var PluvRoom = class {
|
|
|
1222
1361
|
* @description Handle websocket errors in a meaningful way, should they occur
|
|
1223
1362
|
* @date August 19, 2022
|
|
1224
1363
|
*/
|
|
1225
|
-
_onError() {
|
|
1364
|
+
_onError(event) {
|
|
1365
|
+
this._listenerManager.subjects.error.next(event);
|
|
1226
1366
|
}
|
|
1227
1367
|
_onMessage(event) {
|
|
1368
|
+
this._listenerManager.subjects.message.next(event);
|
|
1228
1369
|
const message = this._parseMessage(event);
|
|
1229
1370
|
if (!message) return;
|
|
1230
1371
|
const shouldLog = typeof this._debug === "boolean" ? this._debug : this._debug.output.find((value) => value === message.type);
|
|
@@ -1272,7 +1413,8 @@ var PluvRoom = class {
|
|
|
1272
1413
|
default:
|
|
1273
1414
|
}
|
|
1274
1415
|
}
|
|
1275
|
-
_onOpen() {
|
|
1416
|
+
_onOpen(event) {
|
|
1417
|
+
this._listenerManager.subjects.open.next(event);
|
|
1276
1418
|
if (this._state.connection.state !== ConnectionState.Connecting) return;
|
|
1277
1419
|
this._logDebug("WebSocket connected");
|
|
1278
1420
|
this._updateState((oldState) => {
|
|
@@ -1290,6 +1432,7 @@ var PluvRoom = class {
|
|
|
1290
1432
|
if (this._state.connection.state === ConnectionState.Closed) return;
|
|
1291
1433
|
this._updateState((oldState) => {
|
|
1292
1434
|
oldState.connection.state = ConnectionState.Unavailable;
|
|
1435
|
+
oldState.storage.state = oldState.storage.state === StorageState.Synced ? StorageState.Offline : StorageState.Unavailable;
|
|
1293
1436
|
return oldState;
|
|
1294
1437
|
});
|
|
1295
1438
|
});
|
|
@@ -1389,6 +1532,7 @@ var PluvRoom = class {
|
|
|
1389
1532
|
const oldState = __spreadProps(__spreadValues({}, this._state), {
|
|
1390
1533
|
authorization,
|
|
1391
1534
|
connection: JSON.parse(JSON.stringify(this._state.connection)),
|
|
1535
|
+
storage: JSON.parse(JSON.stringify(this._state.storage)),
|
|
1392
1536
|
webSocket: this._state.webSocket
|
|
1393
1537
|
});
|
|
1394
1538
|
const newState = updater(oldState);
|
|
@@ -1502,12 +1646,16 @@ var createClient = (options) => {
|
|
|
1502
1646
|
var infer = (callback) => callback;
|
|
1503
1647
|
|
|
1504
1648
|
// src/MockedRoom.ts
|
|
1505
|
-
import { ConnectionState as ConnectionState2 } from "@pluv/types";
|
|
1649
|
+
import { ConnectionState as ConnectionState2, StorageState as StorageState2 } from "@pluv/types";
|
|
1506
1650
|
var MockedRoom = class {
|
|
1507
1651
|
constructor(room, options) {
|
|
1652
|
+
/**
|
|
1653
|
+
* @deprecated To be removed in v3. Use `getStorageLoaded` instead.
|
|
1654
|
+
*/
|
|
1655
|
+
this.storageLoaded = true;
|
|
1508
1656
|
this._crdtNotifier = new CrdtNotifier();
|
|
1509
1657
|
this._eventNotifier = new EventNotifier();
|
|
1510
|
-
this.
|
|
1658
|
+
this._usersNotifier = new UsersNotifier();
|
|
1511
1659
|
this._state = {
|
|
1512
1660
|
authorization: {
|
|
1513
1661
|
token: null,
|
|
@@ -1515,10 +1663,12 @@ var MockedRoom = class {
|
|
|
1515
1663
|
},
|
|
1516
1664
|
connection: {
|
|
1517
1665
|
attempts: 0,
|
|
1518
|
-
count: 1,
|
|
1519
1666
|
id: null,
|
|
1520
1667
|
state: ConnectionState2.Untouched
|
|
1521
1668
|
},
|
|
1669
|
+
storage: {
|
|
1670
|
+
state: StorageState2.Unavailable
|
|
1671
|
+
},
|
|
1522
1672
|
webSocket: null
|
|
1523
1673
|
};
|
|
1524
1674
|
this._stateNotifier = new StateNotifier();
|
|
@@ -1594,20 +1744,66 @@ var MockedRoom = class {
|
|
|
1594
1744
|
this.other = (connectionId, callback) => {
|
|
1595
1745
|
const clientId = this._usersManager.getClientId(connectionId);
|
|
1596
1746
|
if (!clientId) return () => void 0;
|
|
1597
|
-
return this.
|
|
1747
|
+
return this._usersNotifier.subscribeOther(clientId, callback);
|
|
1598
1748
|
};
|
|
1599
1749
|
this.redo = () => {
|
|
1600
1750
|
this._crdtManager.doc.redo();
|
|
1601
1751
|
};
|
|
1602
|
-
this.storage = (
|
|
1603
|
-
|
|
1604
|
-
|
|
1752
|
+
this.storage = new Proxy(
|
|
1753
|
+
(key, callback) => this._crdtNotifier.subscribe(key, callback),
|
|
1754
|
+
{
|
|
1755
|
+
get: (fn, prop) => {
|
|
1756
|
+
if (!!prop) {
|
|
1757
|
+
return (callback) => {
|
|
1758
|
+
return this._crdtNotifier.subcribeRoot(callback);
|
|
1759
|
+
};
|
|
1760
|
+
}
|
|
1761
|
+
return (callback) => {
|
|
1762
|
+
return fn(prop, callback);
|
|
1763
|
+
};
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
);
|
|
1605
1767
|
this.storageRoot = (fn) => {
|
|
1606
1768
|
return this._crdtNotifier.subcribeRoot(fn);
|
|
1607
1769
|
};
|
|
1608
|
-
this.subscribe = (
|
|
1609
|
-
|
|
1610
|
-
|
|
1770
|
+
this.subscribe = new Proxy(
|
|
1771
|
+
(name, callback) => {
|
|
1772
|
+
return this._stateNotifier.subscribe(name, callback);
|
|
1773
|
+
},
|
|
1774
|
+
{
|
|
1775
|
+
get: (fn, prop) => {
|
|
1776
|
+
if (prop === "connection") {
|
|
1777
|
+
return (callback) => {
|
|
1778
|
+
return fn("connection", callback);
|
|
1779
|
+
};
|
|
1780
|
+
}
|
|
1781
|
+
if (prop === "myPresence") {
|
|
1782
|
+
return (callback) => {
|
|
1783
|
+
return fn("my-presence", callback);
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
if (prop === "myself") {
|
|
1787
|
+
return (callback) => {
|
|
1788
|
+
return fn("myself", callback);
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1791
|
+
if (prop === "others") {
|
|
1792
|
+
return (callback) => {
|
|
1793
|
+
return this._usersNotifier.subscribeOthers(callback);
|
|
1794
|
+
};
|
|
1795
|
+
}
|
|
1796
|
+
if (prop === "storageLoaded") {
|
|
1797
|
+
return (callback) => {
|
|
1798
|
+
return fn("storage-loaded", callback);
|
|
1799
|
+
};
|
|
1800
|
+
}
|
|
1801
|
+
if (prop === "event") return this.event;
|
|
1802
|
+
if (prop === "other") return this.other;
|
|
1803
|
+
if (prop === "storage") return this.storage;
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
);
|
|
1611
1807
|
this.transact = (fn, origin) => {
|
|
1612
1808
|
const _origin = origin != null ? origin : this._state.connection.id;
|
|
1613
1809
|
const crdtManager = this._crdtManager;
|
|
@@ -1647,8 +1843,8 @@ var MockedRoom = class {
|
|
|
1647
1843
|
});
|
|
1648
1844
|
this._observeCrdt();
|
|
1649
1845
|
}
|
|
1650
|
-
|
|
1651
|
-
return
|
|
1846
|
+
addEventListener(kind, handler) {
|
|
1847
|
+
return () => void 0;
|
|
1652
1848
|
}
|
|
1653
1849
|
getDoc() {
|
|
1654
1850
|
return this._crdtManager.doc;
|
|
@@ -1658,6 +1854,9 @@ var MockedRoom = class {
|
|
|
1658
1854
|
if (typeof type === "undefined") return this._crdtManager.doc.toJson();
|
|
1659
1855
|
return this._crdtManager.doc.toJson(type);
|
|
1660
1856
|
}
|
|
1857
|
+
getStorageLoaded() {
|
|
1858
|
+
return true;
|
|
1859
|
+
}
|
|
1661
1860
|
_observeCrdt() {
|
|
1662
1861
|
var _a, _b;
|
|
1663
1862
|
(_b = (_a = this._subscriptions).observeCrdt) == null ? void 0 : _b.call(_a);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/client",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.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.5",
|
|
21
|
-
"@pluv/crdt": "^2.0
|
|
22
|
-
"@pluv/types": "^2.0
|
|
21
|
+
"@pluv/crdt": "^2.2.0",
|
|
22
|
+
"@pluv/types": "^2.2.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"eslint": "^9.26.0",
|
|
26
26
|
"tsup": "^8.4.0",
|
|
27
27
|
"typescript": "^5.8.3",
|
|
28
|
-
"@pluv/tsconfig": "^2.0
|
|
29
|
-
"eslint-config-pluv": "^2.0
|
|
28
|
+
"@pluv/tsconfig": "^2.2.0",
|
|
29
|
+
"eslint-config-pluv": "^2.2.0"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|