@pluv/client 0.43.0 → 0.44.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @pluv/client@0.43.0 build /home/runner/work/pluv/pluv/packages/client
2
+ > @pluv/client@0.44.1 build /home/runner/work/pluv/pluv/packages/client
3
3
  > tsup src/index.ts --format esm,cjs --dts
4
4
 
5
5
  CLI Building entry: src/index.ts
@@ -8,11 +8,11 @@
8
8
  CLI Target: es6
9
9
  ESM Build start
10
10
  CJS Build start
11
- CJS dist/index.js 57.65 KB
12
- CJS ⚡️ Build success in 115ms
13
- ESM dist/index.mjs 56.33 KB
14
- ESM ⚡️ Build success in 116ms
11
+ ESM dist/index.mjs 56.50 KB
12
+ ESM ⚡️ Build success in 128ms
13
+ CJS dist/index.js 57.82 KB
14
+ CJS ⚡️ Build success in 129ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 3550ms
17
- DTS dist/index.d.mts 25.24 KB
18
- DTS dist/index.d.ts 25.24 KB
16
+ DTS ⚡️ Build success in 3277ms
17
+ DTS dist/index.d.mts 25.36 KB
18
+ DTS dist/index.d.ts 25.36 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @pluv/client
2
2
 
3
+ ## 0.44.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 67c081d: Fix `PluvRoom._reconnect` not being called with the last used metadata (from `PluvRoom.connect`).
8
+ - @pluv/crdt@0.44.1
9
+ - @pluv/types@0.44.1
10
+
11
+ ## 0.44.0
12
+
13
+ ### Minor Changes
14
+
15
+ - c9fcea5: **BREAKING** The `ConnectionState` enum is now a `const` to avoid several pitfalls of using TypeScript enums.
16
+
17
+ ### Patch Changes
18
+
19
+ - fba9354: Fix potential edge case where event handlers may be called redundantly.
20
+ - bc2d684: Fix `PluvRoom` not properly reconnecting when connections are unavailable.
21
+ - @pluv/crdt@0.44.0
22
+ - @pluv/types@0.44.0
23
+
3
24
  ## 0.43.0
4
25
 
5
26
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -6,13 +6,14 @@ import { Subject } from 'wonka';
6
6
 
7
7
  type EventNotifierSubscriptionCallback<TIO extends IOLike<any, any>, TEvent extends keyof InferIOOutput<TIO>> = (value: Id<IOEventMessage<TIO, TEvent>>) => void;
8
8
 
9
- declare enum ConnectionState {
10
- Closed = "Closed",
11
- Connecting = "Connecting",
12
- Open = "Open",
13
- Unavailable = "Unavailable",
14
- Untouched = "Untouched"
15
- }
9
+ declare const ConnectionState: {
10
+ readonly Closed: "Closed";
11
+ readonly Connecting: "Connecting";
12
+ readonly Open: "Open";
13
+ readonly Unavailable: "Unavailable";
14
+ readonly Untouched: "Untouched";
15
+ };
16
+ type ConnectionState = (typeof ConnectionState)[keyof typeof ConnectionState];
16
17
 
17
18
  declare const identity: <T extends unknown>(x: T) => T;
18
19
 
package/dist/index.d.ts CHANGED
@@ -6,13 +6,14 @@ import { Subject } from 'wonka';
6
6
 
7
7
  type EventNotifierSubscriptionCallback<TIO extends IOLike<any, any>, TEvent extends keyof InferIOOutput<TIO>> = (value: Id<IOEventMessage<TIO, TEvent>>) => void;
8
8
 
9
- declare enum ConnectionState {
10
- Closed = "Closed",
11
- Connecting = "Connecting",
12
- Open = "Open",
13
- Unavailable = "Unavailable",
14
- Untouched = "Untouched"
15
- }
9
+ declare const ConnectionState: {
10
+ readonly Closed: "Closed";
11
+ readonly Connecting: "Connecting";
12
+ readonly Open: "Open";
13
+ readonly Unavailable: "Unavailable";
14
+ readonly Untouched: "Untouched";
15
+ };
16
+ type ConnectionState = (typeof ConnectionState)[keyof typeof ConnectionState];
16
17
 
17
18
  declare const identity: <T extends unknown>(x: T) => T;
18
19
 
package/dist/index.js CHANGED
@@ -172,7 +172,7 @@ var CrdtManager = class {
172
172
  }
173
173
  _applyDocUpdates(doc, updates, origin) {
174
174
  doc.transact(() => {
175
- doc.batchApplyEncodedState(updates.map((update) => ({ origin, update })));
175
+ doc.batchApplyEncodedState({ origin, updates });
176
176
  }, origin);
177
177
  return doc;
178
178
  }
@@ -535,14 +535,13 @@ var UsersManager = class {
535
535
  };
536
536
 
537
537
  // src/enums.ts
538
- var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
539
- ConnectionState2["Closed"] = "Closed";
540
- ConnectionState2["Connecting"] = "Connecting";
541
- ConnectionState2["Open"] = "Open";
542
- ConnectionState2["Unavailable"] = "Unavailable";
543
- ConnectionState2["Untouched"] = "Untouched";
544
- return ConnectionState2;
545
- })(ConnectionState || {});
538
+ var ConnectionState = {
539
+ Closed: "Closed",
540
+ Connecting: "Connecting",
541
+ Open: "Open",
542
+ Unavailable: "Unavailable",
543
+ Untouched: "Untouched"
544
+ };
546
545
 
547
546
  // src/PluvRoom.ts
548
547
  var ADD_TO_STORAGE_STATE_DEBOUNCE_MS = 1e3;
@@ -599,7 +598,7 @@ var PluvRoom = class extends AbstractRoom {
599
598
  attempts: 0,
600
599
  count: 0,
601
600
  id: null,
602
- state: "Untouched" /* Untouched */
601
+ state: ConnectionState.Untouched
603
602
  },
604
603
  webSocket: null
605
604
  };
@@ -608,7 +607,7 @@ var PluvRoom = class extends AbstractRoom {
608
607
  this.broadcast = new Proxy(
609
608
  (event, data) => __async(this, null, function* () {
610
609
  if (!this._state.webSocket) return;
611
- if (this._state.connection.state !== "Open" /* Open */) return;
610
+ if (this._state.connection.state !== ConnectionState.Open) return;
612
611
  const type = event.toString();
613
612
  const procedure = this._router._defs.events[type];
614
613
  if (!(procedure == null ? void 0 : procedure.config.broadcast)) {
@@ -765,13 +764,13 @@ var PluvRoom = class extends AbstractRoom {
765
764
  const params = (_a = args[0]) != null ? _a : {};
766
765
  const metadata = params.metadata;
767
766
  this._setMetadata(metadata);
768
- const canConnect = ["Closed" /* Closed */, "Untouched" /* Untouched */].some(
767
+ const canConnect = [ConnectionState.Closed, ConnectionState.Unavailable, ConnectionState.Untouched].some(
769
768
  (state) => this._state.connection.state === state
770
769
  );
771
770
  if (!canConnect) return;
772
771
  this._clearTimeout(this._timeouts.reconnect);
773
772
  this._updateState((oldState) => {
774
- oldState.connection.state = "Connecting" /* Connecting */;
773
+ oldState.connection.state = ConnectionState.Connecting;
775
774
  return oldState;
776
775
  });
777
776
  yield this._storageStore.initialize();
@@ -809,7 +808,7 @@ var PluvRoom = class extends AbstractRoom {
809
808
  disconnect() {
810
809
  return __async(this, null, function* () {
811
810
  if (!this._state.webSocket) return;
812
- const canDisconnect = ["Connecting" /* Connecting */, "Open" /* Open */].some(
811
+ const canDisconnect = [ConnectionState.Connecting, ConnectionState.Open].some(
813
812
  (state) => this._state.connection.state === state
814
813
  );
815
814
  if (!canDisconnect) return;
@@ -818,7 +817,7 @@ var PluvRoom = class extends AbstractRoom {
818
817
  this._clearTimeout(this._timeouts.reconnect);
819
818
  this._updateState((oldState) => {
820
819
  oldState.authorization.token = null;
821
- oldState.connection.state = "Closed" /* Closed */;
820
+ oldState.connection.state = ConnectionState.Closed;
822
821
  oldState.webSocket = null;
823
822
  return oldState;
824
823
  });
@@ -857,7 +856,7 @@ var PluvRoom = class extends AbstractRoom {
857
856
  _attachWindowListeners() {
858
857
  if (typeof window === "undefined") return;
859
858
  if (typeof document === "undefined") return;
860
- this._windowListeners = {
859
+ this._windowListeners = this._windowListeners || {
861
860
  onNavigatorOffline: this._onNavigatorOffline.bind(this),
862
861
  onNavigatorOnline: this._onNavigatorOnline.bind(this),
863
862
  onVisibilityChange: this._onVisibilityChange.bind(this)
@@ -868,7 +867,7 @@ var PluvRoom = class extends AbstractRoom {
868
867
  }
869
868
  _attachWsListeners() {
870
869
  if (!this._state.webSocket) return;
871
- this._wsListeners = {
870
+ this._wsListeners = this._wsListeners || {
872
871
  onClose: this._onClose.bind(this),
873
872
  onError: this._onError.bind(this),
874
873
  onMessage: this._onMessage.bind(this),
@@ -1188,7 +1187,7 @@ var PluvRoom = class extends AbstractRoom {
1188
1187
  const authError = error instanceof Error ? error : new Error("Authorization failed");
1189
1188
  this._listeners.onAuthorizationFail(authError);
1190
1189
  this._updateState((oldState) => {
1191
- oldState.connection.state = "Unavailable" /* Unavailable */;
1190
+ oldState.connection.state = ConnectionState.Unavailable;
1192
1191
  return oldState;
1193
1192
  });
1194
1193
  }
@@ -1212,7 +1211,15 @@ var PluvRoom = class extends AbstractRoom {
1212
1211
  ].some((okToRetryCode) => event.code === okToRetryCode);
1213
1212
  this._updateState((oldState) => {
1214
1213
  oldState.authorization.token = null;
1215
- oldState.connection.state = shouldRetry ? "Unavailable" /* Unavailable */ : "Closed" /* Closed */;
1214
+ oldState.connection.state = shouldRetry ? ConnectionState.Unavailable : (
1215
+ /**
1216
+ * !HACK
1217
+ * @description Assume these are not recoverable. We're just going to mark this
1218
+ * as Closed to avoid reconnect attempts.
1219
+ * @date April 28, 2025
1220
+ */
1221
+ ConnectionState.Closed
1222
+ );
1216
1223
  oldState.webSocket = null;
1217
1224
  return oldState;
1218
1225
  });
@@ -1280,10 +1287,10 @@ var PluvRoom = class extends AbstractRoom {
1280
1287
  }
1281
1288
  }
1282
1289
  _onOpen() {
1283
- if (this._state.connection.state !== "Connecting" /* Connecting */) return;
1290
+ if (this._state.connection.state !== ConnectionState.Connecting) return;
1284
1291
  this._logDebug("WebSocket connected");
1285
1292
  this._updateState((oldState) => {
1286
- oldState.connection.state = "Open" /* Open */;
1293
+ oldState.connection.state = ConnectionState.Open;
1287
1294
  return oldState;
1288
1295
  });
1289
1296
  this._clearInterval(this._intervals.heartbeat);
@@ -1291,16 +1298,16 @@ var PluvRoom = class extends AbstractRoom {
1291
1298
  }
1292
1299
  _onNavigatorOffline() {
1293
1300
  return __async(this, null, function* () {
1294
- if (this._state.connection.state === "Closed" /* Closed */) return;
1301
+ if (this._state.connection.state === ConnectionState.Closed) return;
1295
1302
  this._updateState((oldState) => {
1296
- oldState.connection.state = "Unavailable" /* Unavailable */;
1303
+ oldState.connection.state = ConnectionState.Unavailable;
1297
1304
  return oldState;
1298
1305
  });
1299
1306
  });
1300
1307
  }
1301
1308
  _onNavigatorOnline() {
1302
1309
  return __async(this, null, function* () {
1303
- if (this._state.connection.state !== "Unavailable" /* Unavailable */) return;
1310
+ if (this._state.connection.state !== ConnectionState.Unavailable) return;
1304
1311
  yield this._reconnect();
1305
1312
  });
1306
1313
  }
@@ -1309,12 +1316,12 @@ var PluvRoom = class extends AbstractRoom {
1309
1316
  if (typeof document === "undefined") return;
1310
1317
  if (document.visibilityState !== "visible") return;
1311
1318
  switch (this._state.connection.state) {
1312
- case "Open" /* Open */: {
1319
+ case ConnectionState.Open: {
1313
1320
  this._clearInterval(this._intervals.heartbeat);
1314
1321
  setInterval(this._heartbeat.bind(this), HEARTBEAT_INTERVAL_MS);
1315
1322
  return;
1316
1323
  }
1317
- case "Unavailable" /* Unavailable */: {
1324
+ case ConnectionState.Unavailable: {
1318
1325
  yield this._reconnect();
1319
1326
  return;
1320
1327
  }
@@ -1342,8 +1349,8 @@ var PluvRoom = class extends AbstractRoom {
1342
1349
  }
1343
1350
  _reconnect() {
1344
1351
  return __async(this, null, function* () {
1345
- if (!this._state.webSocket) return;
1346
1352
  this._closeWs();
1353
+ if (this._state.connection.state === ConnectionState.Closed) return;
1347
1354
  const metadata = this._lastMetadata;
1348
1355
  const params = typeof metadata === "undefined" ? [] : [{ metadata }];
1349
1356
  yield this.connect(...params);
@@ -1368,7 +1375,9 @@ var PluvRoom = class extends AbstractRoom {
1368
1375
  webSocket.send(message);
1369
1376
  }
1370
1377
  _setMetadata(metadata) {
1371
- return this.metadata ? this.metadata.parse(metadata) : metadata;
1378
+ const parsed = this.metadata ? this.metadata.parse(metadata) : metadata;
1379
+ this._lastMetadata = parsed;
1380
+ return parsed;
1372
1381
  }
1373
1382
  _updateState(updater) {
1374
1383
  let authorization;
@@ -1508,7 +1517,7 @@ var MockedRoom = class extends AbstractRoom {
1508
1517
  attempts: 0,
1509
1518
  count: 1,
1510
1519
  id: null,
1511
- state: "Untouched" /* Untouched */
1520
+ state: ConnectionState.Untouched
1512
1521
  },
1513
1522
  webSocket: null
1514
1523
  };
@@ -1519,7 +1528,7 @@ var MockedRoom = class extends AbstractRoom {
1519
1528
  this.broadcast = new Proxy(
1520
1529
  (event, data) => __async(this, null, function* () {
1521
1530
  if (!this._state.webSocket) return;
1522
- if (this._state.connection.state !== "Open" /* Open */) return;
1531
+ if (this._state.connection.state !== ConnectionState.Open) return;
1523
1532
  const type = event.toString();
1524
1533
  const procedure = this._router._defs.events[type];
1525
1534
  if (!(procedure == null ? void 0 : procedure.config.broadcast)) {
package/dist/index.mjs CHANGED
@@ -141,7 +141,7 @@ var CrdtManager = class {
141
141
  }
142
142
  _applyDocUpdates(doc, updates, origin) {
143
143
  doc.transact(() => {
144
- doc.batchApplyEncodedState(updates.map((update) => ({ origin, update })));
144
+ doc.batchApplyEncodedState({ origin, updates });
145
145
  }, origin);
146
146
  return doc;
147
147
  }
@@ -504,14 +504,13 @@ var UsersManager = class {
504
504
  };
505
505
 
506
506
  // src/enums.ts
507
- var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
508
- ConnectionState2["Closed"] = "Closed";
509
- ConnectionState2["Connecting"] = "Connecting";
510
- ConnectionState2["Open"] = "Open";
511
- ConnectionState2["Unavailable"] = "Unavailable";
512
- ConnectionState2["Untouched"] = "Untouched";
513
- return ConnectionState2;
514
- })(ConnectionState || {});
507
+ var ConnectionState = {
508
+ Closed: "Closed",
509
+ Connecting: "Connecting",
510
+ Open: "Open",
511
+ Unavailable: "Unavailable",
512
+ Untouched: "Untouched"
513
+ };
515
514
 
516
515
  // src/PluvRoom.ts
517
516
  var ADD_TO_STORAGE_STATE_DEBOUNCE_MS = 1e3;
@@ -568,7 +567,7 @@ var PluvRoom = class extends AbstractRoom {
568
567
  attempts: 0,
569
568
  count: 0,
570
569
  id: null,
571
- state: "Untouched" /* Untouched */
570
+ state: ConnectionState.Untouched
572
571
  },
573
572
  webSocket: null
574
573
  };
@@ -577,7 +576,7 @@ var PluvRoom = class extends AbstractRoom {
577
576
  this.broadcast = new Proxy(
578
577
  (event, data) => __async(this, null, function* () {
579
578
  if (!this._state.webSocket) return;
580
- if (this._state.connection.state !== "Open" /* Open */) return;
579
+ if (this._state.connection.state !== ConnectionState.Open) return;
581
580
  const type = event.toString();
582
581
  const procedure = this._router._defs.events[type];
583
582
  if (!(procedure == null ? void 0 : procedure.config.broadcast)) {
@@ -734,13 +733,13 @@ var PluvRoom = class extends AbstractRoom {
734
733
  const params = (_a = args[0]) != null ? _a : {};
735
734
  const metadata = params.metadata;
736
735
  this._setMetadata(metadata);
737
- const canConnect = ["Closed" /* Closed */, "Untouched" /* Untouched */].some(
736
+ const canConnect = [ConnectionState.Closed, ConnectionState.Unavailable, ConnectionState.Untouched].some(
738
737
  (state) => this._state.connection.state === state
739
738
  );
740
739
  if (!canConnect) return;
741
740
  this._clearTimeout(this._timeouts.reconnect);
742
741
  this._updateState((oldState) => {
743
- oldState.connection.state = "Connecting" /* Connecting */;
742
+ oldState.connection.state = ConnectionState.Connecting;
744
743
  return oldState;
745
744
  });
746
745
  yield this._storageStore.initialize();
@@ -778,7 +777,7 @@ var PluvRoom = class extends AbstractRoom {
778
777
  disconnect() {
779
778
  return __async(this, null, function* () {
780
779
  if (!this._state.webSocket) return;
781
- const canDisconnect = ["Connecting" /* Connecting */, "Open" /* Open */].some(
780
+ const canDisconnect = [ConnectionState.Connecting, ConnectionState.Open].some(
782
781
  (state) => this._state.connection.state === state
783
782
  );
784
783
  if (!canDisconnect) return;
@@ -787,7 +786,7 @@ var PluvRoom = class extends AbstractRoom {
787
786
  this._clearTimeout(this._timeouts.reconnect);
788
787
  this._updateState((oldState) => {
789
788
  oldState.authorization.token = null;
790
- oldState.connection.state = "Closed" /* Closed */;
789
+ oldState.connection.state = ConnectionState.Closed;
791
790
  oldState.webSocket = null;
792
791
  return oldState;
793
792
  });
@@ -826,7 +825,7 @@ var PluvRoom = class extends AbstractRoom {
826
825
  _attachWindowListeners() {
827
826
  if (typeof window === "undefined") return;
828
827
  if (typeof document === "undefined") return;
829
- this._windowListeners = {
828
+ this._windowListeners = this._windowListeners || {
830
829
  onNavigatorOffline: this._onNavigatorOffline.bind(this),
831
830
  onNavigatorOnline: this._onNavigatorOnline.bind(this),
832
831
  onVisibilityChange: this._onVisibilityChange.bind(this)
@@ -837,7 +836,7 @@ var PluvRoom = class extends AbstractRoom {
837
836
  }
838
837
  _attachWsListeners() {
839
838
  if (!this._state.webSocket) return;
840
- this._wsListeners = {
839
+ this._wsListeners = this._wsListeners || {
841
840
  onClose: this._onClose.bind(this),
842
841
  onError: this._onError.bind(this),
843
842
  onMessage: this._onMessage.bind(this),
@@ -1157,7 +1156,7 @@ var PluvRoom = class extends AbstractRoom {
1157
1156
  const authError = error instanceof Error ? error : new Error("Authorization failed");
1158
1157
  this._listeners.onAuthorizationFail(authError);
1159
1158
  this._updateState((oldState) => {
1160
- oldState.connection.state = "Unavailable" /* Unavailable */;
1159
+ oldState.connection.state = ConnectionState.Unavailable;
1161
1160
  return oldState;
1162
1161
  });
1163
1162
  }
@@ -1181,7 +1180,15 @@ var PluvRoom = class extends AbstractRoom {
1181
1180
  ].some((okToRetryCode) => event.code === okToRetryCode);
1182
1181
  this._updateState((oldState) => {
1183
1182
  oldState.authorization.token = null;
1184
- oldState.connection.state = shouldRetry ? "Unavailable" /* Unavailable */ : "Closed" /* Closed */;
1183
+ oldState.connection.state = shouldRetry ? ConnectionState.Unavailable : (
1184
+ /**
1185
+ * !HACK
1186
+ * @description Assume these are not recoverable. We're just going to mark this
1187
+ * as Closed to avoid reconnect attempts.
1188
+ * @date April 28, 2025
1189
+ */
1190
+ ConnectionState.Closed
1191
+ );
1185
1192
  oldState.webSocket = null;
1186
1193
  return oldState;
1187
1194
  });
@@ -1249,10 +1256,10 @@ var PluvRoom = class extends AbstractRoom {
1249
1256
  }
1250
1257
  }
1251
1258
  _onOpen() {
1252
- if (this._state.connection.state !== "Connecting" /* Connecting */) return;
1259
+ if (this._state.connection.state !== ConnectionState.Connecting) return;
1253
1260
  this._logDebug("WebSocket connected");
1254
1261
  this._updateState((oldState) => {
1255
- oldState.connection.state = "Open" /* Open */;
1262
+ oldState.connection.state = ConnectionState.Open;
1256
1263
  return oldState;
1257
1264
  });
1258
1265
  this._clearInterval(this._intervals.heartbeat);
@@ -1260,16 +1267,16 @@ var PluvRoom = class extends AbstractRoom {
1260
1267
  }
1261
1268
  _onNavigatorOffline() {
1262
1269
  return __async(this, null, function* () {
1263
- if (this._state.connection.state === "Closed" /* Closed */) return;
1270
+ if (this._state.connection.state === ConnectionState.Closed) return;
1264
1271
  this._updateState((oldState) => {
1265
- oldState.connection.state = "Unavailable" /* Unavailable */;
1272
+ oldState.connection.state = ConnectionState.Unavailable;
1266
1273
  return oldState;
1267
1274
  });
1268
1275
  });
1269
1276
  }
1270
1277
  _onNavigatorOnline() {
1271
1278
  return __async(this, null, function* () {
1272
- if (this._state.connection.state !== "Unavailable" /* Unavailable */) return;
1279
+ if (this._state.connection.state !== ConnectionState.Unavailable) return;
1273
1280
  yield this._reconnect();
1274
1281
  });
1275
1282
  }
@@ -1278,12 +1285,12 @@ var PluvRoom = class extends AbstractRoom {
1278
1285
  if (typeof document === "undefined") return;
1279
1286
  if (document.visibilityState !== "visible") return;
1280
1287
  switch (this._state.connection.state) {
1281
- case "Open" /* Open */: {
1288
+ case ConnectionState.Open: {
1282
1289
  this._clearInterval(this._intervals.heartbeat);
1283
1290
  setInterval(this._heartbeat.bind(this), HEARTBEAT_INTERVAL_MS);
1284
1291
  return;
1285
1292
  }
1286
- case "Unavailable" /* Unavailable */: {
1293
+ case ConnectionState.Unavailable: {
1287
1294
  yield this._reconnect();
1288
1295
  return;
1289
1296
  }
@@ -1311,8 +1318,8 @@ var PluvRoom = class extends AbstractRoom {
1311
1318
  }
1312
1319
  _reconnect() {
1313
1320
  return __async(this, null, function* () {
1314
- if (!this._state.webSocket) return;
1315
1321
  this._closeWs();
1322
+ if (this._state.connection.state === ConnectionState.Closed) return;
1316
1323
  const metadata = this._lastMetadata;
1317
1324
  const params = typeof metadata === "undefined" ? [] : [{ metadata }];
1318
1325
  yield this.connect(...params);
@@ -1337,7 +1344,9 @@ var PluvRoom = class extends AbstractRoom {
1337
1344
  webSocket.send(message);
1338
1345
  }
1339
1346
  _setMetadata(metadata) {
1340
- return this.metadata ? this.metadata.parse(metadata) : metadata;
1347
+ const parsed = this.metadata ? this.metadata.parse(metadata) : metadata;
1348
+ this._lastMetadata = parsed;
1349
+ return parsed;
1341
1350
  }
1342
1351
  _updateState(updater) {
1343
1352
  let authorization;
@@ -1477,7 +1486,7 @@ var MockedRoom = class extends AbstractRoom {
1477
1486
  attempts: 0,
1478
1487
  count: 1,
1479
1488
  id: null,
1480
- state: "Untouched" /* Untouched */
1489
+ state: ConnectionState.Untouched
1481
1490
  },
1482
1491
  webSocket: null
1483
1492
  };
@@ -1488,7 +1497,7 @@ var MockedRoom = class extends AbstractRoom {
1488
1497
  this.broadcast = new Proxy(
1489
1498
  (event, data) => __async(this, null, function* () {
1490
1499
  if (!this._state.webSocket) return;
1491
- if (this._state.connection.state !== "Open" /* Open */) return;
1500
+ if (this._state.connection.state !== ConnectionState.Open) return;
1492
1501
  const type = event.toString();
1493
1502
  const procedure = this._router._defs.events[type];
1494
1503
  if (!(procedure == null ? void 0 : procedure.config.broadcast)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluv/client",
3
- "version": "0.43.0",
3
+ "version": "0.44.1",
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": "^0.43.0",
22
- "@pluv/types": "^0.43.0"
21
+ "@pluv/crdt": "^0.44.1",
22
+ "@pluv/types": "^0.44.1"
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": "^0.43.0",
29
- "eslint-config-pluv": "^0.43.0"
28
+ "@pluv/tsconfig": "^0.44.1",
29
+ "eslint-config-pluv": "^0.44.1"
30
30
  },
31
31
  "scripts": {
32
32
  "build": "tsup src/index.ts --format esm,cjs --dts",
@@ -93,7 +93,7 @@ export class CrdtManager<TStorage extends Record<string, CrdtType<any, any>>> {
93
93
  origin?: string,
94
94
  ): AbstractCrdtDoc<TStorage> {
95
95
  doc.transact(() => {
96
- doc.batchApplyEncodedState(updates.map((update) => ({ origin, update })));
96
+ doc.batchApplyEncodedState({ origin, updates });
97
97
  }, origin);
98
98
 
99
99
  return doc;
package/src/PluvRoom.ts CHANGED
@@ -363,7 +363,7 @@ export class PluvRoom<
363
363
 
364
364
  this._setMetadata(metadata);
365
365
 
366
- const canConnect = [ConnectionState.Closed, ConnectionState.Untouched].some(
366
+ const canConnect = [ConnectionState.Closed, ConnectionState.Unavailable, ConnectionState.Untouched].some(
367
367
  (state) => this._state.connection.state === state,
368
368
  );
369
369
 
@@ -615,7 +615,7 @@ export class PluvRoom<
615
615
  if (typeof window === "undefined") return;
616
616
  if (typeof document === "undefined") return;
617
617
 
618
- this._windowListeners = {
618
+ this._windowListeners = this._windowListeners || {
619
619
  onNavigatorOffline: this._onNavigatorOffline.bind(this),
620
620
  onNavigatorOnline: this._onNavigatorOnline.bind(this),
621
621
  onVisibilityChange: this._onVisibilityChange.bind(this),
@@ -629,7 +629,7 @@ export class PluvRoom<
629
629
  private _attachWsListeners(): void {
630
630
  if (!this._state.webSocket) return;
631
631
 
632
- this._wsListeners = {
632
+ this._wsListeners = this._wsListeners || {
633
633
  onClose: this._onClose.bind(this),
634
634
  onError: this._onError.bind(this),
635
635
  onMessage: this._onMessage.bind(this),
@@ -1152,7 +1152,15 @@ export class PluvRoom<
1152
1152
 
1153
1153
  this._updateState((oldState) => {
1154
1154
  oldState.authorization.token = null;
1155
- oldState.connection.state = shouldRetry ? ConnectionState.Unavailable : ConnectionState.Closed;
1155
+ oldState.connection.state = shouldRetry
1156
+ ? ConnectionState.Unavailable
1157
+ : /**
1158
+ * !HACK
1159
+ * @description Assume these are not recoverable. We're just going to mark this
1160
+ * as Closed to avoid reconnect attempts.
1161
+ * @date April 28, 2025
1162
+ */
1163
+ ConnectionState.Closed;
1156
1164
  oldState.webSocket = null;
1157
1165
 
1158
1166
  return oldState;
@@ -1314,10 +1322,16 @@ export class PluvRoom<
1314
1322
  }
1315
1323
 
1316
1324
  private async _reconnect(): Promise<void> {
1317
- if (!this._state.webSocket) return;
1318
-
1319
1325
  this._closeWs();
1320
1326
 
1327
+ /**
1328
+ * @description User has manually closed this connection. We're not going to retry, since
1329
+ * the user probably intends for this to stay closed. They will need to invoke connect
1330
+ * themselves.
1331
+ * @date April 28, 2025
1332
+ */
1333
+ if (this._state.connection.state === ConnectionState.Closed) return;
1334
+
1321
1335
  const metadata = this._lastMetadata;
1322
1336
  const params = (typeof metadata === "undefined" ? [] : [{ metadata }]) as RoomConnectParams<TMetadata>;
1323
1337
 
@@ -1357,7 +1371,11 @@ export class PluvRoom<
1357
1371
  }
1358
1372
 
1359
1373
  private _setMetadata(metadata: TMetadata): TMetadata {
1360
- return this.metadata ? this.metadata.parse(metadata) : metadata;
1374
+ const parsed = this.metadata ? this.metadata.parse(metadata) : metadata;
1375
+
1376
+ this._lastMetadata = parsed;
1377
+
1378
+ return parsed;
1361
1379
  }
1362
1380
 
1363
1381
  private _updateState(updater: (oldState: WebSocketState<TIO>) => WebSocketState<TIO>): WebSocketState<TIO> {
package/src/enums.ts CHANGED
@@ -1,7 +1,9 @@
1
- export enum ConnectionState {
2
- Closed = "Closed",
3
- Connecting = "Connecting",
4
- Open = "Open",
5
- Unavailable = "Unavailable",
6
- Untouched = "Untouched",
7
- }
1
+ export const ConnectionState = {
2
+ Closed: "Closed",
3
+ Connecting: "Connecting",
4
+ Open: "Open",
5
+ Unavailable: "Unavailable",
6
+ Untouched: "Untouched",
7
+ } as const;
8
+
9
+ export type ConnectionState = (typeof ConnectionState)[keyof typeof ConnectionState];