@pluv/client 0.11.0 → 0.12.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/dist/index.js CHANGED
@@ -87,14 +87,21 @@ var import_crdt_yjs = require("@pluv/crdt-yjs");
87
87
  var CrdtManager = class {
88
88
  constructor(options = {}) {
89
89
  this.initialized = false;
90
- const { encodedState, initialStorage } = options;
90
+ const {
91
+ captureTimeout,
92
+ encodedState,
93
+ initialStorage,
94
+ trackedOrigins = []
95
+ } = options;
91
96
  const _doc = encodedState ? (0, import_crdt_yjs.doc)().applyUpdate(encodedState) : null;
92
97
  if (_doc && !!Object.keys(_doc.toJSON()).length) {
93
98
  this.doc = _doc;
99
+ this.trackOrigins({ captureTimeout, trackedOrigins });
94
100
  return;
95
101
  }
96
102
  _doc == null ? void 0 : _doc.destroy();
97
103
  this.doc = (0, import_crdt_yjs.doc)(initialStorage == null ? void 0 : initialStorage());
104
+ this.trackOrigins({ captureTimeout, trackedOrigins });
98
105
  }
99
106
  /**
100
107
  * !HACK
@@ -116,8 +123,15 @@ var CrdtManager = class {
116
123
  return this.doc.get(key);
117
124
  }
118
125
  initialize(params) {
119
- const { onInitialized, origin, update } = params;
126
+ const {
127
+ captureTimeout,
128
+ onInitialized,
129
+ origin,
130
+ trackedOrigins,
131
+ update
132
+ } = params;
120
133
  const updates = typeof update === "string" ? [update] : update;
134
+ this.trackOrigins({ captureTimeout, trackedOrigins });
121
135
  if (!updates.length)
122
136
  return this;
123
137
  if (this.initialized) {
@@ -132,8 +146,13 @@ var CrdtManager = class {
132
146
  _doc.destroy();
133
147
  }
134
148
  onInitialized == null ? void 0 : onInitialized();
149
+ this.trackOrigins({ captureTimeout, trackedOrigins });
135
150
  return this;
136
151
  }
152
+ trackOrigins(options) {
153
+ const { captureTimeout, trackedOrigins } = options;
154
+ this.doc.trackOrigins({ captureTimeout, trackedOrigins });
155
+ }
137
156
  _applyDocUpdates(yjsDoc, updates, origin) {
138
157
  yjsDoc.transact(() => {
139
158
  updates.reduce((acc, _update) => acc.applyUpdate(_update), yjsDoc);
@@ -146,6 +165,7 @@ var CrdtManager = class {
146
165
  var import_wonka = require("wonka");
147
166
  var CrdtNotifier = class {
148
167
  constructor() {
168
+ this.rootSubject = (0, import_wonka.makeSubject)();
149
169
  this.subjects = /* @__PURE__ */ new Map();
150
170
  }
151
171
  subject(key) {
@@ -157,6 +177,9 @@ var CrdtNotifier = class {
157
177
  this.subjects.set(key, newSubject);
158
178
  return newSubject;
159
179
  }
180
+ subcribeRoot(callback) {
181
+ return (0, import_wonka.subscribe)(callback)(this.rootSubject.source).unsubscribe;
182
+ }
160
183
  subscribe(key, callback) {
161
184
  const subject = this.subject(key);
162
185
  return (0, import_wonka.subscribe)(callback)(subject.source).unsubscribe;
@@ -379,7 +402,8 @@ var ADD_TO_STORAGE_STATE_DEBOUNCE_MS = 1e3;
379
402
  var HEARTBEAT_INTERVAL_MS = 1e4;
380
403
  var PONG_TIMEOUT_MS = 2e3;
381
404
  var RECONNECT_TIMEOUT_MS = 3e4;
382
- var Y_ORIGIN_INITIALIZED = "$INITIALIZED";
405
+ var ORIGIN_INITIALIZED = "$INITIALIZED";
406
+ var ORIGIN_STORAGE_UPDATED = "$STORAGE_UPDATED";
383
407
  var DEFAULT_PLUV_CLIENT_ADDON = (input) => ({
384
408
  storage: new StorageStore(input.room.id)
385
409
  });
@@ -388,14 +412,17 @@ var PluvRoom = class extends AbstractRoom {
388
412
  const {
389
413
  addons = [],
390
414
  authEndpoint,
415
+ captureTimeout,
391
416
  debug = false,
392
417
  initialPresence,
393
418
  initialStorage,
394
419
  onAuthorizationFail,
395
420
  presence,
421
+ trackedOrigins,
396
422
  wsEndpoint
397
423
  } = options;
398
424
  super(room);
425
+ this._captureTimeout = null;
399
426
  this._crdtNotifier = new CrdtNotifier();
400
427
  this._eventNotifier = new EventNotifier();
401
428
  this._intervals = {
@@ -422,8 +449,15 @@ var PluvRoom = class extends AbstractRoom {
422
449
  pong: null,
423
450
  reconnect: null
424
451
  };
452
+ this._trackedOrigins = null;
425
453
  this._windowListeners = null;
426
454
  this._wsListeners = null;
455
+ this.canRedo = () => {
456
+ return !!this._crdtManager.doc.canRedo();
457
+ };
458
+ this.canUndo = () => {
459
+ return !!this._crdtManager.doc.canUndo();
460
+ };
427
461
  this.event = (event, callback) => {
428
462
  return this._eventNotifier.subscribe(event, callback);
429
463
  };
@@ -446,12 +480,29 @@ var PluvRoom = class extends AbstractRoom {
446
480
  this.other = (connectionId, callback) => {
447
481
  return this._otherNotifier.subscribe(connectionId, callback);
448
482
  };
483
+ this.redo = () => {
484
+ this._crdtManager.doc.redo();
485
+ };
449
486
  this.storage = (key, fn) => {
450
487
  return this._crdtNotifier.subscribe(key, fn);
451
488
  };
489
+ this.storageRoot = (fn) => {
490
+ return this._crdtNotifier.subcribeRoot(fn);
491
+ };
452
492
  this.subscribe = (name, callback) => {
453
493
  return this._stateNotifier.subscribe(name, callback);
454
494
  };
495
+ this.transact = (fn, origin) => {
496
+ const _origin = origin != null ? origin : this._state.connection.id;
497
+ if (typeof _origin !== "string")
498
+ return;
499
+ this._crdtManager.doc.transact(() => {
500
+ fn(this._crdtManager.doc.storage);
501
+ }, _origin);
502
+ };
503
+ this.undo = () => {
504
+ this._crdtManager.doc.undo();
505
+ };
455
506
  this.updateMyPresence = (presence) => {
456
507
  var _a;
457
508
  this._usersManager.updateMyPresence(presence);
@@ -501,7 +552,13 @@ var PluvRoom = class extends AbstractRoom {
501
552
  initialPresence,
502
553
  presence
503
554
  });
504
- this._crdtManager = new CrdtManager({ initialStorage });
555
+ this._crdtManager = new CrdtManager({
556
+ captureTimeout,
557
+ initialStorage,
558
+ trackedOrigins
559
+ });
560
+ this._captureTimeout = captureTimeout != null ? captureTimeout : null;
561
+ this._trackedOrigins = trackedOrigins != null ? trackedOrigins : null;
505
562
  }
506
563
  get webSocket() {
507
564
  return this._state.webSocket;
@@ -532,7 +589,6 @@ var PluvRoom = class extends AbstractRoom {
532
589
  });
533
590
  yield this._storageStore.initialize();
534
591
  yield this._applyStorageStore();
535
- console.log(this._getWsEndpoint(this.id));
536
592
  const url = new URL(this._getWsEndpoint(this.id));
537
593
  let authToken = null;
538
594
  let webSocket;
@@ -588,12 +644,16 @@ var PluvRoom = class extends AbstractRoom {
588
644
  }
589
645
  _applyStorageStore() {
590
646
  return __async(this, null, function* () {
647
+ var _a;
591
648
  const updates = yield this._storageStore.getUpdates();
649
+ const trackedOrigins = this._getTrackedOrigins();
592
650
  this._crdtManager.initialize({
651
+ captureTimeout: (_a = this._captureTimeout) != null ? _a : void 0,
593
652
  onInitialized: () => {
594
653
  this._observeCrdt();
595
654
  },
596
- origin: Y_ORIGIN_INITIALIZED,
655
+ origin: ORIGIN_INITIALIZED,
656
+ trackedOrigins: trackedOrigins != null ? trackedOrigins : void 0,
597
657
  update: updates
598
658
  });
599
659
  this._emitSharedTypes();
@@ -712,10 +772,15 @@ var PluvRoom = class extends AbstractRoom {
712
772
  }
713
773
  _emitSharedTypes() {
714
774
  const sharedTypes = this._crdtManager.doc.getSharedTypes();
715
- Object.entries(sharedTypes).forEach(([prop, sharedType]) => {
716
- const serialized = sharedType.toJSON();
717
- this._crdtNotifier.subject(prop).next(serialized);
718
- });
775
+ const storageRoot = Object.entries(sharedTypes).reduce(
776
+ (acc, [prop, sharedType]) => {
777
+ const serialized = sharedType.toJSON();
778
+ this._crdtNotifier.subject(prop).next(serialized);
779
+ return __spreadProps(__spreadValues({}, acc), { [prop]: serialized });
780
+ },
781
+ {}
782
+ );
783
+ this._crdtNotifier.rootSubject.next(storageRoot);
719
784
  }
720
785
  _getAuthFetchOptions(room) {
721
786
  if (typeof this._endpoints.authEndpoint === "undefined")
@@ -754,6 +819,11 @@ var PluvRoom = class extends AbstractRoom {
754
819
  }
755
820
  });
756
821
  }
822
+ _getTrackedOrigins() {
823
+ var _a;
824
+ const connectionId = this._state.connection.id;
825
+ return !connectionId ? this._trackedOrigins : [connectionId, ...(_a = this._trackedOrigins) != null ? _a : []];
826
+ }
757
827
  _getWsEndpoint(room) {
758
828
  switch (typeof this._endpoints.wsEndpoint) {
759
829
  case "undefined":
@@ -850,17 +920,21 @@ var PluvRoom = class extends AbstractRoom {
850
920
  }
851
921
  _handleStorageReceivedMessage(message) {
852
922
  return __async(this, null, function* () {
923
+ var _a;
853
924
  const { connectionId } = message;
854
925
  if (!connectionId)
855
926
  return;
856
927
  if (!this._state.webSocket)
857
928
  throw new Error("Could not find WebSocket");
858
929
  const data = message.data;
930
+ const trackedOrigins = this._getTrackedOrigins();
859
931
  this._crdtManager.initialize({
932
+ captureTimeout: (_a = this._captureTimeout) != null ? _a : void 0,
860
933
  onInitialized: () => __async(this, null, function* () {
861
934
  this._observeCrdt();
862
935
  }),
863
- origin: Y_ORIGIN_INITIALIZED,
936
+ origin: ORIGIN_INITIALIZED,
937
+ trackedOrigins: trackedOrigins != null ? trackedOrigins : void 0,
864
938
  update: data.state
865
939
  });
866
940
  const encodedState = this._crdtManager.doc.encodeStateAsUpdate();
@@ -869,7 +943,7 @@ var PluvRoom = class extends AbstractRoom {
869
943
  const update = this._crdtManager.doc.encodeStateAsUpdate();
870
944
  this._sendMessage({
871
945
  type: "$UPDATE_STORAGE",
872
- data: { origin: Y_ORIGIN_INITIALIZED, update }
946
+ data: { origin: ORIGIN_INITIALIZED, update }
873
947
  });
874
948
  });
875
949
  }
@@ -882,14 +956,19 @@ var PluvRoom = class extends AbstractRoom {
882
956
  const data = message.data;
883
957
  if (!this._crdtManager)
884
958
  return;
885
- this._crdtManager.doc.applyUpdate(data.state, "$STORAGE_UPDATED");
959
+ this._crdtManager.doc.applyUpdate(data.state, ORIGIN_STORAGE_UPDATED);
886
960
  const sharedTypes = this._crdtManager.doc.getSharedTypes();
887
- Object.entries(sharedTypes).forEach(([prop, sharedType]) => {
888
- if (!this._crdtManager)
889
- return;
890
- const serialized = sharedType.toJSON();
891
- this._crdtNotifier.subject(prop).next(serialized);
892
- });
961
+ const storageRoot = Object.entries(sharedTypes).reduce(
962
+ (acc, [prop, sharedType]) => {
963
+ if (!this._crdtManager)
964
+ return acc;
965
+ const serialized = sharedType.toJSON();
966
+ this._crdtNotifier.subject(prop).next(serialized);
967
+ return __spreadProps(__spreadValues({}, acc), { [prop]: serialized });
968
+ },
969
+ {}
970
+ );
971
+ this._crdtNotifier.rootSubject.next(storageRoot);
893
972
  }
894
973
  _handleUserJoinedMessage(message) {
895
974
  const { connectionId } = message;
@@ -938,7 +1017,7 @@ var PluvRoom = class extends AbstractRoom {
938
1017
  const origin = _origin != null ? _origin : null;
939
1018
  this._addToStorageStore(update);
940
1019
  this._emitSharedTypes();
941
- if (origin === Y_ORIGIN_INITIALIZED || origin === this)
1020
+ if (origin === ORIGIN_INITIALIZED || origin === this)
942
1021
  return;
943
1022
  if (!this._state.webSocket)
944
1023
  return;
@@ -946,7 +1025,7 @@ var PluvRoom = class extends AbstractRoom {
946
1025
  return;
947
1026
  if (this._state.webSocket.readyState !== WebSocket.OPEN)
948
1027
  return;
949
- if (origin === "$STORAGE_UPDATED")
1028
+ if (origin === ORIGIN_STORAGE_UPDATED)
950
1029
  return;
951
1030
  this._sendMessage({
952
1031
  type: "$UPDATE_STORAGE",
@@ -1236,6 +1315,14 @@ var MockedRoom = class extends AbstractRoom {
1236
1315
  this._subscriptions = {
1237
1316
  observeCrdt: null
1238
1317
  };
1318
+ this.canRedo = () => {
1319
+ var _a;
1320
+ return !!((_a = this._crdtManager) == null ? void 0 : _a.doc.canRedo());
1321
+ };
1322
+ this.canUndo = () => {
1323
+ var _a;
1324
+ return !!((_a = this._crdtManager) == null ? void 0 : _a.doc.canUndo());
1325
+ };
1239
1326
  this.event = (event, callback) => {
1240
1327
  return this._eventNotifier.subscribe(event, callback);
1241
1328
  };
@@ -1258,12 +1345,34 @@ var MockedRoom = class extends AbstractRoom {
1258
1345
  this.other = (connectionId, callback) => {
1259
1346
  return this._otherNotifier.subscribe(connectionId, callback);
1260
1347
  };
1348
+ this.redo = () => {
1349
+ var _a;
1350
+ (_a = this._crdtManager) == null ? void 0 : _a.doc.redo();
1351
+ };
1261
1352
  this.storage = (key, fn) => {
1262
1353
  return this._crdtNotifier.subscribe(key, fn);
1263
1354
  };
1355
+ this.storageRoot = (fn) => {
1356
+ return this._crdtNotifier.subcribeRoot(fn);
1357
+ };
1264
1358
  this.subscribe = (name, callback) => {
1265
1359
  return this._stateNotifier.subscribe(name, callback);
1266
1360
  };
1361
+ this.transact = (fn, origin) => {
1362
+ const _origin = origin != null ? origin : this._state.connection.id;
1363
+ const crdtManager = this._crdtManager;
1364
+ if (typeof _origin !== "string")
1365
+ return;
1366
+ if (!crdtManager)
1367
+ return;
1368
+ crdtManager.doc.transact(() => {
1369
+ fn(crdtManager.doc.storage);
1370
+ }, _origin);
1371
+ };
1372
+ this.undo = () => {
1373
+ var _a;
1374
+ (_a = this._crdtManager) == null ? void 0 : _a.doc.undo();
1375
+ };
1267
1376
  this.updateMyPresence = (presence) => {
1268
1377
  var _a;
1269
1378
  this._usersManager.updateMyPresence(presence);
@@ -1315,12 +1424,17 @@ var MockedRoom = class extends AbstractRoom {
1315
1424
  if (origin === "$STORAGE_UPDATED")
1316
1425
  return;
1317
1426
  const sharedTypes = this._crdtManager.doc.getSharedTypes();
1318
- Object.entries(sharedTypes).forEach(([prop, sharedType]) => {
1319
- if (!this._crdtManager)
1320
- return;
1321
- const serialized = sharedType.toJSON();
1322
- this._crdtNotifier.subject(prop).next(serialized);
1323
- });
1427
+ const storageRoot = Object.entries(sharedTypes).reduce(
1428
+ (acc, [prop, sharedType]) => {
1429
+ if (!this._crdtManager)
1430
+ return acc;
1431
+ const serialized = sharedType.toJSON();
1432
+ this._crdtNotifier.subject(prop).next(serialized);
1433
+ return __spreadProps(__spreadValues({}, acc), { [prop]: serialized });
1434
+ },
1435
+ {}
1436
+ );
1437
+ this._crdtNotifier.rootSubject.next(storageRoot);
1324
1438
  }
1325
1439
  );
1326
1440
  this._subscriptions.observeCrdt = unsubscribe;