@mml-io/networked-dom-document 0.20.0 → 0.21.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.
@@ -38,7 +38,7 @@ export declare class NetworkedDOM {
38
38
  addNetworkedDOMConnection(networkedDOMConnection: NetworkedDOMV01Connection | NetworkedDOMV02Connection): void;
39
39
  removeNetworkedDOMConnection(networkedDOMConnection: NetworkedDOMV01Connection | NetworkedDOMV02Connection): void;
40
40
  connectUsers(networkedDOMConnection: NetworkedDOMV01Connection | NetworkedDOMV02Connection, addedExternalUserIds: Set<number>): Map<number, number>;
41
- announceConnectedUsers(userIds: Set<number>): void;
41
+ announceConnectedUsers(userIds: Map<number, string | null>): void;
42
42
  disconnectUsers(networkedDOMConnection: NetworkedDOMV02Connection, removedExternalToInternalUserIds: Map<number, number>): Array<NetworkedDOMV02Diff>;
43
43
  private defaultLogCallback;
44
44
  private sendPings;
@@ -5,6 +5,7 @@ export declare class NetworkedDOMV02Connection {
5
5
  private websocketListener;
6
6
  externalIdToInternalId: Map<number, number>;
7
7
  internalIdToExternalId: Map<number, number>;
8
+ internalIdToToken: Map<number, string | null>;
8
9
  private batchMode;
9
10
  private batchMessages;
10
11
  externalConnectionIds: Set<number>;
@@ -1,5 +1,5 @@
1
1
  import { NetworkedDOMV01Connection } from "./NetworkedDOMV01Connection";
2
2
  import { NetworkedDOMV02Connection } from "./NetworkedDOMV02Connection";
3
- export declare const SupportedWebsocketSubProtocolsPreferenceOrder: readonly ["networked-dom-v0.2", "networked-dom-v0.1"];
3
+ export declare const SupportedWebsocketSubProtocolsPreferenceOrder: readonly ["networked-dom-v0.2.1", "networked-dom-v0.2", "networked-dom-v0.1"];
4
4
  export declare const defaultWebsocketSubProtocol = "networked-dom-v0.1";
5
5
  export declare function createNetworkedDOMConnectionForWebsocket(webSocket: WebSocket): NetworkedDOMV01Connection | NetworkedDOMV02Connection | null;
package/build/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  // src/createNetworkedDOMConnectionForWebsocket.ts
2
2
  import {
3
+ isNetworkedDOMProtocolSubProtocol_v0_2 as isNetworkedDOMProtocolSubProtocol_v0_22,
3
4
  networkedDOMProtocolSubProtocol_v0_1,
4
- networkedDOMProtocolSubProtocol_v0_2
5
+ networkedDOMProtocolSubProtocol_v0_2_SubVersionsList
5
6
  } from "@mml-io/networked-dom-protocol";
6
7
 
7
8
  // src/NetworkedDOMV01Connection.ts
@@ -57,7 +58,9 @@ var NetworkedDOMV01Connection = class {
57
58
  const internalConnectionIds = this.networkedDOM.connectUsers(this, /* @__PURE__ */ new Set([1]));
58
59
  this.internalConnectionId = internalConnectionIds.entries().next().value[0];
59
60
  this.internalIdToExternalId.set(this.internalConnectionId, 1);
60
- this.networkedDOM.announceConnectedUsers(/* @__PURE__ */ new Set([this.internalConnectionId]));
61
+ this.networkedDOM.announceConnectedUsers(
62
+ /* @__PURE__ */ new Map([[this.internalConnectionId, null]])
63
+ );
61
64
  }
62
65
  stringifyAndSendSingleMessage(message) {
63
66
  this.webSocket.send("[" + JSON.stringify(message) + "]");
@@ -77,21 +80,31 @@ import {
77
80
  decodeClientMessages,
78
81
  encodeBatchEnd,
79
82
  encodeBatchStart,
80
- encodeServerMessage
83
+ encodeServerMessage,
84
+ getNetworkedDOMProtocolSubProtocol_v0_2SubversionOrThrow,
85
+ isNetworkedDOMProtocolSubProtocol_v0_2
81
86
  } from "@mml-io/networked-dom-protocol";
82
87
  var NetworkedDOMV02Connection = class {
83
88
  constructor(webSocket) {
84
89
  this.webSocket = webSocket;
85
90
  this.externalIdToInternalId = /* @__PURE__ */ new Map();
86
91
  this.internalIdToExternalId = /* @__PURE__ */ new Map();
92
+ this.internalIdToToken = /* @__PURE__ */ new Map();
87
93
  this.batchMode = false;
88
94
  this.batchMessages = [];
89
95
  this.externalConnectionIds = /* @__PURE__ */ new Set();
90
96
  this.networkedDOM = null;
91
97
  this.messagesAwaitingNetworkedDOM = [];
98
+ const protocol = webSocket.protocol;
99
+ if (!isNetworkedDOMProtocolSubProtocol_v0_2(protocol)) {
100
+ throw new Error(
101
+ `WebSocket protocol ${protocol} is not a supported networked-dom-v0.2 sub-protocol`
102
+ );
103
+ }
104
+ const protocolSubversion = getNetworkedDOMProtocolSubProtocol_v0_2SubversionOrThrow(protocol);
92
105
  this.websocketListener = (messageEvent) => {
93
106
  const buffer = new Uint8Array(messageEvent.data);
94
- const messages = decodeClientMessages(new BufferReader(buffer));
107
+ const messages = decodeClientMessages(new BufferReader(buffer), protocolSubversion);
95
108
  for (const parsed of messages) {
96
109
  if (this.networkedDOM) {
97
110
  this.handleClientMessage(parsed);
@@ -161,8 +174,12 @@ var NetworkedDOMV02Connection = class {
161
174
  handleClientMessage(parsed) {
162
175
  switch (parsed.type) {
163
176
  case "connectUsers": {
177
+ const externalIdsToToken = /* @__PURE__ */ new Map();
164
178
  const addedExternalUserIds = /* @__PURE__ */ new Set();
165
- for (const addingExternalId of parsed.connectionIds) {
179
+ for (let i = 0; i < parsed.connectionIds.length; i++) {
180
+ const addingExternalId = parsed.connectionIds[i];
181
+ const correspondingToken = parsed.connectionTokens[i];
182
+ externalIdsToToken.set(addingExternalId, correspondingToken);
166
183
  if (!Number.isInteger(addingExternalId) || addingExternalId < 0) {
167
184
  this.sendMessage({
168
185
  type: "error",
@@ -195,12 +212,15 @@ var NetworkedDOMV02Connection = class {
195
212
  this,
196
213
  addedExternalUserIds
197
214
  );
198
- const internalIds = new Set(Array.from(connectionIdToExternalId.keys()));
215
+ const addingInternalIdsWithToken = /* @__PURE__ */ new Map();
199
216
  for (const [addingInternalId, addingExternalId] of connectionIdToExternalId) {
217
+ const token = externalIdsToToken.get(addingExternalId) ?? null;
218
+ addingInternalIdsWithToken.set(addingInternalId, token);
200
219
  this.externalIdToInternalId.set(addingExternalId, addingInternalId);
201
220
  this.internalIdToExternalId.set(addingInternalId, addingExternalId);
221
+ this.internalIdToToken.set(addingInternalId, token);
202
222
  }
203
- this.networkedDOM.announceConnectedUsers(internalIds);
223
+ this.networkedDOM.announceConnectedUsers(addingInternalIdsWithToken);
204
224
  }
205
225
  return;
206
226
  }
@@ -246,6 +266,7 @@ var NetworkedDOMV02Connection = class {
246
266
  this.externalConnectionIds.delete(removingExternalId);
247
267
  this.externalIdToInternalId.delete(removingExternalId);
248
268
  this.internalIdToExternalId.delete(removingInternalId);
269
+ this.internalIdToToken.delete(removingInternalId);
249
270
  }
250
271
  } else {
251
272
  const removalDiffs = this.networkedDOM.disconnectUsers(
@@ -301,7 +322,7 @@ var NetworkedDOMV02Connection = class {
301
322
 
302
323
  // src/createNetworkedDOMConnectionForWebsocket.ts
303
324
  var SupportedWebsocketSubProtocolsPreferenceOrder = [
304
- networkedDOMProtocolSubProtocol_v0_2,
325
+ ...networkedDOMProtocolSubProtocol_v0_2_SubVersionsList,
305
326
  networkedDOMProtocolSubProtocol_v0_1
306
327
  ];
307
328
  var defaultWebsocketSubProtocol = networkedDOMProtocolSubProtocol_v0_1;
@@ -336,7 +357,7 @@ function createNetworkedDOMConnectionForWebsocket(webSocket) {
336
357
  webSocket.send(JSON.stringify(warningMessage));
337
358
  assumedProtocol = defaultWebsocketSubProtocol;
338
359
  }
339
- const isV02 = assumedProtocol === networkedDOMProtocolSubProtocol_v0_2;
360
+ const isV02 = isNetworkedDOMProtocolSubProtocol_v0_22(assumedProtocol);
340
361
  if (isV02) {
341
362
  return new NetworkedDOMV02Connection(webSocket);
342
363
  }
@@ -1030,7 +1051,7 @@ function describeNodeWithChildrenForV01Connection(virtualDOMElement, networkedDO
1030
1051
  return null;
1031
1052
  }
1032
1053
  let emittedTagName = virtualDOMElement.tag;
1033
- if (emittedTagName === "#document") {
1054
+ if (emittedTagName === "#DOCUMENT") {
1034
1055
  emittedTagName = "DIV";
1035
1056
  }
1036
1057
  if (emittedTagName === "#text") {
@@ -1070,7 +1091,7 @@ function describeNodeWithChildrenForV02Connection(virtualDOMElement, networkedDO
1070
1091
  return null;
1071
1092
  }
1072
1093
  let emittedTagName = virtualDOMElement.tag;
1073
- if (emittedTagName === "#document") {
1094
+ if (emittedTagName === "#DOCUMENT") {
1074
1095
  emittedTagName = "DIV";
1075
1096
  }
1076
1097
  if (emittedTagName === "#text") {
@@ -1353,6 +1374,12 @@ var NodeManager = class {
1353
1374
  return [nodeWithSubjectivity, hasSubjectivity];
1354
1375
  }
1355
1376
  addRemappedNodeId(clientFacingNodeId, internalNodeId) {
1377
+ if (this.internalNodeIdToClientNodeId.has(internalNodeId)) {
1378
+ throw new Error("Node already exists with internal node id " + internalNodeId);
1379
+ }
1380
+ if (this.clientNodeIdToInternalNodeId.has(clientFacingNodeId)) {
1381
+ throw new Error("Node already exists with client id " + clientFacingNodeId);
1382
+ }
1356
1383
  this.internalNodeIdToClientNodeId.set(internalNodeId, clientFacingNodeId);
1357
1384
  this.clientNodeIdToInternalNodeId.set(clientFacingNodeId, internalNodeId);
1358
1385
  this.maximumNodeId = Math.max(this.maximumNodeId, Math.max(clientFacingNodeId, internalNodeId));
@@ -1366,9 +1393,9 @@ var NodeManager = class {
1366
1393
  return newId;
1367
1394
  }
1368
1395
  if (createIfCollided) {
1369
- if (this.nodeIdToNode.has(nodeId)) {
1396
+ if (this.nodeIdToNode.has(nodeId) || this.clientNodeIdToInternalNodeId.has(nodeId)) {
1370
1397
  const newId2 = ++this.maximumNodeId;
1371
- this.internalNodeIdToClientNodeId.set(nodeId, newId2);
1398
+ this.addRemappedNodeId(newId2, nodeId);
1372
1399
  return newId2;
1373
1400
  }
1374
1401
  return nodeId;
@@ -1564,18 +1591,18 @@ var NetworkedDOM = class {
1564
1591
  }
1565
1592
  }
1566
1593
  for (const networkedDOMConnection of this.networkedDOMV02Connections) {
1567
- for (const connectionId of networkedDOMConnection.internalIdToExternalId.keys()) {
1594
+ for (const [connectionId, token] of networkedDOMConnection.internalIdToToken) {
1568
1595
  if (connectionId >= this.currentConnectionId) {
1569
1596
  this.currentConnectionId = connectionId + 1;
1570
1597
  }
1571
- this.observableDOM.addConnectedUserId(connectionId);
1598
+ this.observableDOM.addConnectedUserId(connectionId, token);
1572
1599
  }
1573
1600
  }
1574
1601
  for (const networkedDOMConnection of this.networkedDOMV01Connections) {
1575
1602
  if (networkedDOMConnection.internalConnectionId === null) {
1576
1603
  networkedDOMConnection.initAsNewV01Connection();
1577
1604
  }
1578
- this.observableDOM.addConnectedUserId(networkedDOMConnection.internalConnectionId);
1605
+ this.observableDOM.addConnectedUserId(networkedDOMConnection.internalConnectionId, null);
1579
1606
  }
1580
1607
  for (const networkedDOMConnection of this.networkedDOMV02Connections) {
1581
1608
  networkedDOMConnection.handleBufferedMessages();
@@ -1684,8 +1711,8 @@ var NetworkedDOM = class {
1684
1711
  networkedDOMConnection.webSocket,
1685
1712
  networkedDOMConnection
1686
1713
  );
1687
- for (const connectionId of networkedDOMConnection.internalIdToExternalId.keys()) {
1688
- this.observableDOM.addConnectedUserId(connectionId);
1714
+ for (const [connectionId, token] of networkedDOMConnection.internalIdToToken) {
1715
+ this.observableDOM.addConnectedUserId(connectionId, token);
1689
1716
  }
1690
1717
  networkedDOMConnection.sendMessage(
1691
1718
  this.getInitialV02Snapshot(networkedDOMConnection, documentVirtualDOMElement)
@@ -1730,8 +1757,8 @@ var NetworkedDOM = class {
1730
1757
  }
1731
1758
  // Called by the connections after storing the mapping of connected users ids
1732
1759
  announceConnectedUsers(userIds) {
1733
- for (const userId of userIds) {
1734
- this.observableDOM.addConnectedUserId(userId);
1760
+ for (const [userId, token] of userIds) {
1761
+ this.observableDOM.addConnectedUserId(userId, token);
1735
1762
  }
1736
1763
  }
1737
1764
  disconnectUsers(networkedDOMConnection, removedExternalToInternalUserIds) {
@@ -1763,6 +1790,7 @@ var NetworkedDOM = class {
1763
1790
  networkedDOMConnection.externalConnectionIds.delete(removingExternalId);
1764
1791
  networkedDOMConnection.externalIdToInternalId.delete(removingExternalId);
1765
1792
  networkedDOMConnection.internalIdToExternalId.delete(removingInternalId);
1793
+ networkedDOMConnection.internalIdToToken.delete(removingInternalId);
1766
1794
  this.connectionIdToNetworkedDOMConnection.delete(removingInternalId);
1767
1795
  }
1768
1796
  const removedMessagesByParent = /* @__PURE__ */ new Map();
@@ -2684,7 +2712,7 @@ var NetworkedDOM = class {
2684
2712
  tag: staticVirtualDOMElement.tag,
2685
2713
  attributes: staticVirtualDOMElement.attributes,
2686
2714
  childNodes: staticVirtualDOMElement.childNodes.map(
2687
- (child) => this.reprojectStaticVirtualDOMElementWithMappings(child)
2715
+ (child) => this.reprojectStaticVirtualDOMElementWithMappings(child, createIfCollided)
2688
2716
  ),
2689
2717
  textContent: staticVirtualDOMElement.textContent
2690
2718
  };