@pluv/client 0.38.14 → 0.39.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 +75 -0
- package/dist/index.d.mts +132 -115
- package/dist/index.d.ts +132 -115
- package/dist/index.js +97 -69
- package/dist/index.mjs +97 -69
- package/eslint.config.mjs +4 -0
- package/package.json +7 -7
- package/src/MockedRoom.ts +1 -0
- package/src/PluvClient.ts +25 -11
- package/src/PluvRoom.ts +133 -76
- package/src/index.ts +10 -3
- package/src/types.ts +21 -0
- package/.eslintrc.js +0 -4
package/dist/index.mjs
CHANGED
|
@@ -407,7 +407,9 @@ var debounce = (fn, options) => {
|
|
|
407
407
|
var ADD_TO_STORAGE_STATE_DEBOUNCE_MS = 1e3;
|
|
408
408
|
var HEARTBEAT_INTERVAL_MS = 1e4;
|
|
409
409
|
var PONG_TIMEOUT_MS = 2e3;
|
|
410
|
-
var RECONNECT_TIMEOUT_MS =
|
|
410
|
+
var RECONNECT_TIMEOUT_MS = 5e3;
|
|
411
|
+
var MIN_RECONNECT_TIMEOUT_MS = 1e3;
|
|
412
|
+
var MAX_RECONNECT_TIMEOUT_MS = 6e4;
|
|
411
413
|
var ORIGIN_INITIALIZED = "$initialized";
|
|
412
414
|
var ORIGIN_STORAGE_UPDATED = "$storageUpdated";
|
|
413
415
|
var DEFAULT_PLUV_CLIENT_ADDON = (input) => ({
|
|
@@ -425,6 +427,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
425
427
|
onAuthorizationFail,
|
|
426
428
|
presence,
|
|
427
429
|
publicKey,
|
|
430
|
+
reconnectTimeoutMs = RECONNECT_TIMEOUT_MS,
|
|
428
431
|
router,
|
|
429
432
|
wsEndpoint
|
|
430
433
|
} = options;
|
|
@@ -434,7 +437,6 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
434
437
|
this._intervals = {
|
|
435
438
|
heartbeat: null
|
|
436
439
|
};
|
|
437
|
-
this._metadata = {};
|
|
438
440
|
this._otherNotifier = new OtherNotifier();
|
|
439
441
|
this._publicKey = null;
|
|
440
442
|
this._stateNotifier = new StateNotifier();
|
|
@@ -445,12 +447,14 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
445
447
|
pong: null,
|
|
446
448
|
reconnect: null
|
|
447
449
|
};
|
|
450
|
+
this._lastMetadata = null;
|
|
448
451
|
this._state = {
|
|
449
452
|
authorization: {
|
|
450
453
|
token: null,
|
|
451
454
|
user: null
|
|
452
455
|
},
|
|
453
456
|
connection: {
|
|
457
|
+
attempts: 0,
|
|
454
458
|
count: 0,
|
|
455
459
|
id: null,
|
|
456
460
|
state: "Untouched" /* Untouched */
|
|
@@ -589,18 +593,14 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
589
593
|
};
|
|
590
594
|
const addon = this._getAddon(addons);
|
|
591
595
|
const { storage } = __spreadValues(__spreadValues({}, DEFAULT_PLUV_CLIENT_ADDON({ room: this })), addon({ room: this }));
|
|
596
|
+
this.metadata = metadata;
|
|
592
597
|
this._debug = debug;
|
|
593
598
|
this._endpoints = { authEndpoint, wsEndpoint };
|
|
599
|
+
this._reconnectTimeoutMs = reconnectTimeoutMs;
|
|
594
600
|
this._storageStore = storage;
|
|
595
|
-
if (typeof metadata !== "undefined") this._metadata = metadata;
|
|
596
601
|
if (!!publicKey) this._publicKey = publicKey;
|
|
597
602
|
this._listeners = {
|
|
598
603
|
onAuthorizationFail: (error) => {
|
|
599
|
-
this._clearTimeout(this._timeouts.reconnect);
|
|
600
|
-
this._timeouts.reconnect = setTimeout(
|
|
601
|
-
this._reconnect.bind(this),
|
|
602
|
-
RECONNECT_TIMEOUT_MS
|
|
603
|
-
);
|
|
604
604
|
onAuthorizationFail == null ? void 0 : onAuthorizationFail(error);
|
|
605
605
|
}
|
|
606
606
|
};
|
|
@@ -614,11 +614,13 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
614
614
|
get webSocket() {
|
|
615
615
|
return this._state.webSocket;
|
|
616
616
|
}
|
|
617
|
-
connect() {
|
|
617
|
+
connect(...args) {
|
|
618
618
|
return __async(this, null, function* () {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
619
|
+
var _a;
|
|
620
|
+
const params = (_a = args[0]) != null ? _a : {};
|
|
621
|
+
const metadata = params.metadata;
|
|
622
|
+
this._setMetadata(metadata);
|
|
623
|
+
if (!this._endpoints.wsEndpoint) throw new Error("Must provide a wsEndpoint.");
|
|
622
624
|
const canConnect = ["Closed" /* Closed */, "Untouched" /* Untouched */].some(
|
|
623
625
|
(state) => this._state.connection.state === state
|
|
624
626
|
);
|
|
@@ -630,21 +632,27 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
630
632
|
});
|
|
631
633
|
yield this._storageStore.initialize();
|
|
632
634
|
yield this._applyStorageStore();
|
|
633
|
-
const url = new URL(this._getWsEndpoint(this.id));
|
|
635
|
+
const url = new URL(this._getWsEndpoint(this.id, params));
|
|
634
636
|
let authToken = null;
|
|
635
637
|
let webSocket;
|
|
636
638
|
try {
|
|
637
|
-
const publicKey = this._getPublicKey();
|
|
638
|
-
authToken = yield this._getAuthorization(this.id);
|
|
639
|
+
const publicKey = this._getPublicKey(params);
|
|
640
|
+
authToken = yield this._getAuthorization(this.id, params);
|
|
639
641
|
authToken && url.searchParams.set("token", encodeURIComponent(authToken));
|
|
640
642
|
publicKey && url.searchParams.set("public_key", encodeURIComponent(publicKey));
|
|
641
643
|
webSocket = new WebSocket(url.toString());
|
|
642
644
|
} catch (err) {
|
|
645
|
+
this._updateState((oldState) => {
|
|
646
|
+
oldState.connection.attempts += 1;
|
|
647
|
+
return oldState;
|
|
648
|
+
});
|
|
643
649
|
yield this._storageStore.destroy();
|
|
644
|
-
this.
|
|
650
|
+
this._pollReconnect();
|
|
651
|
+
yield Promise.resolve(this._onAuthorizationFail(err));
|
|
645
652
|
return;
|
|
646
653
|
}
|
|
647
654
|
this._updateState((oldState) => {
|
|
655
|
+
oldState.connection.attempts = 0;
|
|
648
656
|
oldState.authorization.token = authToken;
|
|
649
657
|
oldState.webSocket = webSocket;
|
|
650
658
|
return oldState;
|
|
@@ -655,16 +663,21 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
655
663
|
}
|
|
656
664
|
disconnect() {
|
|
657
665
|
return __async(this, null, function* () {
|
|
658
|
-
if (!this._endpoints.wsEndpoint)
|
|
659
|
-
throw new Error("Must provide an wsEndpoint.");
|
|
660
|
-
}
|
|
666
|
+
if (!this._endpoints.wsEndpoint) throw new Error("Must provide a wsEndpoint.");
|
|
661
667
|
if (!this._state.webSocket) return;
|
|
662
668
|
const canDisconnect = ["Connecting" /* Connecting */, "Open" /* Open */].some(
|
|
663
669
|
(state) => this._state.connection.state === state
|
|
664
670
|
);
|
|
665
671
|
if (!canDisconnect) return;
|
|
666
|
-
this._clearInterval(this._intervals.heartbeat);
|
|
667
672
|
this._closeWs();
|
|
673
|
+
this._clearInterval(this._intervals.heartbeat);
|
|
674
|
+
this._clearTimeout(this._timeouts.reconnect);
|
|
675
|
+
this._updateState((oldState) => {
|
|
676
|
+
oldState.authorization.token = null;
|
|
677
|
+
oldState.connection.state = "Closed" /* Closed */;
|
|
678
|
+
oldState.webSocket = null;
|
|
679
|
+
return oldState;
|
|
680
|
+
});
|
|
668
681
|
yield this._storageStore.destroy();
|
|
669
682
|
this._crdtManager.destroy();
|
|
670
683
|
this._stateNotifier.subjects["my-presence"].next(null);
|
|
@@ -701,9 +714,11 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
701
714
|
if (typeof window === "undefined") return;
|
|
702
715
|
if (typeof document === "undefined") return;
|
|
703
716
|
this._windowListeners = {
|
|
717
|
+
onNavigatorOffline: this._onNavigatorOffline.bind(this),
|
|
704
718
|
onNavigatorOnline: this._onNavigatorOnline.bind(this),
|
|
705
719
|
onVisibilityChange: this._onVisibilityChange.bind(this)
|
|
706
720
|
};
|
|
721
|
+
window.addEventListener("offline", this._windowListeners.onNavigatorOffline);
|
|
707
722
|
window.addEventListener("online", this._windowListeners.onNavigatorOnline);
|
|
708
723
|
document.addEventListener("visibilitychange", this._windowListeners.onVisibilityChange);
|
|
709
724
|
}
|
|
@@ -729,24 +744,17 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
729
744
|
clearTimeout(timeout);
|
|
730
745
|
}
|
|
731
746
|
_closeWs() {
|
|
732
|
-
var _a, _b;
|
|
733
|
-
if (!this._state.webSocket) return;
|
|
747
|
+
var _a, _b, _c;
|
|
734
748
|
(_b = (_a = this._subscriptions).observeCrdt) == null ? void 0 : _b.call(_a);
|
|
749
|
+
this._clearInterval(this._intervals.heartbeat);
|
|
735
750
|
this._clearTimeout(this._timeouts.pong);
|
|
736
|
-
this._clearTimeout(this._timeouts.reconnect);
|
|
737
751
|
this._detachWindowListeners();
|
|
738
752
|
this._usersManager.removeMyself();
|
|
739
753
|
this._usersManager.removeUsers();
|
|
740
754
|
this._otherNotifier.clear();
|
|
741
755
|
this._stateNotifier.subjects.myself.next(null);
|
|
742
756
|
this._stateNotifier.subjects.others.next([]);
|
|
743
|
-
|
|
744
|
-
(readyState) => {
|
|
745
|
-
var _a2;
|
|
746
|
-
return readyState === ((_a2 = this._state.webSocket) == null ? void 0 : _a2.readyState);
|
|
747
|
-
}
|
|
748
|
-
);
|
|
749
|
-
if (canClose) this._state.webSocket.close();
|
|
757
|
+
(_c = this._state.webSocket) == null ? void 0 : _c.close();
|
|
750
758
|
this._detachWsListeners();
|
|
751
759
|
}
|
|
752
760
|
_detachWindowListeners() {
|
|
@@ -777,7 +785,8 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
777
785
|
);
|
|
778
786
|
this._crdtNotifier.rootSubject.next(storageRoot);
|
|
779
787
|
}
|
|
780
|
-
_getAuthFetchOptions(room) {
|
|
788
|
+
_getAuthFetchOptions(room, params) {
|
|
789
|
+
const metadata = params.metadata;
|
|
781
790
|
if (typeof this._endpoints.authEndpoint === "undefined") return null;
|
|
782
791
|
if (this._endpoints.authEndpoint === true) {
|
|
783
792
|
return {
|
|
@@ -791,18 +800,16 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
791
800
|
options: {}
|
|
792
801
|
};
|
|
793
802
|
}
|
|
794
|
-
const result = this._endpoints.authEndpoint({ metadata
|
|
803
|
+
const result = this._endpoints.authEndpoint({ metadata, room });
|
|
795
804
|
return typeof result === "string" ? { url: result, options: {} } : result;
|
|
796
805
|
}
|
|
797
|
-
_getAuthorization(room) {
|
|
806
|
+
_getAuthorization(room, params) {
|
|
798
807
|
return __async(this, null, function* () {
|
|
799
|
-
const fetchOptions = this._getAuthFetchOptions(room);
|
|
808
|
+
const fetchOptions = this._getAuthFetchOptions(room, params);
|
|
800
809
|
if (!fetchOptions) return null;
|
|
801
810
|
const { url, options } = fetchOptions;
|
|
802
811
|
const res = yield fetch(url, options);
|
|
803
|
-
if (!res.ok || res.status !== 200)
|
|
804
|
-
throw new Error("Room is unauthorized");
|
|
805
|
-
}
|
|
812
|
+
if (!res.ok || res.status !== 200) throw new Error("Room is unauthorized");
|
|
806
813
|
try {
|
|
807
814
|
return yield res.text().then((text) => text.trim());
|
|
808
815
|
} catch (err) {
|
|
@@ -810,19 +817,21 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
810
817
|
}
|
|
811
818
|
});
|
|
812
819
|
}
|
|
813
|
-
_getPublicKey() {
|
|
820
|
+
_getPublicKey(params) {
|
|
821
|
+
const metadata = params.metadata;
|
|
814
822
|
if (!this._publicKey) return null;
|
|
815
823
|
if (typeof this._publicKey === "string") return this._publicKey;
|
|
816
|
-
return this._publicKey({ metadata
|
|
824
|
+
return this._publicKey({ metadata });
|
|
817
825
|
}
|
|
818
|
-
_getWsEndpoint(room) {
|
|
826
|
+
_getWsEndpoint(room, params) {
|
|
827
|
+
const metadata = params.metadata;
|
|
819
828
|
switch (typeof this._endpoints.wsEndpoint) {
|
|
820
829
|
case "undefined":
|
|
821
|
-
return !!this._getPublicKey() ? `wss://rooms.pluv.io/api/room/${room}` : `/api/pluv/room/${room}`;
|
|
830
|
+
return !!this._getPublicKey(params) ? `wss://rooms.pluv.io/api/room/${room}` : `/api/pluv/room/${room}`;
|
|
822
831
|
case "string":
|
|
823
832
|
return this._endpoints.wsEndpoint;
|
|
824
833
|
default:
|
|
825
|
-
return this._endpoints.wsEndpoint({ metadata
|
|
834
|
+
return this._endpoints.wsEndpoint({ metadata, room });
|
|
826
835
|
}
|
|
827
836
|
}
|
|
828
837
|
_handleExit(message) {
|
|
@@ -989,23 +998,30 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
989
998
|
return oldState;
|
|
990
999
|
});
|
|
991
1000
|
}
|
|
992
|
-
/**
|
|
993
|
-
* TODO
|
|
994
|
-
* @description Determine if ws was closed with a code for closing without retries.
|
|
995
|
-
* Otherwise, attempt to retry again with incremental backoff
|
|
996
|
-
* @author leedavidcs
|
|
997
|
-
* @date August 19, 2022
|
|
998
|
-
*/
|
|
999
1001
|
_onClose(event) {
|
|
1000
1002
|
return __async(this, null, function* () {
|
|
1001
1003
|
this._logDebug("WebSocket closed");
|
|
1002
1004
|
!!event.reason && this._logDebug(event.reason);
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1005
|
+
const shouldRetry = [
|
|
1006
|
+
// Going away: Client/server is shutting down or navigating
|
|
1007
|
+
1001,
|
|
1008
|
+
// Abnormal closure: Usually network error
|
|
1009
|
+
1006,
|
|
1010
|
+
// Internal error: may be a larger problem, but try reconnecting for now
|
|
1011
|
+
1011,
|
|
1012
|
+
// Service restart: Server restarted
|
|
1013
|
+
1012,
|
|
1014
|
+
// Try again later: server overloaded
|
|
1015
|
+
1013,
|
|
1016
|
+
// Bad gateway
|
|
1017
|
+
1014
|
|
1018
|
+
].some((okToRetryCode) => event.code === okToRetryCode);
|
|
1019
|
+
this._closeWs();
|
|
1020
|
+
if (!shouldRetry) this._clearTimeout(this._timeouts.reconnect);
|
|
1021
|
+
else this._pollReconnect();
|
|
1006
1022
|
this._updateState((oldState) => {
|
|
1007
1023
|
oldState.authorization.token = null;
|
|
1008
|
-
oldState.connection.state = "Closed" /* Closed */;
|
|
1024
|
+
oldState.connection.state = shouldRetry ? "Unavailable" /* Unavailable */ : "Closed" /* Closed */;
|
|
1009
1025
|
oldState.webSocket = null;
|
|
1010
1026
|
return oldState;
|
|
1011
1027
|
});
|
|
@@ -1014,7 +1030,6 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1014
1030
|
/**
|
|
1015
1031
|
* TODO
|
|
1016
1032
|
* @description Handle websocket errors in a meaningful way, should they occur
|
|
1017
|
-
* @author leedavidcs
|
|
1018
1033
|
* @date August 19, 2022
|
|
1019
1034
|
*/
|
|
1020
1035
|
_onError() {
|
|
@@ -1073,11 +1088,18 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1073
1088
|
this._clearInterval(this._intervals.heartbeat);
|
|
1074
1089
|
this._intervals.heartbeat = setInterval(this._heartbeat.bind(this), HEARTBEAT_INTERVAL_MS);
|
|
1075
1090
|
}
|
|
1091
|
+
_onNavigatorOffline() {
|
|
1092
|
+
return __async(this, null, function* () {
|
|
1093
|
+
if (this._state.connection.state === "Closed" /* Closed */) return;
|
|
1094
|
+
this._updateState((oldState) => {
|
|
1095
|
+
oldState.connection.state = "Unavailable" /* Unavailable */;
|
|
1096
|
+
return oldState;
|
|
1097
|
+
});
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1076
1100
|
_onNavigatorOnline() {
|
|
1077
1101
|
return __async(this, null, function* () {
|
|
1078
|
-
if (this._state.connection.state !== "Unavailable" /* Unavailable */)
|
|
1079
|
-
return;
|
|
1080
|
-
}
|
|
1102
|
+
if (this._state.connection.state !== "Unavailable" /* Unavailable */) return;
|
|
1081
1103
|
yield this._reconnect();
|
|
1082
1104
|
});
|
|
1083
1105
|
}
|
|
@@ -1109,6 +1131,12 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1109
1131
|
return null;
|
|
1110
1132
|
}
|
|
1111
1133
|
}
|
|
1134
|
+
_pollReconnect() {
|
|
1135
|
+
this._clearTimeout(this._timeouts.reconnect);
|
|
1136
|
+
const timeoutMs = typeof this._reconnectTimeoutMs === "number" ? this._reconnectTimeoutMs : this._reconnectTimeoutMs({ attempts: this._state.connection.attempts });
|
|
1137
|
+
const clampedMs = Math.max(Math.min(MIN_RECONNECT_TIMEOUT_MS, timeoutMs), MAX_RECONNECT_TIMEOUT_MS);
|
|
1138
|
+
this._timeouts.reconnect = setTimeout(this._reconnect.bind(this), clampedMs);
|
|
1139
|
+
}
|
|
1112
1140
|
_reconnect() {
|
|
1113
1141
|
return __async(this, null, function* () {
|
|
1114
1142
|
if (!this._endpoints.wsEndpoint) {
|
|
@@ -1116,13 +1144,9 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1116
1144
|
}
|
|
1117
1145
|
if (!this._state.webSocket) return;
|
|
1118
1146
|
this._closeWs();
|
|
1119
|
-
this.
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
oldState.webSocket = null;
|
|
1123
|
-
return oldState;
|
|
1124
|
-
});
|
|
1125
|
-
yield this.connect();
|
|
1147
|
+
const metadata = this._lastMetadata;
|
|
1148
|
+
const params = typeof metadata === "undefined" ? [] : [{ metadata }];
|
|
1149
|
+
yield this.connect(...params);
|
|
1126
1150
|
});
|
|
1127
1151
|
}
|
|
1128
1152
|
_sendMessage(data) {
|
|
@@ -1143,6 +1167,9 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
1143
1167
|
const message = typeof data === "string" ? data : JSON.stringify(data);
|
|
1144
1168
|
webSocket.send(message);
|
|
1145
1169
|
}
|
|
1170
|
+
_setMetadata(metadata) {
|
|
1171
|
+
return this.metadata ? this.metadata.parse(metadata) : metadata;
|
|
1172
|
+
}
|
|
1146
1173
|
_updateState(updater) {
|
|
1147
1174
|
let authorization;
|
|
1148
1175
|
try {
|
|
@@ -1172,17 +1199,17 @@ var PluvClient = class {
|
|
|
1172
1199
|
var _a;
|
|
1173
1200
|
const oldRoom = this.getRoom(room);
|
|
1174
1201
|
if (oldRoom) return oldRoom;
|
|
1175
|
-
const metadata = this._metadata ? this._metadata.parse(options.metadata) : options.metadata;
|
|
1176
1202
|
const newRoom = new PluvRoom(room, {
|
|
1177
1203
|
addons: options.addons,
|
|
1178
1204
|
authEndpoint: this._authEndpoint,
|
|
1179
1205
|
debug: options.debug,
|
|
1180
1206
|
initialPresence: options.initialPresence,
|
|
1181
1207
|
initialStorage: this._initialStorage,
|
|
1182
|
-
metadata,
|
|
1208
|
+
metadata: this.metadata,
|
|
1183
1209
|
onAuthorizationFail: options.onAuthorizationFail,
|
|
1184
1210
|
presence: this._presence,
|
|
1185
1211
|
publicKey: (_a = this._publicKey) != null ? _a : void 0,
|
|
1212
|
+
reconnectTimeoutMs: options.reconnectTimeoutMs,
|
|
1186
1213
|
router: options.router,
|
|
1187
1214
|
wsEndpoint: this._wsEndpoint
|
|
1188
1215
|
});
|
|
@@ -1190,11 +1217,11 @@ var PluvClient = class {
|
|
|
1190
1217
|
this._logDebug(`New room was created: ${room}`);
|
|
1191
1218
|
return newRoom;
|
|
1192
1219
|
};
|
|
1193
|
-
this.enter = (room) => __async(this, null, function* () {
|
|
1220
|
+
this.enter = (room, ...args) => __async(this, null, function* () {
|
|
1194
1221
|
const toEnter = typeof room === "string" ? this.getRoom(room) : room;
|
|
1195
1222
|
if (!toEnter) throw new Error(`Could not find room: ${room}.`);
|
|
1196
1223
|
this._rooms.set(toEnter.id, toEnter);
|
|
1197
|
-
yield toEnter.connect();
|
|
1224
|
+
yield toEnter.connect(...args);
|
|
1198
1225
|
this._logDebug(`Entered room: ${room}`);
|
|
1199
1226
|
return toEnter;
|
|
1200
1227
|
});
|
|
@@ -1213,10 +1240,10 @@ var PluvClient = class {
|
|
|
1213
1240
|
this._logDebug(`Left and deleted room: ${room}`);
|
|
1214
1241
|
});
|
|
1215
1242
|
const { authEndpoint, debug = false, initialStorage, metadata, presence, publicKey, wsEndpoint } = options;
|
|
1243
|
+
this.metadata = metadata;
|
|
1216
1244
|
this._authEndpoint = authEndpoint;
|
|
1217
1245
|
this._debug = debug;
|
|
1218
1246
|
this._initialStorage = initialStorage;
|
|
1219
|
-
this._metadata = metadata;
|
|
1220
1247
|
this._presence = presence;
|
|
1221
1248
|
this._wsEndpoint = wsEndpoint;
|
|
1222
1249
|
if (!!publicKey) this._publicKey = publicKey;
|
|
@@ -1265,6 +1292,7 @@ var MockedRoom = class extends AbstractRoom {
|
|
|
1265
1292
|
user: null
|
|
1266
1293
|
},
|
|
1267
1294
|
connection: {
|
|
1295
|
+
attempts: 0,
|
|
1268
1296
|
count: 1,
|
|
1269
1297
|
id: null,
|
|
1270
1298
|
state: "Untouched" /* Untouched */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.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.39.1",
|
|
22
|
+
"@pluv/types": "^0.39.1"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"eslint": "^
|
|
25
|
+
"eslint": "^9.24.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.39.1",
|
|
29
|
+
"eslint-config-pluv": "^0.39.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* --fix",
|
|
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/MockedRoom.ts
CHANGED
package/src/PluvClient.ts
CHANGED
|
@@ -2,11 +2,19 @@ import type { AbstractCrdtDocFactory, CrdtType } from "@pluv/crdt";
|
|
|
2
2
|
import type { InputZodLike, IOLike, JsonObject } from "@pluv/types";
|
|
3
3
|
import type { InferCallback } from "./infer";
|
|
4
4
|
import { PluvProcedure } from "./PluvProcedure";
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
AuthEndpoint,
|
|
7
|
+
PluvRoomAddon,
|
|
8
|
+
PluvRoomDebug,
|
|
9
|
+
ReconnectTimeoutMs,
|
|
10
|
+
RoomConfig,
|
|
11
|
+
RoomEndpoints,
|
|
12
|
+
WsEndpoint,
|
|
13
|
+
} from "./PluvRoom";
|
|
6
14
|
import { PluvRoom } from "./PluvRoom";
|
|
7
15
|
import type { PluvRouterEventConfig } from "./PluvRouter";
|
|
8
16
|
import { PluvRouter } from "./PluvRouter";
|
|
9
|
-
import type { PublicKey } from "./types";
|
|
17
|
+
import type { PublicKey, WithMetadata } from "./types";
|
|
10
18
|
|
|
11
19
|
export type PluvClientOptions<
|
|
12
20
|
TIO extends IOLike<any, any>,
|
|
@@ -34,8 +42,13 @@ export type CreateRoomOptions<
|
|
|
34
42
|
initialPresence?: TPresence;
|
|
35
43
|
initialStorage?: AbstractCrdtDocFactory<TStorage>;
|
|
36
44
|
onAuthorizationFail?: (error: Error) => void;
|
|
45
|
+
reconnectTimeoutMs?: ReconnectTimeoutMs;
|
|
37
46
|
router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
38
|
-
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type EnterRoomParams<TMetadata extends JsonObject = {}> = keyof TMetadata extends never
|
|
50
|
+
? []
|
|
51
|
+
: [WithMetadata<TMetadata>];
|
|
39
52
|
|
|
40
53
|
export class PluvClient<
|
|
41
54
|
TIO extends IOLike<any, any>,
|
|
@@ -43,10 +56,11 @@ export class PluvClient<
|
|
|
43
56
|
TStorage extends Record<string, CrdtType<any, any>> = {},
|
|
44
57
|
TMetadata extends JsonObject = {},
|
|
45
58
|
> {
|
|
59
|
+
public readonly metadata?: InputZodLike<TMetadata>;
|
|
60
|
+
|
|
46
61
|
private readonly _authEndpoint: AuthEndpoint<TMetadata> | undefined;
|
|
47
62
|
private readonly _debug: boolean;
|
|
48
63
|
private readonly _initialStorage?: AbstractCrdtDocFactory<TStorage>;
|
|
49
|
-
private readonly _metadata?: InputZodLike<TMetadata>;
|
|
50
64
|
private readonly _presence?: InputZodLike<TPresence>;
|
|
51
65
|
private readonly _publicKey: PublicKey<TMetadata> | null = null;
|
|
52
66
|
private readonly _rooms = new Map<string, PluvRoom<TIO, TMetadata, TPresence, TStorage, any>>();
|
|
@@ -65,10 +79,11 @@ export class PluvClient<
|
|
|
65
79
|
constructor(options: PluvClientOptions<TIO, TPresence, TStorage, TMetadata>) {
|
|
66
80
|
const { authEndpoint, debug = false, initialStorage, metadata, presence, publicKey, wsEndpoint } = options;
|
|
67
81
|
|
|
82
|
+
this.metadata = metadata;
|
|
83
|
+
|
|
68
84
|
this._authEndpoint = authEndpoint as AuthEndpoint<TMetadata>;
|
|
69
85
|
this._debug = debug;
|
|
70
86
|
this._initialStorage = initialStorage;
|
|
71
|
-
this._metadata = metadata;
|
|
72
87
|
this._presence = presence;
|
|
73
88
|
this._wsEndpoint = wsEndpoint;
|
|
74
89
|
|
|
@@ -83,18 +98,17 @@ export class PluvClient<
|
|
|
83
98
|
|
|
84
99
|
if (oldRoom) return oldRoom;
|
|
85
100
|
|
|
86
|
-
const metadata = this._metadata ? this._metadata.parse(options.metadata) : options.metadata;
|
|
87
|
-
|
|
88
101
|
const newRoom = new PluvRoom<TIO, TMetadata, TPresence, TStorage, TEvents>(room, {
|
|
89
102
|
addons: options.addons,
|
|
90
103
|
authEndpoint: this._authEndpoint,
|
|
91
104
|
debug: options.debug,
|
|
92
105
|
initialPresence: options.initialPresence,
|
|
93
106
|
initialStorage: this._initialStorage,
|
|
94
|
-
metadata,
|
|
107
|
+
metadata: this.metadata,
|
|
95
108
|
onAuthorizationFail: options.onAuthorizationFail,
|
|
96
109
|
presence: this._presence,
|
|
97
110
|
publicKey: this._publicKey ?? undefined,
|
|
111
|
+
reconnectTimeoutMs: options.reconnectTimeoutMs,
|
|
98
112
|
router: options.router,
|
|
99
113
|
wsEndpoint: this._wsEndpoint,
|
|
100
114
|
} as RoomConfig<TIO, TMetadata, TPresence, TStorage, TEvents>);
|
|
@@ -107,15 +121,15 @@ export class PluvClient<
|
|
|
107
121
|
};
|
|
108
122
|
|
|
109
123
|
public enter = async (
|
|
110
|
-
room: string | PluvRoom<TIO, any, any, any>,
|
|
124
|
+
room: string | PluvRoom<TIO, TMetadata, any, any, any>,
|
|
125
|
+
...args: EnterRoomParams<TMetadata>
|
|
111
126
|
): Promise<PluvRoom<TIO, TMetadata, TPresence, TStorage, any>> => {
|
|
112
127
|
const toEnter = typeof room === "string" ? this.getRoom(room) : room;
|
|
113
128
|
|
|
114
129
|
if (!toEnter) throw new Error(`Could not find room: ${room}.`);
|
|
115
130
|
|
|
116
131
|
this._rooms.set(toEnter.id, toEnter);
|
|
117
|
-
|
|
118
|
-
await toEnter.connect();
|
|
132
|
+
await toEnter.connect(...args);
|
|
119
133
|
|
|
120
134
|
this._logDebug(`Entered room: ${room}`);
|
|
121
135
|
|