@pluv/client 0.40.2 → 0.41.1
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 +23 -0
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +207 -83
- package/dist/index.mjs +207 -83
- package/package.json +7 -7
- package/src/AbstractRoom.ts +4 -1
- package/src/MockedRoom.ts +11 -4
- package/src/OtherNotifier.ts +21 -18
- package/src/PluvRoom.ts +83 -36
- package/src/UsersManager.ts +209 -53
- package/src/constants.ts +1 -0
- package/src/types.ts +1 -1
package/dist/index.mjs
CHANGED
|
@@ -192,24 +192,27 @@ var EventNotifier = class {
|
|
|
192
192
|
import { makeSubject as makeSubject3, subscribe as subscribe3 } from "wonka";
|
|
193
193
|
var OtherNotifier = class {
|
|
194
194
|
constructor() {
|
|
195
|
-
this.
|
|
195
|
+
this._subjects = /* @__PURE__ */ new Map();
|
|
196
196
|
}
|
|
197
197
|
clear() {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
this.subject(connectionId).next(null);
|
|
201
|
-
this.subjects.delete(connectionId);
|
|
198
|
+
this._subjects.forEach((subject) => {
|
|
199
|
+
subject.next(null);
|
|
202
200
|
});
|
|
201
|
+
this._subjects.clear();
|
|
203
202
|
}
|
|
204
|
-
|
|
205
|
-
|
|
203
|
+
delete(clientId) {
|
|
204
|
+
this.subject(clientId).next(null);
|
|
205
|
+
this._subjects.delete(clientId);
|
|
206
|
+
}
|
|
207
|
+
subject(clientId) {
|
|
208
|
+
const subject = this._subjects.get(clientId);
|
|
206
209
|
if (subject) return subject;
|
|
207
210
|
const newSubject = makeSubject3();
|
|
208
|
-
this.
|
|
211
|
+
this._subjects.set(clientId, newSubject);
|
|
209
212
|
return newSubject;
|
|
210
213
|
}
|
|
211
|
-
subscribe(
|
|
212
|
-
const source = this.subject(
|
|
214
|
+
subscribe(clientId, callback) {
|
|
215
|
+
const source = this.subject(clientId).source;
|
|
213
216
|
return subscribe3(callback)(source).unsubscribe;
|
|
214
217
|
}
|
|
215
218
|
};
|
|
@@ -283,9 +286,16 @@ var StorageStore = class extends AbstractStorageStore {
|
|
|
283
286
|
}
|
|
284
287
|
};
|
|
285
288
|
|
|
289
|
+
// src/constants.ts
|
|
290
|
+
var MAX_PRESENCE_SIZE_BYTES = 512;
|
|
291
|
+
|
|
286
292
|
// src/UsersManager.ts
|
|
287
293
|
var UsersManager = class {
|
|
288
294
|
constructor(config) {
|
|
295
|
+
this._idMap = {
|
|
296
|
+
fromConnectionId: /* @__PURE__ */ new Map(),
|
|
297
|
+
fromClientId: /* @__PURE__ */ new Map()
|
|
298
|
+
};
|
|
289
299
|
/**
|
|
290
300
|
* @description This is only set when the user is connected.
|
|
291
301
|
*/
|
|
@@ -303,74 +313,154 @@ var UsersManager = class {
|
|
|
303
313
|
get myself() {
|
|
304
314
|
return this._myself;
|
|
305
315
|
}
|
|
306
|
-
|
|
316
|
+
addConnection(userInfo) {
|
|
317
|
+
var _a;
|
|
318
|
+
const data = __spreadProps(__spreadValues({}, userInfo), {
|
|
319
|
+
presence: (_a = userInfo.presence) != null ? _a : this._initialPresence
|
|
320
|
+
});
|
|
321
|
+
const myClientId = !!this._myself ? this.getClientId(this._myself) : null;
|
|
322
|
+
const clientId = this.getClientId(data);
|
|
323
|
+
const remaining = this._setConnectionId(userInfo.connectionId, clientId).size;
|
|
324
|
+
if (myClientId === clientId) {
|
|
325
|
+
const result2 = {
|
|
326
|
+
clientId,
|
|
327
|
+
data,
|
|
328
|
+
isMyself: true,
|
|
329
|
+
remaining
|
|
330
|
+
};
|
|
331
|
+
return result2;
|
|
332
|
+
}
|
|
333
|
+
const other = this._others.get(clientId);
|
|
334
|
+
if (!other) this._others.set(clientId, data);
|
|
335
|
+
const result = {
|
|
336
|
+
clientId,
|
|
337
|
+
data,
|
|
338
|
+
isMyself: false,
|
|
339
|
+
remaining
|
|
340
|
+
};
|
|
341
|
+
return result;
|
|
342
|
+
}
|
|
343
|
+
clearConnections() {
|
|
344
|
+
this.removeMyself();
|
|
307
345
|
this._others.clear();
|
|
346
|
+
this._idMap.fromClientId.clear();
|
|
347
|
+
this._idMap.fromConnectionId.clear();
|
|
348
|
+
}
|
|
349
|
+
deleteConnection(connectionId) {
|
|
350
|
+
var _a, _b, _c;
|
|
351
|
+
const clientId = this.getClientId(connectionId);
|
|
352
|
+
this._deleteConnectionId(connectionId);
|
|
353
|
+
if (!clientId) return null;
|
|
354
|
+
const userInfo = (_a = this._others.get(clientId)) != null ? _a : null;
|
|
355
|
+
if (!userInfo) return null;
|
|
356
|
+
const remaining = (_c = (_b = this._getConnectionIds(clientId)) == null ? void 0 : _b.size) != null ? _c : 0;
|
|
357
|
+
const result = { clientId, remaining, data: userInfo };
|
|
358
|
+
if (!remaining) this._others.delete(clientId);
|
|
359
|
+
return result;
|
|
360
|
+
}
|
|
361
|
+
getClientId(input) {
|
|
362
|
+
var _a, _b, _c, _d;
|
|
363
|
+
if (typeof input !== "string") {
|
|
364
|
+
const userInfo = input;
|
|
365
|
+
const connectionId2 = userInfo.connectionId;
|
|
366
|
+
const userId = (_b = (_a = userInfo.user) == null ? void 0 : _a.id) != null ? _b : null;
|
|
367
|
+
return userId != null ? userId : connectionId2;
|
|
368
|
+
}
|
|
369
|
+
const connectionId = input;
|
|
370
|
+
if (((_c = this._myself) == null ? void 0 : _c.connectionId) === connectionId) {
|
|
371
|
+
return this.getClientId(this._myself);
|
|
372
|
+
}
|
|
373
|
+
const clientId = (_d = this._idMap.fromConnectionId.get(connectionId)) != null ? _d : null;
|
|
374
|
+
return clientId;
|
|
308
375
|
}
|
|
309
376
|
getOther(connectionId) {
|
|
310
377
|
var _a;
|
|
311
|
-
|
|
378
|
+
const clientId = this.getClientId(connectionId);
|
|
379
|
+
if (!clientId) return null;
|
|
380
|
+
return (_a = this._others.get(clientId)) != null ? _a : null;
|
|
312
381
|
}
|
|
313
382
|
getOthers() {
|
|
314
383
|
return Array.from(this._others.values());
|
|
315
384
|
}
|
|
316
385
|
patchPresence(connectionId, patch) {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
if (!other) return;
|
|
386
|
+
const clientId = this.getClientId(connectionId);
|
|
387
|
+
const myClientId = !!this._myself ? this.getClientId(this._myself) : null;
|
|
388
|
+
if (!clientId) return null;
|
|
389
|
+
if (myClientId === clientId) return this.updateMyPresence(patch);
|
|
390
|
+
const other = this._others.get(clientId);
|
|
391
|
+
if (!other) return null;
|
|
324
392
|
const presence = __spreadValues(__spreadValues({}, other.presence), patch);
|
|
325
|
-
|
|
326
|
-
this._others.set(
|
|
393
|
+
const validated = this._presence ? this._presence.parse(presence) : presence;
|
|
394
|
+
this._others.set(clientId, __spreadProps(__spreadValues({}, other), { presence: validated }));
|
|
395
|
+
return validated;
|
|
327
396
|
}
|
|
328
397
|
removeMyself() {
|
|
398
|
+
if (!this._myself) return;
|
|
399
|
+
const connectionId = this._myself.connectionId;
|
|
400
|
+
this._deleteConnectionId(connectionId);
|
|
329
401
|
this._myself = null;
|
|
330
402
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
this.
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
this.
|
|
339
|
-
connectionId,
|
|
340
|
-
presence: this._initialPresence,
|
|
341
|
-
user
|
|
342
|
-
};
|
|
343
|
-
this._myPresence = this._initialPresence;
|
|
403
|
+
setMyself(userInfo) {
|
|
404
|
+
var _a;
|
|
405
|
+
const connectionId = userInfo.connectionId;
|
|
406
|
+
const presence = (_a = userInfo.presence) != null ? _a : this._initialPresence;
|
|
407
|
+
this._myself = __spreadProps(__spreadValues({}, userInfo), { presence });
|
|
408
|
+
this._myPresence = presence;
|
|
409
|
+
const clientId = this.getClientId(this._myself);
|
|
410
|
+
this._setConnectionId(connectionId, clientId);
|
|
344
411
|
}
|
|
345
412
|
setPresence(connectionId, presence) {
|
|
346
|
-
|
|
347
|
-
|
|
413
|
+
const clientId = this.getClientId(connectionId);
|
|
414
|
+
const myClientId = !!this._myself ? this.getClientId(this._myself) : null;
|
|
415
|
+
if (!clientId) return;
|
|
416
|
+
if (myClientId === clientId) {
|
|
417
|
+
if (!this._myself) return;
|
|
348
418
|
this._myself.presence = presence;
|
|
349
419
|
this._myPresence = presence;
|
|
350
420
|
return;
|
|
351
421
|
}
|
|
352
|
-
const other = this._others.get(
|
|
422
|
+
const other = this._others.get(clientId);
|
|
353
423
|
if (!other) return;
|
|
354
|
-
this._others.set(
|
|
355
|
-
}
|
|
356
|
-
setUser(connectionId, user, presence) {
|
|
357
|
-
var _a;
|
|
358
|
-
if (((_a = this._myself) == null ? void 0 : _a.connectionId) === connectionId) return;
|
|
359
|
-
const other = this._others.get(connectionId);
|
|
360
|
-
if (other) return;
|
|
361
|
-
this._others.set(connectionId, {
|
|
362
|
-
connectionId,
|
|
363
|
-
presence: presence != null ? presence : this._initialPresence,
|
|
364
|
-
user
|
|
365
|
-
});
|
|
424
|
+
this._others.set(clientId, __spreadProps(__spreadValues({}, other), { presence }));
|
|
366
425
|
}
|
|
367
426
|
/**
|
|
368
427
|
* @description This method need not care about being connected.
|
|
369
428
|
*/
|
|
370
429
|
updateMyPresence(patch) {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
430
|
+
const updated = __spreadValues(__spreadValues({}, this._myPresence), patch);
|
|
431
|
+
const bytes = new TextEncoder().encode(JSON.stringify(updated)).length;
|
|
432
|
+
if (bytes > MAX_PRESENCE_SIZE_BYTES) {
|
|
433
|
+
throw new Error(
|
|
434
|
+
`Large presence. Presence must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
this._myPresence = updated;
|
|
438
|
+
if (!this._myself) return updated;
|
|
439
|
+
this._myself.presence = updated;
|
|
440
|
+
return updated;
|
|
441
|
+
}
|
|
442
|
+
_deleteConnectionId(connectionId) {
|
|
443
|
+
var _a;
|
|
444
|
+
const clientId = this.getClientId(connectionId);
|
|
445
|
+
this._idMap.fromConnectionId.delete(connectionId);
|
|
446
|
+
if (!clientId) return;
|
|
447
|
+
const set = (_a = this._idMap.fromClientId.get(clientId)) != null ? _a : null;
|
|
448
|
+
if (!set) return;
|
|
449
|
+
set.delete(connectionId);
|
|
450
|
+
if (!!set.size) return;
|
|
451
|
+
this._idMap.fromClientId.delete(clientId);
|
|
452
|
+
}
|
|
453
|
+
_getConnectionIds(clientId) {
|
|
454
|
+
const set = this._idMap.fromClientId.get(clientId);
|
|
455
|
+
return set != null ? set : null;
|
|
456
|
+
}
|
|
457
|
+
_setConnectionId(connectionId, clientId) {
|
|
458
|
+
var _a;
|
|
459
|
+
const set = (_a = this._idMap.fromClientId.get(clientId)) != null ? _a : /* @__PURE__ */ new Set();
|
|
460
|
+
const updated = set.add(connectionId);
|
|
461
|
+
this._idMap.fromConnectionId.set(connectionId, clientId);
|
|
462
|
+
this._idMap.fromClientId.set(clientId, updated);
|
|
463
|
+
return updated;
|
|
374
464
|
}
|
|
375
465
|
};
|
|
376
466
|
|
|
@@ -536,7 +626,9 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
536
626
|
return sharedType;
|
|
537
627
|
};
|
|
538
628
|
this.other = (connectionId, callback) => {
|
|
539
|
-
|
|
629
|
+
const clientId = this._usersManager.getClientId(connectionId);
|
|
630
|
+
if (!clientId) return () => void 0;
|
|
631
|
+
return this._otherNotifier.subscribe(clientId, callback);
|
|
540
632
|
};
|
|
541
633
|
this.redo = () => {
|
|
542
634
|
this._crdtManager.doc.redo();
|
|
@@ -568,7 +660,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
568
660
|
const myPresence = this._usersManager.myPresence;
|
|
569
661
|
const myself = (_a = this._usersManager.myself) != null ? _a : null;
|
|
570
662
|
this._stateNotifier.subjects["my-presence"].next(myPresence);
|
|
571
|
-
!!myself
|
|
663
|
+
if (!!myself) this._stateNotifier.subjects.myself.next(myself);
|
|
572
664
|
this.broadcast(
|
|
573
665
|
"$updatePresence",
|
|
574
666
|
{ presence: newPresence }
|
|
@@ -638,8 +730,8 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
638
730
|
try {
|
|
639
731
|
const publicKey = this._getPublicKey(params);
|
|
640
732
|
authToken = yield this._getAuthorization(this.id, params);
|
|
641
|
-
authToken
|
|
642
|
-
publicKey
|
|
733
|
+
if (authToken) url.searchParams.set("token", encodeURIComponent(authToken));
|
|
734
|
+
if (publicKey) url.searchParams.set("public_key", encodeURIComponent(publicKey));
|
|
643
735
|
webSocket = new WebSocket(url.toString());
|
|
644
736
|
} catch (err) {
|
|
645
737
|
this._updateState((oldState) => {
|
|
@@ -750,7 +842,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
750
842
|
this._clearTimeout(this._timeouts.pong);
|
|
751
843
|
this._detachWindowListeners();
|
|
752
844
|
this._usersManager.removeMyself();
|
|
753
|
-
this._usersManager.
|
|
845
|
+
this._usersManager.clearConnections();
|
|
754
846
|
this._otherNotifier.clear();
|
|
755
847
|
this._stateNotifier.subjects.myself.next(null);
|
|
756
848
|
this._stateNotifier.subjects.others.next([]);
|
|
@@ -838,11 +930,11 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
838
930
|
const { connectionId } = message;
|
|
839
931
|
if (!connectionId) return;
|
|
840
932
|
if (!this._state.webSocket) throw new Error("Could not find WebSocket");
|
|
841
|
-
this._usersManager.
|
|
933
|
+
const clientId = this._usersManager.getClientId(connectionId);
|
|
934
|
+
const deleted = this._usersManager.deleteConnection(connectionId);
|
|
842
935
|
const others = this._usersManager.getOthers();
|
|
843
936
|
this._stateNotifier.subjects.others.next(others);
|
|
844
|
-
this._otherNotifier.
|
|
845
|
-
this._otherNotifier.subjects.delete(connectionId);
|
|
937
|
+
if (!(deleted == null ? void 0 : deleted.remaining) && !!clientId) this._otherNotifier.delete(clientId);
|
|
846
938
|
}
|
|
847
939
|
_handlePresenceUpdatedMessage(message) {
|
|
848
940
|
var _a;
|
|
@@ -852,11 +944,18 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
852
944
|
const data = message.data;
|
|
853
945
|
const myself = (_a = this._usersManager.myself) != null ? _a : null;
|
|
854
946
|
if ((myself == null ? void 0 : myself.connectionId) === connectionId) return;
|
|
855
|
-
this._usersManager.patchPresence(connectionId, data.presence);
|
|
947
|
+
const updated = this._usersManager.patchPresence(connectionId, data.presence);
|
|
948
|
+
const myClientId = !!myself ? this._usersManager.getClientId(myself) : null;
|
|
949
|
+
const clientId = this._usersManager.getClientId(connectionId);
|
|
950
|
+
if (!!clientId && myClientId === clientId) {
|
|
951
|
+
this._stateNotifier.subjects["my-presence"].next(updated);
|
|
952
|
+
this._stateNotifier.subjects.myself.next(this._usersManager.myself);
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
856
955
|
const other = this._usersManager.getOther(connectionId);
|
|
857
956
|
const others = this._usersManager.getOthers();
|
|
858
|
-
this._otherNotifier.subject(
|
|
859
|
-
this._stateNotifier.subjects
|
|
957
|
+
if (!!clientId) this._otherNotifier.subject(clientId).next(other);
|
|
958
|
+
this._stateNotifier.subjects.others.next(others);
|
|
860
959
|
}
|
|
861
960
|
_handleReceiveOthers(message) {
|
|
862
961
|
if (!message.connectionId) return;
|
|
@@ -864,31 +963,44 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
864
963
|
const data = message.data;
|
|
865
964
|
Object.keys(data.others).forEach((connectionId) => {
|
|
866
965
|
const { presence, user } = data.others[connectionId];
|
|
867
|
-
this._usersManager.
|
|
966
|
+
const result = this._usersManager.addConnection({
|
|
967
|
+
connectionId,
|
|
968
|
+
presence: presence != null ? presence : void 0,
|
|
969
|
+
user
|
|
970
|
+
});
|
|
971
|
+
if (!!presence) this._usersManager.patchPresence(connectionId, presence);
|
|
972
|
+
if (result.isMyself) return;
|
|
973
|
+
const clientId = result.clientId;
|
|
868
974
|
const other = this._usersManager.getOther(connectionId);
|
|
869
|
-
|
|
870
|
-
this._otherNotifier.subject(connectionId).next(other);
|
|
975
|
+
this._otherNotifier.subject(clientId).next(other);
|
|
871
976
|
});
|
|
872
977
|
const others = this._usersManager.getOthers();
|
|
873
|
-
this._stateNotifier.subjects
|
|
978
|
+
this._stateNotifier.subjects.others.next(others);
|
|
874
979
|
}
|
|
875
980
|
_handleRegisteredMessage(message) {
|
|
876
|
-
var _a, _b;
|
|
877
|
-
const { connectionId
|
|
981
|
+
var _a, _b, _c;
|
|
982
|
+
const { connectionId } = message;
|
|
983
|
+
const user = message.user;
|
|
878
984
|
if (!connectionId) return;
|
|
879
985
|
if (!this._state.webSocket) throw new Error("Could not find WebSocket");
|
|
986
|
+
const data = message.data;
|
|
880
987
|
this._updateState((oldState) => {
|
|
881
988
|
oldState.connection.count += 1;
|
|
882
989
|
oldState.connection.id = connectionId;
|
|
883
990
|
oldState.authorization.user = user != null ? user : null;
|
|
884
991
|
return oldState;
|
|
885
992
|
});
|
|
886
|
-
|
|
993
|
+
const userInfo = {
|
|
994
|
+
connectionId,
|
|
995
|
+
presence: (_a = data.presence) != null ? _a : void 0,
|
|
996
|
+
user
|
|
997
|
+
};
|
|
998
|
+
this._usersManager.setMyself(userInfo);
|
|
887
999
|
const presence = this._usersManager.myPresence;
|
|
888
|
-
const myself = (
|
|
1000
|
+
const myself = (_b = this._usersManager.myself) != null ? _b : null;
|
|
889
1001
|
this._stateNotifier.subjects["my-presence"].next(presence);
|
|
890
|
-
this._stateNotifier.subjects
|
|
891
|
-
const update = this._state.connection.count > 1 ? (
|
|
1002
|
+
this._stateNotifier.subjects.myself.next(myself);
|
|
1003
|
+
const update = this._state.connection.count > 1 ? (_c = this._crdtManager.doc.getEncodedState()) != null ? _c : null : null;
|
|
892
1004
|
this._sendMessage({
|
|
893
1005
|
type: "$initializeSession",
|
|
894
1006
|
data: { presence, update }
|
|
@@ -943,6 +1055,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
943
1055
|
this._crdtNotifier.rootSubject.next(storageRoot);
|
|
944
1056
|
}
|
|
945
1057
|
_handleUserJoinedMessage(message) {
|
|
1058
|
+
var _a;
|
|
946
1059
|
const { connectionId } = message;
|
|
947
1060
|
if (!connectionId) return;
|
|
948
1061
|
if (!this._state.webSocket) throw new Error("Could not find WebSocket");
|
|
@@ -951,12 +1064,18 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
951
1064
|
const myself = this._usersManager.myself;
|
|
952
1065
|
if (myself.connectionId === connectionId) {
|
|
953
1066
|
this._sendMessage({ type: "$getOthers", data: {} });
|
|
1067
|
+
return;
|
|
954
1068
|
}
|
|
955
|
-
this._usersManager.
|
|
1069
|
+
const result = this._usersManager.addConnection({
|
|
1070
|
+
connectionId,
|
|
1071
|
+
presence: data.presence,
|
|
1072
|
+
user: data.user
|
|
1073
|
+
});
|
|
1074
|
+
const clientId = (_a = result == null ? void 0 : result.clientId) != null ? _a : null;
|
|
956
1075
|
const other = this._usersManager.getOther(connectionId);
|
|
957
1076
|
const others = this._usersManager.getOthers();
|
|
958
|
-
this._otherNotifier.subject(
|
|
959
|
-
this._stateNotifier.subjects
|
|
1077
|
+
if (!!clientId) this._otherNotifier.subject(clientId).next(other);
|
|
1078
|
+
this._stateNotifier.subjects.others.next(others);
|
|
960
1079
|
}
|
|
961
1080
|
_heartbeat() {
|
|
962
1081
|
this._clearTimeout(this._timeouts.pong);
|
|
@@ -966,7 +1085,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
966
1085
|
_logDebug(...data) {
|
|
967
1086
|
var _a;
|
|
968
1087
|
if (((_a = process == null ? void 0 : process.env) == null ? void 0 : _a.NODE_ENV) === "production") return;
|
|
969
|
-
this._debug
|
|
1088
|
+
if (this._debug) console.log(...data);
|
|
970
1089
|
}
|
|
971
1090
|
_observeCrdt() {
|
|
972
1091
|
var _a, _b;
|
|
@@ -1001,7 +1120,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1001
1120
|
_onClose(event) {
|
|
1002
1121
|
return __async(this, null, function* () {
|
|
1003
1122
|
this._logDebug("WebSocket closed");
|
|
1004
|
-
!!event.reason
|
|
1123
|
+
if (!!event.reason) this._logDebug(event.reason);
|
|
1005
1124
|
const shouldRetry = [
|
|
1006
1125
|
// Going away: Client/server is shutting down or navigating
|
|
1007
1126
|
1001,
|
|
@@ -1016,15 +1135,18 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1016
1135
|
// Bad gateway
|
|
1017
1136
|
1014
|
|
1018
1137
|
].some((okToRetryCode) => event.code === okToRetryCode);
|
|
1019
|
-
this._closeWs();
|
|
1020
|
-
if (!shouldRetry) this._clearTimeout(this._timeouts.reconnect);
|
|
1021
|
-
else this._pollReconnect();
|
|
1022
1138
|
this._updateState((oldState) => {
|
|
1023
1139
|
oldState.authorization.token = null;
|
|
1024
1140
|
oldState.connection.state = shouldRetry ? "Unavailable" /* Unavailable */ : "Closed" /* Closed */;
|
|
1025
1141
|
oldState.webSocket = null;
|
|
1026
1142
|
return oldState;
|
|
1027
1143
|
});
|
|
1144
|
+
if (shouldRetry) {
|
|
1145
|
+
yield this._reconnect();
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
this._closeWs();
|
|
1149
|
+
this._clearTimeout(this._timeouts.reconnect);
|
|
1028
1150
|
});
|
|
1029
1151
|
}
|
|
1030
1152
|
/**
|
|
@@ -1373,7 +1495,9 @@ var MockedRoom = class extends AbstractRoom {
|
|
|
1373
1495
|
return sharedType;
|
|
1374
1496
|
};
|
|
1375
1497
|
this.other = (connectionId, callback) => {
|
|
1376
|
-
|
|
1498
|
+
const clientId = this._usersManager.getClientId(connectionId);
|
|
1499
|
+
if (!clientId) return () => void 0;
|
|
1500
|
+
return this._otherNotifier.subscribe(clientId, callback);
|
|
1377
1501
|
};
|
|
1378
1502
|
this.redo = () => {
|
|
1379
1503
|
this._crdtManager.doc.redo();
|
|
@@ -1407,7 +1531,7 @@ var MockedRoom = class extends AbstractRoom {
|
|
|
1407
1531
|
const myPresence = this._usersManager.myPresence;
|
|
1408
1532
|
const myself = (_a = this._usersManager.myself) != null ? _a : null;
|
|
1409
1533
|
this._stateNotifier.subjects["my-presence"].next(myPresence);
|
|
1410
|
-
!!myself
|
|
1534
|
+
if (!!myself) this._stateNotifier.subjects["myself"].next(myself);
|
|
1411
1535
|
};
|
|
1412
1536
|
this._events = events;
|
|
1413
1537
|
this._router = router != null ? router : new PluvRouter({});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.1",
|
|
4
4
|
"description": "@pluv/io frontend client",
|
|
5
5
|
"author": "leedavidcs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,20 +18,20 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"wonka": "^6.3.5",
|
|
21
|
-
"@pluv/crdt": "^0.
|
|
22
|
-
"@pluv/types": "^0.
|
|
21
|
+
"@pluv/crdt": "^0.41.1",
|
|
22
|
+
"@pluv/types": "^0.41.1"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"eslint": "^9.
|
|
25
|
+
"eslint": "^9.25.0",
|
|
26
26
|
"tsup": "^8.4.0",
|
|
27
27
|
"typescript": "^5.8.3",
|
|
28
|
-
"@pluv/tsconfig": "^0.
|
|
29
|
-
"eslint-config-pluv": "^0.
|
|
28
|
+
"@pluv/tsconfig": "^0.41.1",
|
|
29
|
+
"eslint-config-pluv": "^0.41.1"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
33
33
|
"dev": "tsup src/index.ts --format esm,cjs --watch --dts",
|
|
34
|
-
"lint": "eslint src/**/*.ts
|
|
34
|
+
"lint": "eslint \"src/**/*.ts*\" --fix --max-warnings 0",
|
|
35
35
|
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
|
36
36
|
}
|
|
37
37
|
}
|
package/src/AbstractRoom.ts
CHANGED
|
@@ -51,7 +51,10 @@ export abstract class AbstractRoom<
|
|
|
51
51
|
public abstract getStorageJson(): InferCrdtJson<TStorage> | null;
|
|
52
52
|
public abstract getStorageJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]> | null;
|
|
53
53
|
|
|
54
|
-
public abstract other(
|
|
54
|
+
public abstract other(
|
|
55
|
+
connectionId: string,
|
|
56
|
+
callback: OtherNotifierSubscriptionCallback<TIO, TPresence>,
|
|
57
|
+
): () => void;
|
|
55
58
|
|
|
56
59
|
public abstract redo(): void;
|
|
57
60
|
|
package/src/MockedRoom.ts
CHANGED
|
@@ -51,7 +51,7 @@ export class MockedRoom<
|
|
|
51
51
|
private _crdtNotifier = new CrdtNotifier<TStorage>();
|
|
52
52
|
private _eventNotifier = new EventNotifier<MergeEvents<TEvents, TIO>>();
|
|
53
53
|
private _events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;
|
|
54
|
-
private _otherNotifier = new OtherNotifier<TIO>();
|
|
54
|
+
private _otherNotifier = new OtherNotifier<TIO, TPresence>();
|
|
55
55
|
private _router: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
56
56
|
private _state: WebSocketState<TIO> = {
|
|
57
57
|
authorization: {
|
|
@@ -226,8 +226,15 @@ export class MockedRoom<
|
|
|
226
226
|
return this._crdtManager.doc.toJson(type);
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
-
public other = (
|
|
230
|
-
|
|
229
|
+
public other = (
|
|
230
|
+
connectionId: string,
|
|
231
|
+
callback: OtherNotifierSubscriptionCallback<TIO, TPresence>,
|
|
232
|
+
): (() => void) => {
|
|
233
|
+
const clientId = this._usersManager.getClientId(connectionId);
|
|
234
|
+
|
|
235
|
+
if (!clientId) return () => undefined;
|
|
236
|
+
|
|
237
|
+
return this._otherNotifier.subscribe(clientId, callback);
|
|
231
238
|
};
|
|
232
239
|
|
|
233
240
|
public redo = (): void => {
|
|
@@ -290,7 +297,7 @@ export class MockedRoom<
|
|
|
290
297
|
const myself = this._usersManager.myself ?? null;
|
|
291
298
|
|
|
292
299
|
this._stateNotifier.subjects["my-presence"].next(myPresence);
|
|
293
|
-
!!myself
|
|
300
|
+
if (!!myself) this._stateNotifier.subjects["myself"].next(myself);
|
|
294
301
|
};
|
|
295
302
|
|
|
296
303
|
private _observeCrdt(): void {
|
package/src/OtherNotifier.ts
CHANGED
|
@@ -1,39 +1,42 @@
|
|
|
1
|
-
import type { Id, IOLike } from "@pluv/types";
|
|
1
|
+
import type { Id, IOLike, JsonObject } from "@pluv/types";
|
|
2
2
|
import type { Subject } from "wonka";
|
|
3
3
|
import { makeSubject, subscribe } from "wonka";
|
|
4
4
|
import type { UserInfo } from "./types";
|
|
5
5
|
|
|
6
|
-
export type OtherNotifierSubscriptionCallback<TIO extends IOLike> = (
|
|
6
|
+
export type OtherNotifierSubscriptionCallback<TIO extends IOLike, TPresence extends JsonObject> = (
|
|
7
|
+
value: Id<UserInfo<TIO, TPresence>> | null,
|
|
8
|
+
) => void;
|
|
7
9
|
|
|
8
|
-
export class OtherNotifier<TIO extends IOLike> {
|
|
9
|
-
|
|
10
|
+
export class OtherNotifier<TIO extends IOLike, TPresence extends JsonObject = {}> {
|
|
11
|
+
private _subjects = new Map<[clientId: string][0], Subject<Id<UserInfo<TIO, TPresence>> | null>>();
|
|
10
12
|
|
|
11
13
|
public clear(): void {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
connectionIds.forEach((connectionId) => {
|
|
15
|
-
this.subject(connectionId).next(null);
|
|
16
|
-
this.subjects.delete(connectionId);
|
|
14
|
+
this._subjects.forEach((subject) => {
|
|
15
|
+
subject.next(null);
|
|
17
16
|
});
|
|
17
|
+
|
|
18
|
+
this._subjects.clear();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public delete(clientId: string): void {
|
|
22
|
+
this.subject(clientId).next(null);
|
|
23
|
+
this._subjects.delete(clientId);
|
|
18
24
|
}
|
|
19
25
|
|
|
20
|
-
public subject
|
|
21
|
-
const subject = this.
|
|
26
|
+
public subject(clientId: string): Subject<Id<UserInfo<TIO, TPresence>> | null> {
|
|
27
|
+
const subject = this._subjects.get(clientId);
|
|
22
28
|
|
|
23
29
|
if (subject) return subject;
|
|
24
30
|
|
|
25
|
-
const newSubject = makeSubject<Id<UserInfo<TIO>>>();
|
|
31
|
+
const newSubject = makeSubject<Id<UserInfo<TIO, TPresence>>>();
|
|
26
32
|
|
|
27
|
-
this.
|
|
33
|
+
this._subjects.set(clientId, newSubject);
|
|
28
34
|
|
|
29
35
|
return newSubject;
|
|
30
36
|
}
|
|
31
37
|
|
|
32
|
-
public subscribe<
|
|
33
|
-
|
|
34
|
-
callback: OtherNotifierSubscriptionCallback<TIO>,
|
|
35
|
-
): () => void {
|
|
36
|
-
const source = this.subject(name).source;
|
|
38
|
+
public subscribe(clientId: string, callback: OtherNotifierSubscriptionCallback<TIO, TPresence>): () => void {
|
|
39
|
+
const source = this.subject(clientId).source;
|
|
37
40
|
|
|
38
41
|
return subscribe(callback)(source).unsubscribe;
|
|
39
42
|
}
|