@hocuspocus/provider 2.1.0-alpha.0 → 2.1.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/hocuspocus-provider.cjs +917 -915
- package/dist/hocuspocus-provider.cjs.map +1 -1
- package/dist/hocuspocus-provider.esm.js +917 -915
- package/dist/hocuspocus-provider.esm.js.map +1 -1
- package/dist/packages/common/src/CloseEvents.d.ts +29 -29
- package/dist/packages/common/src/auth.d.ts +6 -6
- package/dist/packages/common/src/awarenessStatesToArray.d.ts +3 -3
- package/dist/packages/common/src/index.d.ts +4 -4
- package/dist/packages/common/src/types.d.ts +10 -10
- package/dist/packages/extension-database/src/Database.d.ts +30 -30
- package/dist/packages/extension-database/src/index.d.ts +1 -1
- package/dist/packages/extension-logger/src/Logger.d.ts +67 -67
- package/dist/packages/extension-logger/src/index.d.ts +1 -1
- package/dist/packages/extension-redis/src/Redis.d.ts +116 -95
- package/dist/packages/extension-redis/src/index.d.ts +1 -1
- package/dist/packages/extension-sqlite/src/SQLite.d.ts +26 -26
- package/dist/packages/extension-sqlite/src/index.d.ts +1 -1
- package/dist/packages/extension-throttle/src/index.d.ts +31 -31
- package/dist/packages/extension-webhook/src/index.d.ts +57 -57
- package/dist/packages/provider/src/EventEmitter.d.ts +9 -9
- package/dist/packages/provider/src/HocuspocusProvider.d.ts +110 -110
- package/dist/packages/provider/src/HocuspocusProviderWebsocket.d.ts +115 -115
- package/dist/packages/provider/src/IncomingMessage.d.ts +16 -16
- package/dist/packages/provider/src/MessageReceiver.d.ts +13 -13
- package/dist/packages/provider/src/MessageSender.d.ts +10 -10
- package/dist/packages/provider/src/OutgoingMessage.d.ts +9 -9
- package/dist/packages/provider/src/OutgoingMessages/AuthenticationMessage.d.ts +7 -7
- package/dist/packages/provider/src/OutgoingMessages/AwarenessMessage.d.ts +8 -8
- package/dist/packages/provider/src/OutgoingMessages/CloseMessage.d.ts +8 -8
- package/dist/packages/provider/src/OutgoingMessages/QueryAwarenessMessage.d.ts +8 -8
- package/dist/packages/provider/src/OutgoingMessages/StatelessMessage.d.ts +7 -7
- package/dist/packages/provider/src/OutgoingMessages/SyncStepOneMessage.d.ts +8 -8
- package/dist/packages/provider/src/OutgoingMessages/SyncStepTwoMessage.d.ts +8 -8
- package/dist/packages/provider/src/OutgoingMessages/UpdateMessage.d.ts +7 -7
- package/dist/packages/provider/src/TiptapCollabProvider.d.ts +11 -11
- package/dist/packages/provider/src/TiptapCollabProviderWebsocket.d.ts +11 -11
- package/dist/packages/provider/src/index.d.ts +5 -5
- package/dist/packages/provider/src/types.d.ts +84 -84
- package/dist/packages/server/src/Connection.d.ts +71 -71
- package/dist/packages/server/src/Debugger.d.ts +14 -14
- package/dist/packages/server/src/DirectConnection.d.ts +13 -0
- package/dist/packages/server/src/Document.d.ts +91 -88
- package/dist/packages/server/src/Hocuspocus.d.ts +111 -108
- package/dist/packages/server/src/IncomingMessage.d.ts +21 -21
- package/dist/packages/server/src/MessageReceiver.d.ts +12 -12
- package/dist/packages/server/src/OutgoingMessage.d.ts +20 -20
- package/dist/packages/server/src/index.d.ts +8 -8
- package/dist/packages/server/src/types.d.ts +266 -264
- package/dist/packages/transformer/src/Prosemirror.d.ts +11 -11
- package/dist/packages/transformer/src/Tiptap.d.ts +10 -10
- package/dist/packages/transformer/src/index.d.ts +3 -3
- package/dist/packages/transformer/src/types.d.ts +5 -5
- package/dist/playground/backend/src/default.d.ts +1 -1
- package/dist/playground/backend/src/express.d.ts +1 -1
- package/dist/playground/backend/src/koa.d.ts +1 -1
- package/dist/playground/backend/src/load-document.d.ts +1 -1
- package/dist/playground/backend/src/redis.d.ts +1 -1
- package/dist/playground/backend/src/slow.d.ts +1 -1
- package/dist/playground/backend/src/tiptapcollab.d.ts +1 -1
- package/dist/playground/backend/src/webhook.d.ts +1 -1
- package/dist/playground/frontend/src/main.d.ts +1 -1
- package/dist/playground/frontend/vite.config.d.ts +2 -2
- package/dist/tests/extension-database/fetch.d.ts +1 -1
- package/dist/tests/extension-logger/onListen.d.ts +1 -1
- package/dist/tests/extension-redis/closeConnections.d.ts +1 -1
- package/dist/tests/extension-redis/getConnectionCount.d.ts +1 -1
- package/dist/tests/extension-redis/getDocumentsCount.d.ts +1 -1
- package/dist/tests/extension-redis/onAwarenessChange.d.ts +1 -1
- package/dist/tests/extension-redis/onChange.d.ts +1 -1
- package/dist/tests/extension-redis/onStateless.d.ts +1 -1
- package/dist/tests/extension-redis/onStoreDocument.d.ts +1 -1
- package/dist/tests/extension-throttle/banning.d.ts +1 -1
- package/dist/tests/extension-throttle/configuration.d.ts +1 -1
- package/dist/tests/provider/observe.d.ts +1 -1
- package/dist/tests/provider/observeDeep.d.ts +1 -1
- package/dist/tests/provider/onAuthenticated.d.ts +1 -1
- package/dist/tests/provider/onAuthenticationFailed.d.ts +1 -1
- package/dist/tests/provider/onAwarenessChange.d.ts +1 -1
- package/dist/tests/provider/onAwarenessUpdate.d.ts +1 -1
- package/dist/tests/provider/onClose.d.ts +1 -1
- package/dist/tests/provider/onConnect.d.ts +1 -1
- package/dist/tests/provider/onDisconnect.d.ts +1 -1
- package/dist/tests/provider/onMessage.d.ts +1 -1
- package/dist/tests/provider/onOpen.d.ts +1 -1
- package/dist/tests/provider/onStateless.d.ts +1 -1
- package/dist/tests/provider/onSynced.d.ts +1 -1
- package/dist/tests/providerwebsocket/configuration.d.ts +1 -1
- package/dist/tests/server/address.d.ts +1 -1
- package/dist/tests/server/afterStoreDocument.d.ts +1 -1
- package/dist/tests/server/beforeBroadcastStateless.d.ts +1 -1
- package/dist/tests/server/beforeHandleMessage.d.ts +1 -1
- package/dist/tests/server/closeConnections.d.ts +1 -1
- package/dist/tests/server/getConnectionsCount.d.ts +1 -1
- package/dist/tests/server/getDocumentsCount.d.ts +1 -1
- package/dist/tests/server/getMessageLogs.d.ts +1 -1
- package/dist/tests/server/listen.d.ts +1 -1
- package/dist/tests/server/onAuthenticate.d.ts +1 -1
- package/dist/tests/server/onAwarenessUpdate.d.ts +1 -1
- package/dist/tests/server/onChange.d.ts +1 -1
- package/dist/tests/server/onClose.d.ts +1 -1
- package/dist/tests/server/onConfigure.d.ts +1 -1
- package/dist/tests/server/onConnect.d.ts +1 -1
- package/dist/tests/server/onDestroy.d.ts +1 -1
- package/dist/tests/server/onDisconnect.d.ts +1 -1
- package/dist/tests/server/onListen.d.ts +1 -1
- package/dist/tests/server/onLoadDocument.d.ts +1 -1
- package/dist/tests/server/onRequest.d.ts +1 -1
- package/dist/tests/server/onStateless.d.ts +1 -1
- package/dist/tests/server/onStoreDocument.d.ts +1 -1
- package/dist/tests/server/onUpgrade.d.ts +1 -1
- package/dist/tests/server/openDirectConnection.d.ts +1 -0
- package/dist/tests/server/requiresAuthentication.d.ts +1 -1
- package/dist/tests/server/websocketError.d.ts +1 -1
- package/dist/tests/transformer/TiptapTransformer.d.ts +1 -1
- package/dist/tests/utils/createDirectory.d.ts +1 -1
- package/dist/tests/utils/flushRedis.d.ts +1 -1
- package/dist/tests/utils/index.d.ts +9 -9
- package/dist/tests/utils/newHocuspocus.d.ts +2 -2
- package/dist/tests/utils/newHocuspocusProvider.d.ts +3 -3
- package/dist/tests/utils/newHocuspocusProviderWebsocket.d.ts +3 -3
- package/dist/tests/utils/randomInteger.d.ts +1 -1
- package/dist/tests/utils/redisConnectionSettings.d.ts +4 -4
- package/dist/tests/utils/removeDirectory.d.ts +1 -1
- package/dist/tests/utils/retryableAssertion.d.ts +2 -2
- package/dist/tests/utils/sleep.d.ts +1 -1
- package/package.json +4 -3
- package/src/HocuspocusProvider.ts +20 -16
- package/src/HocuspocusProviderWebsocket.ts +4 -3
- package/src/IncomingMessage.ts +1 -1
- package/src/MessageReceiver.ts +4 -4
- package/src/MessageSender.ts +1 -1
- package/src/OutgoingMessage.ts +1 -1
- package/src/OutgoingMessages/AuthenticationMessage.ts +2 -2
- package/src/OutgoingMessages/AwarenessMessage.ts +2 -2
- package/src/OutgoingMessages/CloseMessage.ts +2 -2
- package/src/OutgoingMessages/QueryAwarenessMessage.ts +2 -2
- package/src/OutgoingMessages/StatelessMessage.ts +2 -2
- package/src/OutgoingMessages/SyncStepOneMessage.ts +2 -2
- package/src/OutgoingMessages/SyncStepTwoMessage.ts +2 -2
- package/src/OutgoingMessages/UpdateMessage.ts +2 -2
- package/src/TiptapCollabProvider.ts +2 -2
- package/src/TiptapCollabProviderWebsocket.ts +1 -1
- package/src/index.ts +5 -5
- package/src/types.ts +8 -8
|
@@ -1530,68 +1530,68 @@ const createMutex = () => {
|
|
|
1530
1530
|
}
|
|
1531
1531
|
};
|
|
1532
1532
|
|
|
1533
|
-
class EventEmitter {
|
|
1534
|
-
constructor() {
|
|
1535
|
-
this.callbacks = {};
|
|
1536
|
-
}
|
|
1537
|
-
on(event, fn) {
|
|
1538
|
-
if (!this.callbacks[event]) {
|
|
1539
|
-
this.callbacks[event] = [];
|
|
1540
|
-
}
|
|
1541
|
-
this.callbacks[event].push(fn);
|
|
1542
|
-
return this;
|
|
1543
|
-
}
|
|
1544
|
-
emit(event, ...args) {
|
|
1545
|
-
const callbacks = this.callbacks[event];
|
|
1546
|
-
if (callbacks) {
|
|
1547
|
-
callbacks.forEach(callback => callback.apply(this, args));
|
|
1548
|
-
}
|
|
1549
|
-
return this;
|
|
1550
|
-
}
|
|
1551
|
-
off(event, fn) {
|
|
1552
|
-
const callbacks = this.callbacks[event];
|
|
1553
|
-
if (callbacks) {
|
|
1554
|
-
if (fn) {
|
|
1555
|
-
this.callbacks[event] = callbacks.filter(callback => callback !== fn);
|
|
1556
|
-
}
|
|
1557
|
-
else {
|
|
1558
|
-
delete this.callbacks[event];
|
|
1559
|
-
}
|
|
1560
|
-
}
|
|
1561
|
-
return this;
|
|
1562
|
-
}
|
|
1563
|
-
removeAllListeners() {
|
|
1564
|
-
this.callbacks = {};
|
|
1565
|
-
}
|
|
1533
|
+
class EventEmitter {
|
|
1534
|
+
constructor() {
|
|
1535
|
+
this.callbacks = {};
|
|
1536
|
+
}
|
|
1537
|
+
on(event, fn) {
|
|
1538
|
+
if (!this.callbacks[event]) {
|
|
1539
|
+
this.callbacks[event] = [];
|
|
1540
|
+
}
|
|
1541
|
+
this.callbacks[event].push(fn);
|
|
1542
|
+
return this;
|
|
1543
|
+
}
|
|
1544
|
+
emit(event, ...args) {
|
|
1545
|
+
const callbacks = this.callbacks[event];
|
|
1546
|
+
if (callbacks) {
|
|
1547
|
+
callbacks.forEach(callback => callback.apply(this, args));
|
|
1548
|
+
}
|
|
1549
|
+
return this;
|
|
1550
|
+
}
|
|
1551
|
+
off(event, fn) {
|
|
1552
|
+
const callbacks = this.callbacks[event];
|
|
1553
|
+
if (callbacks) {
|
|
1554
|
+
if (fn) {
|
|
1555
|
+
this.callbacks[event] = callbacks.filter(callback => callback !== fn);
|
|
1556
|
+
}
|
|
1557
|
+
else {
|
|
1558
|
+
delete this.callbacks[event];
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
return this;
|
|
1562
|
+
}
|
|
1563
|
+
removeAllListeners() {
|
|
1564
|
+
this.callbacks = {};
|
|
1565
|
+
}
|
|
1566
1566
|
}
|
|
1567
1567
|
|
|
1568
|
-
class IncomingMessage {
|
|
1569
|
-
constructor(data) {
|
|
1570
|
-
this.data = data;
|
|
1571
|
-
this.encoder = createEncoder();
|
|
1572
|
-
this.decoder = createDecoder(new Uint8Array(this.data));
|
|
1573
|
-
}
|
|
1574
|
-
readVarUint() {
|
|
1575
|
-
return readVarUint(this.decoder);
|
|
1576
|
-
}
|
|
1577
|
-
readVarString() {
|
|
1578
|
-
return readVarString(this.decoder);
|
|
1579
|
-
}
|
|
1580
|
-
readVarUint8Array() {
|
|
1581
|
-
return readVarUint8Array(this.decoder);
|
|
1582
|
-
}
|
|
1583
|
-
writeVarUint(type) {
|
|
1584
|
-
return writeVarUint(this.encoder, type);
|
|
1585
|
-
}
|
|
1586
|
-
writeVarString(string) {
|
|
1587
|
-
return writeVarString(this.encoder, string);
|
|
1588
|
-
}
|
|
1589
|
-
writeVarUint8Array(data) {
|
|
1590
|
-
return writeVarUint8Array(this.encoder, data);
|
|
1591
|
-
}
|
|
1592
|
-
length() {
|
|
1593
|
-
return length(this.encoder);
|
|
1594
|
-
}
|
|
1568
|
+
class IncomingMessage {
|
|
1569
|
+
constructor(data) {
|
|
1570
|
+
this.data = data;
|
|
1571
|
+
this.encoder = createEncoder();
|
|
1572
|
+
this.decoder = createDecoder(new Uint8Array(this.data));
|
|
1573
|
+
}
|
|
1574
|
+
readVarUint() {
|
|
1575
|
+
return readVarUint(this.decoder);
|
|
1576
|
+
}
|
|
1577
|
+
readVarString() {
|
|
1578
|
+
return readVarString(this.decoder);
|
|
1579
|
+
}
|
|
1580
|
+
readVarUint8Array() {
|
|
1581
|
+
return readVarUint8Array(this.decoder);
|
|
1582
|
+
}
|
|
1583
|
+
writeVarUint(type) {
|
|
1584
|
+
return writeVarUint(this.encoder, type);
|
|
1585
|
+
}
|
|
1586
|
+
writeVarString(string) {
|
|
1587
|
+
return writeVarString(this.encoder, string);
|
|
1588
|
+
}
|
|
1589
|
+
writeVarUint8Array(data) {
|
|
1590
|
+
return writeVarUint8Array(this.encoder, data);
|
|
1591
|
+
}
|
|
1592
|
+
length() {
|
|
1593
|
+
return length(this.encoder);
|
|
1594
|
+
}
|
|
1595
1595
|
}
|
|
1596
1596
|
|
|
1597
1597
|
/**
|
|
@@ -1721,231 +1721,231 @@ const readSyncMessage = (decoder, encoder, doc, transactionOrigin) => {
|
|
|
1721
1721
|
return messageType
|
|
1722
1722
|
};
|
|
1723
1723
|
|
|
1724
|
-
exports.MessageType = void 0;
|
|
1725
|
-
(function (MessageType) {
|
|
1726
|
-
MessageType[MessageType["Sync"] = 0] = "Sync";
|
|
1727
|
-
MessageType[MessageType["Awareness"] = 1] = "Awareness";
|
|
1728
|
-
MessageType[MessageType["Auth"] = 2] = "Auth";
|
|
1729
|
-
MessageType[MessageType["QueryAwareness"] = 3] = "QueryAwareness";
|
|
1730
|
-
MessageType[MessageType["Stateless"] = 5] = "Stateless";
|
|
1731
|
-
MessageType[MessageType["CLOSE"] = 7] = "CLOSE";
|
|
1732
|
-
})(exports.MessageType || (exports.MessageType = {}));
|
|
1733
|
-
exports.WebSocketStatus = void 0;
|
|
1734
|
-
(function (WebSocketStatus) {
|
|
1735
|
-
WebSocketStatus["Connecting"] = "connecting";
|
|
1736
|
-
WebSocketStatus["Connected"] = "connected";
|
|
1737
|
-
WebSocketStatus["Disconnected"] = "disconnected";
|
|
1724
|
+
exports.MessageType = void 0;
|
|
1725
|
+
(function (MessageType) {
|
|
1726
|
+
MessageType[MessageType["Sync"] = 0] = "Sync";
|
|
1727
|
+
MessageType[MessageType["Awareness"] = 1] = "Awareness";
|
|
1728
|
+
MessageType[MessageType["Auth"] = 2] = "Auth";
|
|
1729
|
+
MessageType[MessageType["QueryAwareness"] = 3] = "QueryAwareness";
|
|
1730
|
+
MessageType[MessageType["Stateless"] = 5] = "Stateless";
|
|
1731
|
+
MessageType[MessageType["CLOSE"] = 7] = "CLOSE";
|
|
1732
|
+
})(exports.MessageType || (exports.MessageType = {}));
|
|
1733
|
+
exports.WebSocketStatus = void 0;
|
|
1734
|
+
(function (WebSocketStatus) {
|
|
1735
|
+
WebSocketStatus["Connecting"] = "connecting";
|
|
1736
|
+
WebSocketStatus["Connected"] = "connected";
|
|
1737
|
+
WebSocketStatus["Disconnected"] = "disconnected";
|
|
1738
1738
|
})(exports.WebSocketStatus || (exports.WebSocketStatus = {}));
|
|
1739
1739
|
|
|
1740
|
-
class OutgoingMessage {
|
|
1741
|
-
constructor() {
|
|
1742
|
-
this.encoder = createEncoder();
|
|
1743
|
-
}
|
|
1744
|
-
get(args) {
|
|
1745
|
-
return args.encoder;
|
|
1746
|
-
}
|
|
1747
|
-
toUint8Array() {
|
|
1748
|
-
return toUint8Array(this.encoder);
|
|
1749
|
-
}
|
|
1740
|
+
class OutgoingMessage {
|
|
1741
|
+
constructor() {
|
|
1742
|
+
this.encoder = createEncoder();
|
|
1743
|
+
}
|
|
1744
|
+
get(args) {
|
|
1745
|
+
return args.encoder;
|
|
1746
|
+
}
|
|
1747
|
+
toUint8Array() {
|
|
1748
|
+
return toUint8Array(this.encoder);
|
|
1749
|
+
}
|
|
1750
1750
|
}
|
|
1751
1751
|
|
|
1752
|
-
class MessageReceiver {
|
|
1753
|
-
constructor(message) {
|
|
1754
|
-
this.broadcasted = false;
|
|
1755
|
-
this.message = message;
|
|
1756
|
-
}
|
|
1757
|
-
setBroadcasted(value) {
|
|
1758
|
-
this.broadcasted = value;
|
|
1759
|
-
return this;
|
|
1760
|
-
}
|
|
1761
|
-
apply(provider, emitSynced = true) {
|
|
1762
|
-
const { message } = this;
|
|
1763
|
-
const type = message.readVarUint();
|
|
1764
|
-
const emptyMessageLength = message.length();
|
|
1765
|
-
switch (type) {
|
|
1766
|
-
case exports.MessageType.Sync:
|
|
1767
|
-
this.applySyncMessage(provider, emitSynced);
|
|
1768
|
-
break;
|
|
1769
|
-
case exports.MessageType.Awareness:
|
|
1770
|
-
this.applyAwarenessMessage(provider);
|
|
1771
|
-
break;
|
|
1772
|
-
case exports.MessageType.Auth:
|
|
1773
|
-
this.applyAuthMessage(provider);
|
|
1774
|
-
break;
|
|
1775
|
-
case exports.MessageType.QueryAwareness:
|
|
1776
|
-
this.applyQueryAwarenessMessage(provider);
|
|
1777
|
-
break;
|
|
1778
|
-
case exports.MessageType.Stateless:
|
|
1779
|
-
provider.receiveStateless(readVarString(message.decoder));
|
|
1780
|
-
break;
|
|
1781
|
-
default:
|
|
1782
|
-
throw new Error(`Can’t apply message of unknown type: ${type}`);
|
|
1783
|
-
}
|
|
1784
|
-
// Reply
|
|
1785
|
-
if (message.length() > emptyMessageLength + 1) { // length of documentName (considered in emptyMessageLength plus length of yjs sync type, set in applySyncMessage)
|
|
1786
|
-
if (this.broadcasted) {
|
|
1787
|
-
// TODO: Some weird TypeScript error
|
|
1788
|
-
// @ts-ignore
|
|
1789
|
-
provider.broadcast(OutgoingMessage, { encoder: message.encoder });
|
|
1790
|
-
}
|
|
1791
|
-
else {
|
|
1792
|
-
// TODO: Some weird TypeScript error
|
|
1793
|
-
// @ts-ignore
|
|
1794
|
-
provider.send(OutgoingMessage, { encoder: message.encoder });
|
|
1795
|
-
}
|
|
1796
|
-
}
|
|
1797
|
-
}
|
|
1798
|
-
applySyncMessage(provider, emitSynced) {
|
|
1799
|
-
const { message } = this;
|
|
1800
|
-
message.writeVarUint(exports.MessageType.Sync);
|
|
1801
|
-
// Apply update
|
|
1802
|
-
const syncMessageType = readSyncMessage(message.decoder, message.encoder, provider.document, provider);
|
|
1803
|
-
// Synced once we receive Step2
|
|
1804
|
-
if (emitSynced && syncMessageType === messageYjsSyncStep2) {
|
|
1805
|
-
provider.synced = true;
|
|
1806
|
-
}
|
|
1807
|
-
if (syncMessageType === messageYjsUpdate || syncMessageType === messageYjsSyncStep2) {
|
|
1808
|
-
if (provider.unsyncedChanges > 0) {
|
|
1809
|
-
provider.updateUnsyncedChanges(-1);
|
|
1810
|
-
}
|
|
1811
|
-
}
|
|
1812
|
-
}
|
|
1813
|
-
applyAwarenessMessage(provider) {
|
|
1814
|
-
const { message } = this;
|
|
1815
|
-
applyAwarenessUpdate(provider.awareness, message.readVarUint8Array(), provider);
|
|
1816
|
-
}
|
|
1817
|
-
applyAuthMessage(provider) {
|
|
1818
|
-
const { message } = this;
|
|
1819
|
-
common.readAuthMessage(message.decoder, provider.permissionDeniedHandler.bind(provider), provider.authenticatedHandler.bind(provider));
|
|
1820
|
-
}
|
|
1821
|
-
applyQueryAwarenessMessage(provider) {
|
|
1822
|
-
const { message } = this;
|
|
1823
|
-
message.writeVarUint(exports.MessageType.Awareness);
|
|
1824
|
-
message.writeVarUint8Array(encodeAwarenessUpdate(provider.awareness, Array.from(provider.awareness.getStates().keys())));
|
|
1825
|
-
}
|
|
1752
|
+
class MessageReceiver {
|
|
1753
|
+
constructor(message) {
|
|
1754
|
+
this.broadcasted = false;
|
|
1755
|
+
this.message = message;
|
|
1756
|
+
}
|
|
1757
|
+
setBroadcasted(value) {
|
|
1758
|
+
this.broadcasted = value;
|
|
1759
|
+
return this;
|
|
1760
|
+
}
|
|
1761
|
+
apply(provider, emitSynced = true) {
|
|
1762
|
+
const { message } = this;
|
|
1763
|
+
const type = message.readVarUint();
|
|
1764
|
+
const emptyMessageLength = message.length();
|
|
1765
|
+
switch (type) {
|
|
1766
|
+
case exports.MessageType.Sync:
|
|
1767
|
+
this.applySyncMessage(provider, emitSynced);
|
|
1768
|
+
break;
|
|
1769
|
+
case exports.MessageType.Awareness:
|
|
1770
|
+
this.applyAwarenessMessage(provider);
|
|
1771
|
+
break;
|
|
1772
|
+
case exports.MessageType.Auth:
|
|
1773
|
+
this.applyAuthMessage(provider);
|
|
1774
|
+
break;
|
|
1775
|
+
case exports.MessageType.QueryAwareness:
|
|
1776
|
+
this.applyQueryAwarenessMessage(provider);
|
|
1777
|
+
break;
|
|
1778
|
+
case exports.MessageType.Stateless:
|
|
1779
|
+
provider.receiveStateless(readVarString(message.decoder));
|
|
1780
|
+
break;
|
|
1781
|
+
default:
|
|
1782
|
+
throw new Error(`Can’t apply message of unknown type: ${type}`);
|
|
1783
|
+
}
|
|
1784
|
+
// Reply
|
|
1785
|
+
if (message.length() > emptyMessageLength + 1) { // length of documentName (considered in emptyMessageLength plus length of yjs sync type, set in applySyncMessage)
|
|
1786
|
+
if (this.broadcasted) {
|
|
1787
|
+
// TODO: Some weird TypeScript error
|
|
1788
|
+
// @ts-ignore
|
|
1789
|
+
provider.broadcast(OutgoingMessage, { encoder: message.encoder });
|
|
1790
|
+
}
|
|
1791
|
+
else {
|
|
1792
|
+
// TODO: Some weird TypeScript error
|
|
1793
|
+
// @ts-ignore
|
|
1794
|
+
provider.send(OutgoingMessage, { encoder: message.encoder });
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
applySyncMessage(provider, emitSynced) {
|
|
1799
|
+
const { message } = this;
|
|
1800
|
+
message.writeVarUint(exports.MessageType.Sync);
|
|
1801
|
+
// Apply update
|
|
1802
|
+
const syncMessageType = readSyncMessage(message.decoder, message.encoder, provider.document, provider);
|
|
1803
|
+
// Synced once we receive Step2
|
|
1804
|
+
if (emitSynced && syncMessageType === messageYjsSyncStep2) {
|
|
1805
|
+
provider.synced = true;
|
|
1806
|
+
}
|
|
1807
|
+
if (syncMessageType === messageYjsUpdate || syncMessageType === messageYjsSyncStep2) {
|
|
1808
|
+
if (provider.unsyncedChanges > 0) {
|
|
1809
|
+
provider.updateUnsyncedChanges(-1);
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
applyAwarenessMessage(provider) {
|
|
1814
|
+
const { message } = this;
|
|
1815
|
+
applyAwarenessUpdate(provider.awareness, message.readVarUint8Array(), provider);
|
|
1816
|
+
}
|
|
1817
|
+
applyAuthMessage(provider) {
|
|
1818
|
+
const { message } = this;
|
|
1819
|
+
common.readAuthMessage(message.decoder, provider.permissionDeniedHandler.bind(provider), provider.authenticatedHandler.bind(provider));
|
|
1820
|
+
}
|
|
1821
|
+
applyQueryAwarenessMessage(provider) {
|
|
1822
|
+
const { message } = this;
|
|
1823
|
+
message.writeVarUint(exports.MessageType.Awareness);
|
|
1824
|
+
message.writeVarUint8Array(encodeAwarenessUpdate(provider.awareness, Array.from(provider.awareness.getStates().keys())));
|
|
1825
|
+
}
|
|
1826
1826
|
}
|
|
1827
1827
|
|
|
1828
|
-
class MessageSender {
|
|
1829
|
-
constructor(Message, args = {}) {
|
|
1830
|
-
this.message = new Message();
|
|
1831
|
-
this.encoder = this.message.get(args);
|
|
1832
|
-
}
|
|
1833
|
-
create() {
|
|
1834
|
-
return toUint8Array(this.encoder);
|
|
1835
|
-
}
|
|
1836
|
-
send(webSocket) {
|
|
1837
|
-
webSocket === null || webSocket === void 0 ? void 0 : webSocket.send(this.create());
|
|
1838
|
-
}
|
|
1839
|
-
broadcast(channel) {
|
|
1840
|
-
publish(channel, this.create());
|
|
1841
|
-
}
|
|
1828
|
+
class MessageSender {
|
|
1829
|
+
constructor(Message, args = {}) {
|
|
1830
|
+
this.message = new Message();
|
|
1831
|
+
this.encoder = this.message.get(args);
|
|
1832
|
+
}
|
|
1833
|
+
create() {
|
|
1834
|
+
return toUint8Array(this.encoder);
|
|
1835
|
+
}
|
|
1836
|
+
send(webSocket) {
|
|
1837
|
+
webSocket === null || webSocket === void 0 ? void 0 : webSocket.send(this.create());
|
|
1838
|
+
}
|
|
1839
|
+
broadcast(channel) {
|
|
1840
|
+
publish(channel, this.create());
|
|
1841
|
+
}
|
|
1842
1842
|
}
|
|
1843
1843
|
|
|
1844
|
-
class SyncStepOneMessage extends OutgoingMessage {
|
|
1845
|
-
constructor() {
|
|
1846
|
-
super(...arguments);
|
|
1847
|
-
this.type = exports.MessageType.Sync;
|
|
1848
|
-
this.description = 'First sync step';
|
|
1849
|
-
}
|
|
1850
|
-
get(args) {
|
|
1851
|
-
if (typeof args.document === 'undefined') {
|
|
1852
|
-
throw new Error('The sync step one message requires document as an argument');
|
|
1853
|
-
}
|
|
1854
|
-
writeVarString(this.encoder, args.documentName);
|
|
1855
|
-
writeVarUint(this.encoder, this.type);
|
|
1856
|
-
writeSyncStep1(this.encoder, args.document);
|
|
1857
|
-
return this.encoder;
|
|
1858
|
-
}
|
|
1844
|
+
class SyncStepOneMessage extends OutgoingMessage {
|
|
1845
|
+
constructor() {
|
|
1846
|
+
super(...arguments);
|
|
1847
|
+
this.type = exports.MessageType.Sync;
|
|
1848
|
+
this.description = 'First sync step';
|
|
1849
|
+
}
|
|
1850
|
+
get(args) {
|
|
1851
|
+
if (typeof args.document === 'undefined') {
|
|
1852
|
+
throw new Error('The sync step one message requires document as an argument');
|
|
1853
|
+
}
|
|
1854
|
+
writeVarString(this.encoder, args.documentName);
|
|
1855
|
+
writeVarUint(this.encoder, this.type);
|
|
1856
|
+
writeSyncStep1(this.encoder, args.document);
|
|
1857
|
+
return this.encoder;
|
|
1858
|
+
}
|
|
1859
1859
|
}
|
|
1860
1860
|
|
|
1861
|
-
class SyncStepTwoMessage extends OutgoingMessage {
|
|
1862
|
-
constructor() {
|
|
1863
|
-
super(...arguments);
|
|
1864
|
-
this.type = exports.MessageType.Sync;
|
|
1865
|
-
this.description = 'Second sync step';
|
|
1866
|
-
}
|
|
1867
|
-
get(args) {
|
|
1868
|
-
if (typeof args.document === 'undefined') {
|
|
1869
|
-
throw new Error('The sync step two message requires document as an argument');
|
|
1870
|
-
}
|
|
1871
|
-
writeVarString(this.encoder, args.documentName);
|
|
1872
|
-
writeVarUint(this.encoder, this.type);
|
|
1873
|
-
writeSyncStep2(this.encoder, args.document);
|
|
1874
|
-
return this.encoder;
|
|
1875
|
-
}
|
|
1861
|
+
class SyncStepTwoMessage extends OutgoingMessage {
|
|
1862
|
+
constructor() {
|
|
1863
|
+
super(...arguments);
|
|
1864
|
+
this.type = exports.MessageType.Sync;
|
|
1865
|
+
this.description = 'Second sync step';
|
|
1866
|
+
}
|
|
1867
|
+
get(args) {
|
|
1868
|
+
if (typeof args.document === 'undefined') {
|
|
1869
|
+
throw new Error('The sync step two message requires document as an argument');
|
|
1870
|
+
}
|
|
1871
|
+
writeVarString(this.encoder, args.documentName);
|
|
1872
|
+
writeVarUint(this.encoder, this.type);
|
|
1873
|
+
writeSyncStep2(this.encoder, args.document);
|
|
1874
|
+
return this.encoder;
|
|
1875
|
+
}
|
|
1876
1876
|
}
|
|
1877
1877
|
|
|
1878
|
-
class QueryAwarenessMessage extends OutgoingMessage {
|
|
1879
|
-
constructor() {
|
|
1880
|
-
super(...arguments);
|
|
1881
|
-
this.type = exports.MessageType.QueryAwareness;
|
|
1882
|
-
this.description = 'Queries awareness states';
|
|
1883
|
-
}
|
|
1884
|
-
get(args) {
|
|
1885
|
-
console.log('queryAwareness: writing string docName', args.documentName);
|
|
1886
|
-
console.log(this.encoder.cpos);
|
|
1887
|
-
writeVarString(this.encoder, args.documentName);
|
|
1888
|
-
writeVarUint(this.encoder, this.type);
|
|
1889
|
-
return this.encoder;
|
|
1890
|
-
}
|
|
1878
|
+
class QueryAwarenessMessage extends OutgoingMessage {
|
|
1879
|
+
constructor() {
|
|
1880
|
+
super(...arguments);
|
|
1881
|
+
this.type = exports.MessageType.QueryAwareness;
|
|
1882
|
+
this.description = 'Queries awareness states';
|
|
1883
|
+
}
|
|
1884
|
+
get(args) {
|
|
1885
|
+
console.log('queryAwareness: writing string docName', args.documentName);
|
|
1886
|
+
console.log(this.encoder.cpos);
|
|
1887
|
+
writeVarString(this.encoder, args.documentName);
|
|
1888
|
+
writeVarUint(this.encoder, this.type);
|
|
1889
|
+
return this.encoder;
|
|
1890
|
+
}
|
|
1891
1891
|
}
|
|
1892
1892
|
|
|
1893
|
-
class AuthenticationMessage extends OutgoingMessage {
|
|
1894
|
-
constructor() {
|
|
1895
|
-
super(...arguments);
|
|
1896
|
-
this.type = exports.MessageType.Auth;
|
|
1897
|
-
this.description = 'Authentication';
|
|
1898
|
-
}
|
|
1899
|
-
get(args) {
|
|
1900
|
-
if (typeof args.token === 'undefined') {
|
|
1901
|
-
throw new Error('The authentication message requires `token` as an argument.');
|
|
1902
|
-
}
|
|
1903
|
-
writeVarString(this.encoder, args.documentName);
|
|
1904
|
-
writeVarUint(this.encoder, this.type);
|
|
1905
|
-
common.writeAuthentication(this.encoder, args.token);
|
|
1906
|
-
return this.encoder;
|
|
1907
|
-
}
|
|
1893
|
+
class AuthenticationMessage extends OutgoingMessage {
|
|
1894
|
+
constructor() {
|
|
1895
|
+
super(...arguments);
|
|
1896
|
+
this.type = exports.MessageType.Auth;
|
|
1897
|
+
this.description = 'Authentication';
|
|
1898
|
+
}
|
|
1899
|
+
get(args) {
|
|
1900
|
+
if (typeof args.token === 'undefined') {
|
|
1901
|
+
throw new Error('The authentication message requires `token` as an argument.');
|
|
1902
|
+
}
|
|
1903
|
+
writeVarString(this.encoder, args.documentName);
|
|
1904
|
+
writeVarUint(this.encoder, this.type);
|
|
1905
|
+
common.writeAuthentication(this.encoder, args.token);
|
|
1906
|
+
return this.encoder;
|
|
1907
|
+
}
|
|
1908
1908
|
}
|
|
1909
1909
|
|
|
1910
|
-
class AwarenessMessage extends OutgoingMessage {
|
|
1911
|
-
constructor() {
|
|
1912
|
-
super(...arguments);
|
|
1913
|
-
this.type = exports.MessageType.Awareness;
|
|
1914
|
-
this.description = 'Awareness states update';
|
|
1915
|
-
}
|
|
1916
|
-
get(args) {
|
|
1917
|
-
if (typeof args.awareness === 'undefined') {
|
|
1918
|
-
throw new Error('The awareness message requires awareness as an argument');
|
|
1919
|
-
}
|
|
1920
|
-
if (typeof args.clients === 'undefined') {
|
|
1921
|
-
throw new Error('The awareness message requires clients as an argument');
|
|
1922
|
-
}
|
|
1923
|
-
writeVarString(this.encoder, args.documentName);
|
|
1924
|
-
writeVarUint(this.encoder, this.type);
|
|
1925
|
-
let awarenessUpdate;
|
|
1926
|
-
if (args.states === undefined) {
|
|
1927
|
-
awarenessUpdate = encodeAwarenessUpdate(args.awareness, args.clients);
|
|
1928
|
-
}
|
|
1929
|
-
else {
|
|
1930
|
-
awarenessUpdate = encodeAwarenessUpdate(args.awareness, args.clients, args.states);
|
|
1931
|
-
}
|
|
1932
|
-
writeVarUint8Array(this.encoder, awarenessUpdate);
|
|
1933
|
-
return this.encoder;
|
|
1934
|
-
}
|
|
1910
|
+
class AwarenessMessage extends OutgoingMessage {
|
|
1911
|
+
constructor() {
|
|
1912
|
+
super(...arguments);
|
|
1913
|
+
this.type = exports.MessageType.Awareness;
|
|
1914
|
+
this.description = 'Awareness states update';
|
|
1915
|
+
}
|
|
1916
|
+
get(args) {
|
|
1917
|
+
if (typeof args.awareness === 'undefined') {
|
|
1918
|
+
throw new Error('The awareness message requires awareness as an argument');
|
|
1919
|
+
}
|
|
1920
|
+
if (typeof args.clients === 'undefined') {
|
|
1921
|
+
throw new Error('The awareness message requires clients as an argument');
|
|
1922
|
+
}
|
|
1923
|
+
writeVarString(this.encoder, args.documentName);
|
|
1924
|
+
writeVarUint(this.encoder, this.type);
|
|
1925
|
+
let awarenessUpdate;
|
|
1926
|
+
if (args.states === undefined) {
|
|
1927
|
+
awarenessUpdate = encodeAwarenessUpdate(args.awareness, args.clients);
|
|
1928
|
+
}
|
|
1929
|
+
else {
|
|
1930
|
+
awarenessUpdate = encodeAwarenessUpdate(args.awareness, args.clients, args.states);
|
|
1931
|
+
}
|
|
1932
|
+
writeVarUint8Array(this.encoder, awarenessUpdate);
|
|
1933
|
+
return this.encoder;
|
|
1934
|
+
}
|
|
1935
1935
|
}
|
|
1936
1936
|
|
|
1937
|
-
class UpdateMessage extends OutgoingMessage {
|
|
1938
|
-
constructor() {
|
|
1939
|
-
super(...arguments);
|
|
1940
|
-
this.type = exports.MessageType.Sync;
|
|
1941
|
-
this.description = 'A document update';
|
|
1942
|
-
}
|
|
1943
|
-
get(args) {
|
|
1944
|
-
writeVarString(this.encoder, args.documentName);
|
|
1945
|
-
writeVarUint(this.encoder, this.type);
|
|
1946
|
-
writeUpdate(this.encoder, args.update);
|
|
1947
|
-
return this.encoder;
|
|
1948
|
-
}
|
|
1937
|
+
class UpdateMessage extends OutgoingMessage {
|
|
1938
|
+
constructor() {
|
|
1939
|
+
super(...arguments);
|
|
1940
|
+
this.type = exports.MessageType.Sync;
|
|
1941
|
+
this.description = 'A document update';
|
|
1942
|
+
}
|
|
1943
|
+
get(args) {
|
|
1944
|
+
writeVarString(this.encoder, args.documentName);
|
|
1945
|
+
writeVarUint(this.encoder, this.type);
|
|
1946
|
+
writeUpdate(this.encoder, args.update);
|
|
1947
|
+
return this.encoder;
|
|
1948
|
+
}
|
|
1949
1949
|
}
|
|
1950
1950
|
|
|
1951
1951
|
/**
|
|
@@ -1961,664 +1961,666 @@ class UpdateMessage extends OutgoingMessage {
|
|
|
1961
1961
|
const encodeQueryParams = params =>
|
|
1962
1962
|
map(params, (val, key) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`).join('&');
|
|
1963
1963
|
|
|
1964
|
-
class HocuspocusProviderWebsocket extends EventEmitter {
|
|
1965
|
-
constructor(configuration) {
|
|
1966
|
-
super();
|
|
1967
|
-
this.configuration = {
|
|
1968
|
-
url: '',
|
|
1969
|
-
// @ts-ignore
|
|
1970
|
-
document: undefined,
|
|
1971
|
-
// @ts-ignore
|
|
1972
|
-
awareness: undefined,
|
|
1973
|
-
WebSocketPolyfill: undefined,
|
|
1974
|
-
parameters: {},
|
|
1975
|
-
connect: true,
|
|
1976
|
-
broadcast: true,
|
|
1977
|
-
forceSyncInterval: false,
|
|
1978
|
-
// TODO: this should depend on awareness.outdatedTime
|
|
1979
|
-
messageReconnectTimeout: 30000,
|
|
1980
|
-
// 1 second
|
|
1981
|
-
delay: 1000,
|
|
1982
|
-
// instant
|
|
1983
|
-
initialDelay: 0,
|
|
1984
|
-
// double the delay each time
|
|
1985
|
-
factor: 2,
|
|
1986
|
-
// unlimited retries
|
|
1987
|
-
maxAttempts: 0,
|
|
1988
|
-
// wait at least 1 second
|
|
1989
|
-
minDelay: 1000,
|
|
1990
|
-
// at least every 30 seconds
|
|
1991
|
-
maxDelay: 30000,
|
|
1992
|
-
// randomize
|
|
1993
|
-
jitter: true,
|
|
1994
|
-
// retry forever
|
|
1995
|
-
timeout: 0,
|
|
1996
|
-
onOpen: () => null,
|
|
1997
|
-
onConnect: () => null,
|
|
1998
|
-
onMessage: () => null,
|
|
1999
|
-
onOutgoingMessage: () => null,
|
|
2000
|
-
onStatus: () => null,
|
|
2001
|
-
onDisconnect: () => null,
|
|
2002
|
-
onClose: () => null,
|
|
2003
|
-
onDestroy: () => null,
|
|
2004
|
-
onAwarenessUpdate: () => null,
|
|
2005
|
-
onAwarenessChange: () => null,
|
|
2006
|
-
quiet: false,
|
|
2007
|
-
};
|
|
2008
|
-
this.subscribedToBroadcastChannel = false;
|
|
2009
|
-
this.webSocket = null;
|
|
2010
|
-
this.shouldConnect = true;
|
|
2011
|
-
this.status = exports.WebSocketStatus.Disconnected;
|
|
2012
|
-
this.lastMessageReceived = 0;
|
|
2013
|
-
this.mux = createMutex();
|
|
2014
|
-
this.intervals = {
|
|
2015
|
-
forceSync: null,
|
|
2016
|
-
connectionChecker: null,
|
|
2017
|
-
};
|
|
2018
|
-
this.connectionAttempt = null;
|
|
2019
|
-
this.receivedOnOpenPayload = undefined;
|
|
2020
|
-
this.receivedOnStatusPayload = undefined;
|
|
2021
|
-
this.boundConnect = this.connect.bind(this);
|
|
2022
|
-
this.setConfiguration(configuration);
|
|
2023
|
-
this.configuration.WebSocketPolyfill = configuration.WebSocketPolyfill ? configuration.WebSocketPolyfill : WebSocket;
|
|
2024
|
-
this.on('open', this.configuration.onOpen);
|
|
2025
|
-
this.on('open', this.onOpen.bind(this));
|
|
2026
|
-
this.on('connect', this.configuration.onConnect);
|
|
2027
|
-
this.on('message', this.configuration.onMessage);
|
|
2028
|
-
this.on('outgoingMessage', this.configuration.onOutgoingMessage);
|
|
2029
|
-
this.on('status', this.configuration.onStatus);
|
|
2030
|
-
this.on('status', this.onStatus.bind(this));
|
|
2031
|
-
this.on('disconnect', this.configuration.onDisconnect);
|
|
2032
|
-
this.on('close', this.configuration.onClose);
|
|
2033
|
-
this.on('destroy', this.configuration.onDestroy);
|
|
2034
|
-
this.on('awarenessUpdate', this.configuration.onAwarenessUpdate);
|
|
2035
|
-
this.on('awarenessChange', this.configuration.onAwarenessChange);
|
|
2036
|
-
this.on('close', this.onClose.bind(this));
|
|
2037
|
-
this.on('message', this.onMessage.bind(this));
|
|
2038
|
-
this.registerEventListeners();
|
|
2039
|
-
this.intervals.connectionChecker = setInterval(this.checkConnection.bind(this), this.configuration.messageReconnectTimeout / 10);
|
|
2040
|
-
if (typeof configuration.connect !== 'undefined') {
|
|
2041
|
-
this.shouldConnect = configuration.connect;
|
|
2042
|
-
}
|
|
2043
|
-
if (!this.shouldConnect) {
|
|
2044
|
-
return;
|
|
2045
|
-
}
|
|
2046
|
-
this.connect();
|
|
2047
|
-
}
|
|
2048
|
-
async onOpen(event) {
|
|
2049
|
-
this.receivedOnOpenPayload = event;
|
|
2050
|
-
}
|
|
2051
|
-
async onStatus(data) {
|
|
2052
|
-
this.receivedOnStatusPayload = data;
|
|
2053
|
-
}
|
|
2054
|
-
attach(provider) {
|
|
2055
|
-
if (this.receivedOnOpenPayload) {
|
|
2056
|
-
provider.onOpen(this.receivedOnOpenPayload);
|
|
2057
|
-
}
|
|
2058
|
-
if (this.receivedOnStatusPayload) {
|
|
2059
|
-
provider.onStatus(this.receivedOnStatusPayload);
|
|
2060
|
-
}
|
|
2061
|
-
}
|
|
2062
|
-
detach(provider) {
|
|
2063
|
-
// tell the server to remove the listener
|
|
2064
|
-
}
|
|
2065
|
-
setConfiguration(configuration = {}) {
|
|
2066
|
-
this.configuration = { ...this.configuration, ...configuration };
|
|
2067
|
-
}
|
|
2068
|
-
async connect() {
|
|
2069
|
-
if (this.status === exports.WebSocketStatus.Connected) {
|
|
2070
|
-
return;
|
|
2071
|
-
}
|
|
2072
|
-
// Always cancel any previously initiated connection retryer instances
|
|
2073
|
-
if (this.cancelWebsocketRetry) {
|
|
2074
|
-
this.cancelWebsocketRetry();
|
|
2075
|
-
this.cancelWebsocketRetry = undefined;
|
|
2076
|
-
}
|
|
2077
|
-
this.shouldConnect = true;
|
|
2078
|
-
const abortableRetry = () => {
|
|
2079
|
-
let cancelAttempt = false;
|
|
2080
|
-
const retryPromise = attempt.retry(this.createWebSocketConnection.bind(this), {
|
|
2081
|
-
delay: this.configuration.delay,
|
|
2082
|
-
initialDelay: this.configuration.initialDelay,
|
|
2083
|
-
factor: this.configuration.factor,
|
|
2084
|
-
maxAttempts: this.configuration.maxAttempts,
|
|
2085
|
-
minDelay: this.configuration.minDelay,
|
|
2086
|
-
maxDelay: this.configuration.maxDelay,
|
|
2087
|
-
jitter: this.configuration.jitter,
|
|
2088
|
-
timeout: this.configuration.timeout,
|
|
2089
|
-
beforeAttempt: context => {
|
|
2090
|
-
if (!this.shouldConnect || cancelAttempt) {
|
|
2091
|
-
context.abort();
|
|
2092
|
-
}
|
|
2093
|
-
},
|
|
2094
|
-
}).catch((error) => {
|
|
2095
|
-
// If we aborted the connection attempt then don’t throw an error
|
|
2096
|
-
// ref: https://github.com/lifeomic/attempt/blob/master/src/index.ts#L136
|
|
2097
|
-
if (error && error.code !== 'ATTEMPT_ABORTED') {
|
|
2098
|
-
throw error;
|
|
2099
|
-
}
|
|
2100
|
-
});
|
|
2101
|
-
return {
|
|
2102
|
-
retryPromise,
|
|
2103
|
-
cancelFunc: () => {
|
|
2104
|
-
cancelAttempt = true;
|
|
2105
|
-
},
|
|
2106
|
-
};
|
|
2107
|
-
};
|
|
2108
|
-
const { retryPromise, cancelFunc } = abortableRetry();
|
|
2109
|
-
this.cancelWebsocketRetry = cancelFunc;
|
|
2110
|
-
return retryPromise;
|
|
2111
|
-
}
|
|
2112
|
-
createWebSocketConnection() {
|
|
2113
|
-
return new Promise((resolve, reject) => {
|
|
2114
|
-
if (this.webSocket) {
|
|
2115
|
-
this.webSocket.close();
|
|
2116
|
-
this.webSocket = null;
|
|
2117
|
-
}
|
|
2118
|
-
// Init the WebSocket connection
|
|
2119
|
-
const ws = new this.configuration.WebSocketPolyfill(this.url);
|
|
2120
|
-
ws.binaryType = 'arraybuffer';
|
|
2121
|
-
ws.onmessage = (payload) => this.emit('message', payload);
|
|
2122
|
-
ws.onclose = (payload) => this.emit('close', { event: payload });
|
|
2123
|
-
ws.onopen = (payload) => this.emit('open', payload);
|
|
2124
|
-
ws.onerror = (err) => {
|
|
2125
|
-
reject(err);
|
|
2126
|
-
};
|
|
2127
|
-
this.webSocket = ws;
|
|
2128
|
-
// Reset the status
|
|
2129
|
-
this.status = exports.WebSocketStatus.Connecting;
|
|
2130
|
-
this.emit('status', { status: exports.WebSocketStatus.Connecting });
|
|
2131
|
-
// Store resolve/reject for later use
|
|
2132
|
-
this.connectionAttempt = {
|
|
2133
|
-
resolve,
|
|
2134
|
-
reject,
|
|
2135
|
-
};
|
|
2136
|
-
});
|
|
2137
|
-
}
|
|
2138
|
-
onMessage(event) {
|
|
2139
|
-
this.resolveConnectionAttempt();
|
|
2140
|
-
}
|
|
2141
|
-
resolveConnectionAttempt() {
|
|
2142
|
-
if (this.connectionAttempt) {
|
|
2143
|
-
this.connectionAttempt.resolve();
|
|
2144
|
-
this.connectionAttempt = null;
|
|
2145
|
-
this.status = exports.WebSocketStatus.Connected;
|
|
2146
|
-
this.emit('status', { status: exports.WebSocketStatus.Connected });
|
|
2147
|
-
this.emit('connect');
|
|
2148
|
-
}
|
|
2149
|
-
}
|
|
2150
|
-
stopConnectionAttempt() {
|
|
2151
|
-
this.connectionAttempt = null;
|
|
2152
|
-
}
|
|
2153
|
-
rejectConnectionAttempt() {
|
|
2154
|
-
var _a;
|
|
2155
|
-
(_a = this.connectionAttempt) === null || _a === void 0 ? void 0 : _a.reject();
|
|
2156
|
-
this.connectionAttempt = null;
|
|
2157
|
-
}
|
|
2158
|
-
checkConnection() {
|
|
2159
|
-
var _a;
|
|
2160
|
-
// Don’t check the connection when it’s not even established
|
|
2161
|
-
if (this.status !== exports.WebSocketStatus.Connected) {
|
|
2162
|
-
return;
|
|
2163
|
-
}
|
|
2164
|
-
// Don’t close then connection while waiting for the first message
|
|
2165
|
-
if (!this.lastMessageReceived) {
|
|
2166
|
-
return;
|
|
2167
|
-
}
|
|
2168
|
-
// Don’t close the connection when a message was received recently
|
|
2169
|
-
if (this.configuration.messageReconnectTimeout >= getUnixTime() - this.lastMessageReceived) {
|
|
2170
|
-
return;
|
|
2171
|
-
}
|
|
2172
|
-
// No message received in a long time, not even your own
|
|
2173
|
-
// Awareness updates, which are updated every 15 seconds.
|
|
2174
|
-
(_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.close();
|
|
2175
|
-
}
|
|
2176
|
-
registerEventListeners() {
|
|
2177
|
-
if (typeof window === 'undefined') {
|
|
2178
|
-
return;
|
|
2179
|
-
}
|
|
2180
|
-
window.addEventListener('online', this.boundConnect);
|
|
2181
|
-
}
|
|
2182
|
-
// Ensure that the URL always ends with /
|
|
2183
|
-
get serverUrl() {
|
|
2184
|
-
while (this.configuration.url[this.configuration.url.length - 1] === '/') {
|
|
2185
|
-
return this.configuration.url.slice(0, this.configuration.url.length - 1);
|
|
2186
|
-
}
|
|
2187
|
-
return this.configuration.url;
|
|
2188
|
-
}
|
|
2189
|
-
get url() {
|
|
2190
|
-
const encodedParams = encodeQueryParams(this.configuration.parameters);
|
|
2191
|
-
return `${this.serverUrl}${encodedParams.length === 0 ? '' : `?${encodedParams}`}`;
|
|
2192
|
-
}
|
|
2193
|
-
disconnect() {
|
|
2194
|
-
this.shouldConnect = false;
|
|
2195
|
-
if (this.webSocket === null) {
|
|
2196
|
-
return;
|
|
2197
|
-
}
|
|
2198
|
-
try {
|
|
2199
|
-
this.webSocket.close();
|
|
2200
|
-
}
|
|
2201
|
-
catch {
|
|
2202
|
-
//
|
|
2203
|
-
}
|
|
2204
|
-
}
|
|
2205
|
-
send(message) {
|
|
2206
|
-
var _a;
|
|
2207
|
-
if (((_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.readyState) === common.WsReadyStates.Open) {
|
|
2208
|
-
this.webSocket.send(message);
|
|
2209
|
-
}
|
|
2210
|
-
}
|
|
2211
|
-
onClose({ event }) {
|
|
2212
|
-
this.webSocket = null;
|
|
2213
|
-
if (this.status === exports.WebSocketStatus.Connected) {
|
|
2214
|
-
this.status = exports.WebSocketStatus.Disconnected;
|
|
2215
|
-
this.emit('status', { status: exports.WebSocketStatus.Disconnected });
|
|
2216
|
-
this.emit('disconnect', { event });
|
|
2217
|
-
}
|
|
2218
|
-
if (event.code === common.Unauthorized.code) {
|
|
2219
|
-
if (event.reason === common.Unauthorized.reason) {
|
|
2220
|
-
console.warn('[HocuspocusProvider] An authentication token is required, but you didn’t send one. Try adding a `token` to your HocuspocusProvider configuration. Won’t try again.');
|
|
2221
|
-
}
|
|
2222
|
-
else {
|
|
2223
|
-
console.warn(`[HocuspocusProvider] Connection closed with status Unauthorized: ${event.reason}`);
|
|
2224
|
-
}
|
|
2225
|
-
this.shouldConnect = false;
|
|
2226
|
-
}
|
|
2227
|
-
if (event.code === common.Forbidden.code) {
|
|
2228
|
-
if (!this.configuration.quiet) {
|
|
2229
|
-
console.warn('[HocuspocusProvider] The provided authentication token isn’t allowed to connect to this server. Will try again.');
|
|
2230
|
-
return; // TODO REMOVE ME
|
|
2231
|
-
}
|
|
2232
|
-
}
|
|
2233
|
-
if (event.code === common.MessageTooBig.code) {
|
|
2234
|
-
console.warn(`[HocuspocusProvider] Connection closed with status MessageTooBig: ${event.reason}`);
|
|
2235
|
-
this.shouldConnect = false;
|
|
2236
|
-
}
|
|
2237
|
-
if (this.connectionAttempt) {
|
|
2238
|
-
// That connection attempt failed.
|
|
2239
|
-
this.rejectConnectionAttempt();
|
|
2240
|
-
}
|
|
2241
|
-
else if (this.shouldConnect) {
|
|
2242
|
-
// The connection was closed by the server. Let’s just try again.
|
|
2243
|
-
this.connect();
|
|
2244
|
-
}
|
|
2245
|
-
// If we’ll reconnect, we’re done for now.
|
|
2246
|
-
if (this.shouldConnect) {
|
|
2247
|
-
return;
|
|
2248
|
-
}
|
|
2249
|
-
// The status is set correctly already.
|
|
2250
|
-
if (this.status === exports.WebSocketStatus.Disconnected) {
|
|
2251
|
-
return;
|
|
2252
|
-
}
|
|
2253
|
-
// Let’s update the connection status.
|
|
2254
|
-
this.status = exports.WebSocketStatus.Disconnected;
|
|
2255
|
-
this.emit('status', { status: exports.WebSocketStatus.Disconnected });
|
|
2256
|
-
this.emit('disconnect', { event });
|
|
2257
|
-
}
|
|
2258
|
-
destroy() {
|
|
2259
|
-
this.emit('destroy');
|
|
2260
|
-
if (this.intervals.forceSync) {
|
|
2261
|
-
clearInterval(this.intervals.forceSync);
|
|
2262
|
-
}
|
|
2263
|
-
clearInterval(this.intervals.connectionChecker);
|
|
2264
|
-
// If there is still a connection attempt outstanding then we should stop
|
|
2265
|
-
// it before calling disconnect, otherwise it will be rejected in the onClose
|
|
2266
|
-
// handler and trigger a retry
|
|
2267
|
-
this.stopConnectionAttempt();
|
|
2268
|
-
this.disconnect();
|
|
2269
|
-
this.removeAllListeners();
|
|
2270
|
-
if (typeof window === 'undefined') {
|
|
2271
|
-
return;
|
|
2272
|
-
}
|
|
2273
|
-
window.removeEventListener('online', this.boundConnect);
|
|
2274
|
-
}
|
|
1964
|
+
class HocuspocusProviderWebsocket extends EventEmitter {
|
|
1965
|
+
constructor(configuration) {
|
|
1966
|
+
super();
|
|
1967
|
+
this.configuration = {
|
|
1968
|
+
url: '',
|
|
1969
|
+
// @ts-ignore
|
|
1970
|
+
document: undefined,
|
|
1971
|
+
// @ts-ignore
|
|
1972
|
+
awareness: undefined,
|
|
1973
|
+
WebSocketPolyfill: undefined,
|
|
1974
|
+
parameters: {},
|
|
1975
|
+
connect: true,
|
|
1976
|
+
broadcast: true,
|
|
1977
|
+
forceSyncInterval: false,
|
|
1978
|
+
// TODO: this should depend on awareness.outdatedTime
|
|
1979
|
+
messageReconnectTimeout: 30000,
|
|
1980
|
+
// 1 second
|
|
1981
|
+
delay: 1000,
|
|
1982
|
+
// instant
|
|
1983
|
+
initialDelay: 0,
|
|
1984
|
+
// double the delay each time
|
|
1985
|
+
factor: 2,
|
|
1986
|
+
// unlimited retries
|
|
1987
|
+
maxAttempts: 0,
|
|
1988
|
+
// wait at least 1 second
|
|
1989
|
+
minDelay: 1000,
|
|
1990
|
+
// at least every 30 seconds
|
|
1991
|
+
maxDelay: 30000,
|
|
1992
|
+
// randomize
|
|
1993
|
+
jitter: true,
|
|
1994
|
+
// retry forever
|
|
1995
|
+
timeout: 0,
|
|
1996
|
+
onOpen: () => null,
|
|
1997
|
+
onConnect: () => null,
|
|
1998
|
+
onMessage: () => null,
|
|
1999
|
+
onOutgoingMessage: () => null,
|
|
2000
|
+
onStatus: () => null,
|
|
2001
|
+
onDisconnect: () => null,
|
|
2002
|
+
onClose: () => null,
|
|
2003
|
+
onDestroy: () => null,
|
|
2004
|
+
onAwarenessUpdate: () => null,
|
|
2005
|
+
onAwarenessChange: () => null,
|
|
2006
|
+
quiet: false,
|
|
2007
|
+
};
|
|
2008
|
+
this.subscribedToBroadcastChannel = false;
|
|
2009
|
+
this.webSocket = null;
|
|
2010
|
+
this.shouldConnect = true;
|
|
2011
|
+
this.status = exports.WebSocketStatus.Disconnected;
|
|
2012
|
+
this.lastMessageReceived = 0;
|
|
2013
|
+
this.mux = createMutex();
|
|
2014
|
+
this.intervals = {
|
|
2015
|
+
forceSync: null,
|
|
2016
|
+
connectionChecker: null,
|
|
2017
|
+
};
|
|
2018
|
+
this.connectionAttempt = null;
|
|
2019
|
+
this.receivedOnOpenPayload = undefined;
|
|
2020
|
+
this.receivedOnStatusPayload = undefined;
|
|
2021
|
+
this.boundConnect = this.connect.bind(this);
|
|
2022
|
+
this.setConfiguration(configuration);
|
|
2023
|
+
this.configuration.WebSocketPolyfill = configuration.WebSocketPolyfill ? configuration.WebSocketPolyfill : WebSocket;
|
|
2024
|
+
this.on('open', this.configuration.onOpen);
|
|
2025
|
+
this.on('open', this.onOpen.bind(this));
|
|
2026
|
+
this.on('connect', this.configuration.onConnect);
|
|
2027
|
+
this.on('message', this.configuration.onMessage);
|
|
2028
|
+
this.on('outgoingMessage', this.configuration.onOutgoingMessage);
|
|
2029
|
+
this.on('status', this.configuration.onStatus);
|
|
2030
|
+
this.on('status', this.onStatus.bind(this));
|
|
2031
|
+
this.on('disconnect', this.configuration.onDisconnect);
|
|
2032
|
+
this.on('close', this.configuration.onClose);
|
|
2033
|
+
this.on('destroy', this.configuration.onDestroy);
|
|
2034
|
+
this.on('awarenessUpdate', this.configuration.onAwarenessUpdate);
|
|
2035
|
+
this.on('awarenessChange', this.configuration.onAwarenessChange);
|
|
2036
|
+
this.on('close', this.onClose.bind(this));
|
|
2037
|
+
this.on('message', this.onMessage.bind(this));
|
|
2038
|
+
this.registerEventListeners();
|
|
2039
|
+
this.intervals.connectionChecker = setInterval(this.checkConnection.bind(this), this.configuration.messageReconnectTimeout / 10);
|
|
2040
|
+
if (typeof configuration.connect !== 'undefined') {
|
|
2041
|
+
this.shouldConnect = configuration.connect;
|
|
2042
|
+
}
|
|
2043
|
+
if (!this.shouldConnect) {
|
|
2044
|
+
return;
|
|
2045
|
+
}
|
|
2046
|
+
this.connect();
|
|
2047
|
+
}
|
|
2048
|
+
async onOpen(event) {
|
|
2049
|
+
this.receivedOnOpenPayload = event;
|
|
2050
|
+
}
|
|
2051
|
+
async onStatus(data) {
|
|
2052
|
+
this.receivedOnStatusPayload = data;
|
|
2053
|
+
}
|
|
2054
|
+
attach(provider) {
|
|
2055
|
+
if (this.receivedOnOpenPayload) {
|
|
2056
|
+
provider.onOpen(this.receivedOnOpenPayload);
|
|
2057
|
+
}
|
|
2058
|
+
if (this.receivedOnStatusPayload) {
|
|
2059
|
+
provider.onStatus(this.receivedOnStatusPayload);
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
detach(provider) {
|
|
2063
|
+
// tell the server to remove the listener
|
|
2064
|
+
}
|
|
2065
|
+
setConfiguration(configuration = {}) {
|
|
2066
|
+
this.configuration = { ...this.configuration, ...configuration };
|
|
2067
|
+
}
|
|
2068
|
+
async connect() {
|
|
2069
|
+
if (this.status === exports.WebSocketStatus.Connected) {
|
|
2070
|
+
return;
|
|
2071
|
+
}
|
|
2072
|
+
// Always cancel any previously initiated connection retryer instances
|
|
2073
|
+
if (this.cancelWebsocketRetry) {
|
|
2074
|
+
this.cancelWebsocketRetry();
|
|
2075
|
+
this.cancelWebsocketRetry = undefined;
|
|
2076
|
+
}
|
|
2077
|
+
this.shouldConnect = true;
|
|
2078
|
+
const abortableRetry = () => {
|
|
2079
|
+
let cancelAttempt = false;
|
|
2080
|
+
const retryPromise = attempt.retry(this.createWebSocketConnection.bind(this), {
|
|
2081
|
+
delay: this.configuration.delay,
|
|
2082
|
+
initialDelay: this.configuration.initialDelay,
|
|
2083
|
+
factor: this.configuration.factor,
|
|
2084
|
+
maxAttempts: this.configuration.maxAttempts,
|
|
2085
|
+
minDelay: this.configuration.minDelay,
|
|
2086
|
+
maxDelay: this.configuration.maxDelay,
|
|
2087
|
+
jitter: this.configuration.jitter,
|
|
2088
|
+
timeout: this.configuration.timeout,
|
|
2089
|
+
beforeAttempt: context => {
|
|
2090
|
+
if (!this.shouldConnect || cancelAttempt) {
|
|
2091
|
+
context.abort();
|
|
2092
|
+
}
|
|
2093
|
+
},
|
|
2094
|
+
}).catch((error) => {
|
|
2095
|
+
// If we aborted the connection attempt then don’t throw an error
|
|
2096
|
+
// ref: https://github.com/lifeomic/attempt/blob/master/src/index.ts#L136
|
|
2097
|
+
if (error && error.code !== 'ATTEMPT_ABORTED') {
|
|
2098
|
+
throw error;
|
|
2099
|
+
}
|
|
2100
|
+
});
|
|
2101
|
+
return {
|
|
2102
|
+
retryPromise,
|
|
2103
|
+
cancelFunc: () => {
|
|
2104
|
+
cancelAttempt = true;
|
|
2105
|
+
},
|
|
2106
|
+
};
|
|
2107
|
+
};
|
|
2108
|
+
const { retryPromise, cancelFunc } = abortableRetry();
|
|
2109
|
+
this.cancelWebsocketRetry = cancelFunc;
|
|
2110
|
+
return retryPromise;
|
|
2111
|
+
}
|
|
2112
|
+
createWebSocketConnection() {
|
|
2113
|
+
return new Promise((resolve, reject) => {
|
|
2114
|
+
if (this.webSocket) {
|
|
2115
|
+
this.webSocket.close();
|
|
2116
|
+
this.webSocket = null;
|
|
2117
|
+
}
|
|
2118
|
+
// Init the WebSocket connection
|
|
2119
|
+
const ws = new this.configuration.WebSocketPolyfill(this.url);
|
|
2120
|
+
ws.binaryType = 'arraybuffer';
|
|
2121
|
+
ws.onmessage = (payload) => this.emit('message', payload);
|
|
2122
|
+
ws.onclose = (payload) => this.emit('close', { event: payload });
|
|
2123
|
+
ws.onopen = (payload) => this.emit('open', payload);
|
|
2124
|
+
ws.onerror = (err) => {
|
|
2125
|
+
reject(err);
|
|
2126
|
+
};
|
|
2127
|
+
this.webSocket = ws;
|
|
2128
|
+
// Reset the status
|
|
2129
|
+
this.status = exports.WebSocketStatus.Connecting;
|
|
2130
|
+
this.emit('status', { status: exports.WebSocketStatus.Connecting });
|
|
2131
|
+
// Store resolve/reject for later use
|
|
2132
|
+
this.connectionAttempt = {
|
|
2133
|
+
resolve,
|
|
2134
|
+
reject,
|
|
2135
|
+
};
|
|
2136
|
+
});
|
|
2137
|
+
}
|
|
2138
|
+
onMessage(event) {
|
|
2139
|
+
this.resolveConnectionAttempt();
|
|
2140
|
+
}
|
|
2141
|
+
resolveConnectionAttempt() {
|
|
2142
|
+
if (this.connectionAttempt) {
|
|
2143
|
+
this.connectionAttempt.resolve();
|
|
2144
|
+
this.connectionAttempt = null;
|
|
2145
|
+
this.status = exports.WebSocketStatus.Connected;
|
|
2146
|
+
this.emit('status', { status: exports.WebSocketStatus.Connected });
|
|
2147
|
+
this.emit('connect');
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
stopConnectionAttempt() {
|
|
2151
|
+
this.connectionAttempt = null;
|
|
2152
|
+
}
|
|
2153
|
+
rejectConnectionAttempt() {
|
|
2154
|
+
var _a;
|
|
2155
|
+
(_a = this.connectionAttempt) === null || _a === void 0 ? void 0 : _a.reject();
|
|
2156
|
+
this.connectionAttempt = null;
|
|
2157
|
+
}
|
|
2158
|
+
checkConnection() {
|
|
2159
|
+
var _a;
|
|
2160
|
+
// Don’t check the connection when it’s not even established
|
|
2161
|
+
if (this.status !== exports.WebSocketStatus.Connected) {
|
|
2162
|
+
return;
|
|
2163
|
+
}
|
|
2164
|
+
// Don’t close then connection while waiting for the first message
|
|
2165
|
+
if (!this.lastMessageReceived) {
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
2168
|
+
// Don’t close the connection when a message was received recently
|
|
2169
|
+
if (this.configuration.messageReconnectTimeout >= getUnixTime() - this.lastMessageReceived) {
|
|
2170
|
+
return;
|
|
2171
|
+
}
|
|
2172
|
+
// No message received in a long time, not even your own
|
|
2173
|
+
// Awareness updates, which are updated every 15 seconds.
|
|
2174
|
+
(_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.close();
|
|
2175
|
+
}
|
|
2176
|
+
registerEventListeners() {
|
|
2177
|
+
if (typeof window === 'undefined') {
|
|
2178
|
+
return;
|
|
2179
|
+
}
|
|
2180
|
+
window.addEventListener('online', this.boundConnect);
|
|
2181
|
+
}
|
|
2182
|
+
// Ensure that the URL always ends with /
|
|
2183
|
+
get serverUrl() {
|
|
2184
|
+
while (this.configuration.url[this.configuration.url.length - 1] === '/') {
|
|
2185
|
+
return this.configuration.url.slice(0, this.configuration.url.length - 1);
|
|
2186
|
+
}
|
|
2187
|
+
return this.configuration.url;
|
|
2188
|
+
}
|
|
2189
|
+
get url() {
|
|
2190
|
+
const encodedParams = encodeQueryParams(this.configuration.parameters);
|
|
2191
|
+
return `${this.serverUrl}${encodedParams.length === 0 ? '' : `?${encodedParams}`}`;
|
|
2192
|
+
}
|
|
2193
|
+
disconnect() {
|
|
2194
|
+
this.shouldConnect = false;
|
|
2195
|
+
if (this.webSocket === null) {
|
|
2196
|
+
return;
|
|
2197
|
+
}
|
|
2198
|
+
try {
|
|
2199
|
+
this.webSocket.close();
|
|
2200
|
+
}
|
|
2201
|
+
catch {
|
|
2202
|
+
//
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
send(message) {
|
|
2206
|
+
var _a;
|
|
2207
|
+
if (((_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.readyState) === common.WsReadyStates.Open) {
|
|
2208
|
+
this.webSocket.send(message);
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
onClose({ event }) {
|
|
2212
|
+
this.webSocket = null;
|
|
2213
|
+
if (this.status === exports.WebSocketStatus.Connected) {
|
|
2214
|
+
this.status = exports.WebSocketStatus.Disconnected;
|
|
2215
|
+
this.emit('status', { status: exports.WebSocketStatus.Disconnected });
|
|
2216
|
+
this.emit('disconnect', { event });
|
|
2217
|
+
}
|
|
2218
|
+
if (event.code === common.Unauthorized.code) {
|
|
2219
|
+
if (event.reason === common.Unauthorized.reason) {
|
|
2220
|
+
console.warn('[HocuspocusProvider] An authentication token is required, but you didn’t send one. Try adding a `token` to your HocuspocusProvider configuration. Won’t try again.');
|
|
2221
|
+
}
|
|
2222
|
+
else {
|
|
2223
|
+
console.warn(`[HocuspocusProvider] Connection closed with status Unauthorized: ${event.reason}`);
|
|
2224
|
+
}
|
|
2225
|
+
this.shouldConnect = false;
|
|
2226
|
+
}
|
|
2227
|
+
if (event.code === common.Forbidden.code) {
|
|
2228
|
+
if (!this.configuration.quiet) {
|
|
2229
|
+
console.warn('[HocuspocusProvider] The provided authentication token isn’t allowed to connect to this server. Will try again.');
|
|
2230
|
+
return; // TODO REMOVE ME
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
if (event.code === common.MessageTooBig.code) {
|
|
2234
|
+
console.warn(`[HocuspocusProvider] Connection closed with status MessageTooBig: ${event.reason}`);
|
|
2235
|
+
this.shouldConnect = false;
|
|
2236
|
+
}
|
|
2237
|
+
if (this.connectionAttempt) {
|
|
2238
|
+
// That connection attempt failed.
|
|
2239
|
+
this.rejectConnectionAttempt();
|
|
2240
|
+
}
|
|
2241
|
+
else if (this.shouldConnect) {
|
|
2242
|
+
// The connection was closed by the server. Let’s just try again.
|
|
2243
|
+
this.connect();
|
|
2244
|
+
}
|
|
2245
|
+
// If we’ll reconnect, we’re done for now.
|
|
2246
|
+
if (this.shouldConnect) {
|
|
2247
|
+
return;
|
|
2248
|
+
}
|
|
2249
|
+
// The status is set correctly already.
|
|
2250
|
+
if (this.status === exports.WebSocketStatus.Disconnected) {
|
|
2251
|
+
return;
|
|
2252
|
+
}
|
|
2253
|
+
// Let’s update the connection status.
|
|
2254
|
+
this.status = exports.WebSocketStatus.Disconnected;
|
|
2255
|
+
this.emit('status', { status: exports.WebSocketStatus.Disconnected });
|
|
2256
|
+
this.emit('disconnect', { event });
|
|
2257
|
+
}
|
|
2258
|
+
destroy() {
|
|
2259
|
+
this.emit('destroy');
|
|
2260
|
+
if (this.intervals.forceSync) {
|
|
2261
|
+
clearInterval(this.intervals.forceSync);
|
|
2262
|
+
}
|
|
2263
|
+
clearInterval(this.intervals.connectionChecker);
|
|
2264
|
+
// If there is still a connection attempt outstanding then we should stop
|
|
2265
|
+
// it before calling disconnect, otherwise it will be rejected in the onClose
|
|
2266
|
+
// handler and trigger a retry
|
|
2267
|
+
this.stopConnectionAttempt();
|
|
2268
|
+
this.disconnect();
|
|
2269
|
+
this.removeAllListeners();
|
|
2270
|
+
if (typeof window === 'undefined') {
|
|
2271
|
+
return;
|
|
2272
|
+
}
|
|
2273
|
+
window.removeEventListener('online', this.boundConnect);
|
|
2274
|
+
}
|
|
2275
2275
|
}
|
|
2276
2276
|
|
|
2277
|
-
class StatelessMessage extends OutgoingMessage {
|
|
2278
|
-
constructor() {
|
|
2279
|
-
super(...arguments);
|
|
2280
|
-
this.type = exports.MessageType.Stateless;
|
|
2281
|
-
this.description = 'A stateless message';
|
|
2282
|
-
}
|
|
2283
|
-
get(args) {
|
|
2284
|
-
var _a;
|
|
2285
|
-
writeVarString(this.encoder, args.documentName);
|
|
2286
|
-
writeVarUint(this.encoder, this.type);
|
|
2287
|
-
writeVarString(this.encoder, (_a = args.payload) !== null && _a !== void 0 ? _a : '');
|
|
2288
|
-
return this.encoder;
|
|
2289
|
-
}
|
|
2277
|
+
class StatelessMessage extends OutgoingMessage {
|
|
2278
|
+
constructor() {
|
|
2279
|
+
super(...arguments);
|
|
2280
|
+
this.type = exports.MessageType.Stateless;
|
|
2281
|
+
this.description = 'A stateless message';
|
|
2282
|
+
}
|
|
2283
|
+
get(args) {
|
|
2284
|
+
var _a;
|
|
2285
|
+
writeVarString(this.encoder, args.documentName);
|
|
2286
|
+
writeVarUint(this.encoder, this.type);
|
|
2287
|
+
writeVarString(this.encoder, (_a = args.payload) !== null && _a !== void 0 ? _a : '');
|
|
2288
|
+
return this.encoder;
|
|
2289
|
+
}
|
|
2290
2290
|
}
|
|
2291
2291
|
|
|
2292
|
-
class CloseMessage extends OutgoingMessage {
|
|
2293
|
-
constructor() {
|
|
2294
|
-
super(...arguments);
|
|
2295
|
-
this.type = exports.MessageType.CLOSE;
|
|
2296
|
-
this.description = 'Ask the server to close the connection';
|
|
2297
|
-
}
|
|
2298
|
-
get(args) {
|
|
2299
|
-
writeVarString(this.encoder, args.documentName);
|
|
2300
|
-
writeVarUint(this.encoder, this.type);
|
|
2301
|
-
return this.encoder;
|
|
2302
|
-
}
|
|
2292
|
+
class CloseMessage extends OutgoingMessage {
|
|
2293
|
+
constructor() {
|
|
2294
|
+
super(...arguments);
|
|
2295
|
+
this.type = exports.MessageType.CLOSE;
|
|
2296
|
+
this.description = 'Ask the server to close the connection';
|
|
2297
|
+
}
|
|
2298
|
+
get(args) {
|
|
2299
|
+
writeVarString(this.encoder, args.documentName);
|
|
2300
|
+
writeVarUint(this.encoder, this.type);
|
|
2301
|
+
return this.encoder;
|
|
2302
|
+
}
|
|
2303
2303
|
}
|
|
2304
2304
|
|
|
2305
|
-
class HocuspocusProvider extends EventEmitter {
|
|
2306
|
-
constructor(configuration) {
|
|
2307
|
-
super();
|
|
2308
|
-
this.configuration = {
|
|
2309
|
-
name: '',
|
|
2310
|
-
// @ts-ignore
|
|
2311
|
-
document: undefined,
|
|
2312
|
-
// @ts-ignore
|
|
2313
|
-
awareness: undefined,
|
|
2314
|
-
token: null,
|
|
2315
|
-
parameters: {},
|
|
2316
|
-
broadcast: true,
|
|
2317
|
-
forceSyncInterval: false,
|
|
2318
|
-
onAuthenticated: () => null,
|
|
2319
|
-
onAuthenticationFailed: () => null,
|
|
2320
|
-
onOpen: () => null,
|
|
2321
|
-
onConnect: () => null,
|
|
2322
|
-
onMessage: () => null,
|
|
2323
|
-
onOutgoingMessage: () => null,
|
|
2324
|
-
onStatus: () => null,
|
|
2325
|
-
onSynced: () => null,
|
|
2326
|
-
onDisconnect: () => null,
|
|
2327
|
-
onClose: () => null,
|
|
2328
|
-
onDestroy: () => null,
|
|
2329
|
-
onAwarenessUpdate: () => null,
|
|
2330
|
-
onAwarenessChange: () => null,
|
|
2331
|
-
onStateless: () => null,
|
|
2332
|
-
quiet: false,
|
|
2333
|
-
};
|
|
2334
|
-
this.subscribedToBroadcastChannel = false;
|
|
2335
|
-
this.isSynced = false;
|
|
2336
|
-
this.unsyncedChanges = 0;
|
|
2337
|
-
this.status = exports.WebSocketStatus.Disconnected;
|
|
2338
|
-
this.isAuthenticated = false;
|
|
2339
|
-
this.
|
|
2340
|
-
this.
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
this.
|
|
2345
|
-
this.
|
|
2346
|
-
this.
|
|
2347
|
-
this.configuration
|
|
2348
|
-
this.configuration.
|
|
2349
|
-
this.
|
|
2350
|
-
this.on('
|
|
2351
|
-
this.on('
|
|
2352
|
-
this.on('
|
|
2353
|
-
this.on('
|
|
2354
|
-
this.on('
|
|
2355
|
-
this.on('
|
|
2356
|
-
this.on('
|
|
2357
|
-
this.on('
|
|
2358
|
-
this.on('
|
|
2359
|
-
this.
|
|
2360
|
-
this.configuration.websocketProvider.on('connect',
|
|
2361
|
-
this.configuration.websocketProvider.on('
|
|
2362
|
-
this.configuration.websocketProvider.on('open',
|
|
2363
|
-
this.configuration.websocketProvider.on('
|
|
2364
|
-
this.configuration.websocketProvider.on('
|
|
2365
|
-
this.configuration.websocketProvider.on('close', this.
|
|
2366
|
-
this.configuration.websocketProvider.on('close',
|
|
2367
|
-
this.configuration.websocketProvider.on('
|
|
2368
|
-
this.configuration.websocketProvider.on('
|
|
2369
|
-
this.configuration.websocketProvider.on('disconnect',
|
|
2370
|
-
this.configuration.websocketProvider.on('
|
|
2371
|
-
this.configuration.websocketProvider.on('destroy',
|
|
2372
|
-
this.
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
this.
|
|
2380
|
-
this.
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
this.
|
|
2389
|
-
this.
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
this.
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
this.
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
this.
|
|
2456
|
-
this.emit('
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
this.
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
this.
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
const
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
new
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
this.
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
this.
|
|
2533
|
-
this.
|
|
2534
|
-
this.
|
|
2535
|
-
this.
|
|
2536
|
-
this.
|
|
2537
|
-
this.
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
this.
|
|
2546
|
-
this.
|
|
2547
|
-
this.
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
this.
|
|
2552
|
-
this.
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
message
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
this.broadcast(
|
|
2576
|
-
this.broadcast(
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2305
|
+
class HocuspocusProvider extends EventEmitter {
|
|
2306
|
+
constructor(configuration) {
|
|
2307
|
+
super();
|
|
2308
|
+
this.configuration = {
|
|
2309
|
+
name: '',
|
|
2310
|
+
// @ts-ignore
|
|
2311
|
+
document: undefined,
|
|
2312
|
+
// @ts-ignore
|
|
2313
|
+
awareness: undefined,
|
|
2314
|
+
token: null,
|
|
2315
|
+
parameters: {},
|
|
2316
|
+
broadcast: true,
|
|
2317
|
+
forceSyncInterval: false,
|
|
2318
|
+
onAuthenticated: () => null,
|
|
2319
|
+
onAuthenticationFailed: () => null,
|
|
2320
|
+
onOpen: () => null,
|
|
2321
|
+
onConnect: () => null,
|
|
2322
|
+
onMessage: () => null,
|
|
2323
|
+
onOutgoingMessage: () => null,
|
|
2324
|
+
onStatus: () => null,
|
|
2325
|
+
onSynced: () => null,
|
|
2326
|
+
onDisconnect: () => null,
|
|
2327
|
+
onClose: () => null,
|
|
2328
|
+
onDestroy: () => null,
|
|
2329
|
+
onAwarenessUpdate: () => null,
|
|
2330
|
+
onAwarenessChange: () => null,
|
|
2331
|
+
onStateless: () => null,
|
|
2332
|
+
quiet: false,
|
|
2333
|
+
};
|
|
2334
|
+
this.subscribedToBroadcastChannel = false;
|
|
2335
|
+
this.isSynced = false;
|
|
2336
|
+
this.unsyncedChanges = 0;
|
|
2337
|
+
this.status = exports.WebSocketStatus.Disconnected;
|
|
2338
|
+
this.isAuthenticated = false;
|
|
2339
|
+
this.authorizedScope = undefined;
|
|
2340
|
+
this.mux = createMutex();
|
|
2341
|
+
this.intervals = {
|
|
2342
|
+
forceSync: null,
|
|
2343
|
+
};
|
|
2344
|
+
this.isConnected = true;
|
|
2345
|
+
this.boundBeforeUnload = this.beforeUnload.bind(this);
|
|
2346
|
+
this.boundBroadcastChannelSubscriber = this.broadcastChannelSubscriber.bind(this);
|
|
2347
|
+
this.setConfiguration(configuration);
|
|
2348
|
+
this.configuration.document = configuration.document ? configuration.document : new Y__namespace.Doc();
|
|
2349
|
+
this.configuration.awareness = configuration.awareness ? configuration.awareness : new Awareness(this.document);
|
|
2350
|
+
this.on('open', this.configuration.onOpen);
|
|
2351
|
+
this.on('message', this.configuration.onMessage);
|
|
2352
|
+
this.on('outgoingMessage', this.configuration.onOutgoingMessage);
|
|
2353
|
+
this.on('synced', this.configuration.onSynced);
|
|
2354
|
+
this.on('destroy', this.configuration.onDestroy);
|
|
2355
|
+
this.on('awarenessUpdate', this.configuration.onAwarenessUpdate);
|
|
2356
|
+
this.on('awarenessChange', this.configuration.onAwarenessChange);
|
|
2357
|
+
this.on('stateless', this.configuration.onStateless);
|
|
2358
|
+
this.on('authenticated', this.configuration.onAuthenticated);
|
|
2359
|
+
this.on('authenticationFailed', this.configuration.onAuthenticationFailed);
|
|
2360
|
+
this.configuration.websocketProvider.on('connect', this.configuration.onConnect);
|
|
2361
|
+
this.configuration.websocketProvider.on('connect', (e) => this.emit('connect', e));
|
|
2362
|
+
this.configuration.websocketProvider.on('open', this.onOpen.bind(this));
|
|
2363
|
+
this.configuration.websocketProvider.on('open', (e) => this.emit('open', e));
|
|
2364
|
+
this.configuration.websocketProvider.on('message', this.onMessage.bind(this));
|
|
2365
|
+
this.configuration.websocketProvider.on('close', this.onClose.bind(this));
|
|
2366
|
+
this.configuration.websocketProvider.on('close', this.configuration.onClose);
|
|
2367
|
+
this.configuration.websocketProvider.on('close', (e) => this.emit('close', e));
|
|
2368
|
+
this.configuration.websocketProvider.on('status', this.onStatus.bind(this));
|
|
2369
|
+
this.configuration.websocketProvider.on('disconnect', this.configuration.onDisconnect);
|
|
2370
|
+
this.configuration.websocketProvider.on('disconnect', (e) => this.emit('disconnect', e));
|
|
2371
|
+
this.configuration.websocketProvider.on('destroy', this.configuration.onDestroy);
|
|
2372
|
+
this.configuration.websocketProvider.on('destroy', (e) => this.emit('destroy', e));
|
|
2373
|
+
this.awareness.on('update', () => {
|
|
2374
|
+
this.emit('awarenessUpdate', { states: common.awarenessStatesToArray(this.awareness.getStates()) });
|
|
2375
|
+
});
|
|
2376
|
+
this.awareness.on('change', () => {
|
|
2377
|
+
this.emit('awarenessChange', { states: common.awarenessStatesToArray(this.awareness.getStates()) });
|
|
2378
|
+
});
|
|
2379
|
+
this.document.on('update', this.documentUpdateHandler.bind(this));
|
|
2380
|
+
this.awareness.on('update', this.awarenessUpdateHandler.bind(this));
|
|
2381
|
+
this.registerEventListeners();
|
|
2382
|
+
if (this.configuration.forceSyncInterval) {
|
|
2383
|
+
this.intervals.forceSync = setInterval(this.forceSync.bind(this), this.configuration.forceSyncInterval);
|
|
2384
|
+
}
|
|
2385
|
+
this.configuration.websocketProvider.attach(this);
|
|
2386
|
+
}
|
|
2387
|
+
onStatus({ status }) {
|
|
2388
|
+
this.status = status;
|
|
2389
|
+
this.configuration.onStatus({ status });
|
|
2390
|
+
this.emit('status', { status });
|
|
2391
|
+
}
|
|
2392
|
+
setConfiguration(configuration = {}) {
|
|
2393
|
+
if (!configuration.websocketProvider && configuration.url) {
|
|
2394
|
+
const websocketProviderConfig = configuration;
|
|
2395
|
+
this.configuration.websocketProvider = new HocuspocusProviderWebsocket({
|
|
2396
|
+
url: websocketProviderConfig.url,
|
|
2397
|
+
parameters: websocketProviderConfig.parameters,
|
|
2398
|
+
});
|
|
2399
|
+
}
|
|
2400
|
+
this.configuration = { ...this.configuration, ...configuration };
|
|
2401
|
+
}
|
|
2402
|
+
get document() {
|
|
2403
|
+
return this.configuration.document;
|
|
2404
|
+
}
|
|
2405
|
+
get awareness() {
|
|
2406
|
+
return this.configuration.awareness;
|
|
2407
|
+
}
|
|
2408
|
+
get hasUnsyncedChanges() {
|
|
2409
|
+
return this.unsyncedChanges > 0;
|
|
2410
|
+
}
|
|
2411
|
+
updateUnsyncedChanges(unsyncedChanges = 0) {
|
|
2412
|
+
this.unsyncedChanges += unsyncedChanges;
|
|
2413
|
+
this.emit('unsyncedChanges', this.unsyncedChanges);
|
|
2414
|
+
}
|
|
2415
|
+
forceSync() {
|
|
2416
|
+
this.send(SyncStepOneMessage, { document: this.document, documentName: this.configuration.name });
|
|
2417
|
+
}
|
|
2418
|
+
beforeUnload() {
|
|
2419
|
+
removeAwarenessStates(this.awareness, [this.document.clientID], 'window unload');
|
|
2420
|
+
}
|
|
2421
|
+
registerEventListeners() {
|
|
2422
|
+
if (typeof window === 'undefined') {
|
|
2423
|
+
return;
|
|
2424
|
+
}
|
|
2425
|
+
window.addEventListener('beforeunload', this.boundBeforeUnload);
|
|
2426
|
+
}
|
|
2427
|
+
sendStateless(payload) {
|
|
2428
|
+
this.send(StatelessMessage, { documentName: this.configuration.name, payload });
|
|
2429
|
+
}
|
|
2430
|
+
documentUpdateHandler(update, origin) {
|
|
2431
|
+
if (origin === this) {
|
|
2432
|
+
return;
|
|
2433
|
+
}
|
|
2434
|
+
this.updateUnsyncedChanges(1);
|
|
2435
|
+
this.send(UpdateMessage, { update, documentName: this.configuration.name }, true);
|
|
2436
|
+
}
|
|
2437
|
+
awarenessUpdateHandler({ added, updated, removed }, origin) {
|
|
2438
|
+
const changedClients = added.concat(updated).concat(removed);
|
|
2439
|
+
this.send(AwarenessMessage, {
|
|
2440
|
+
awareness: this.awareness,
|
|
2441
|
+
clients: changedClients,
|
|
2442
|
+
documentName: this.configuration.name,
|
|
2443
|
+
}, true);
|
|
2444
|
+
}
|
|
2445
|
+
get synced() {
|
|
2446
|
+
return this.isSynced;
|
|
2447
|
+
}
|
|
2448
|
+
set synced(state) {
|
|
2449
|
+
if (this.isSynced === state) {
|
|
2450
|
+
return;
|
|
2451
|
+
}
|
|
2452
|
+
if (state && this.unsyncedChanges > 0) {
|
|
2453
|
+
this.updateUnsyncedChanges(-1 * this.unsyncedChanges);
|
|
2454
|
+
}
|
|
2455
|
+
this.isSynced = state;
|
|
2456
|
+
this.emit('synced', { state });
|
|
2457
|
+
this.emit('sync', { state });
|
|
2458
|
+
}
|
|
2459
|
+
receiveStateless(payload) {
|
|
2460
|
+
this.emit('stateless', { payload });
|
|
2461
|
+
}
|
|
2462
|
+
get isAuthenticationRequired() {
|
|
2463
|
+
return !!this.configuration.token && !this.isAuthenticated;
|
|
2464
|
+
}
|
|
2465
|
+
// not needed, but provides backward compatibility with e.g. lexicla/yjs
|
|
2466
|
+
async connect() {
|
|
2467
|
+
return this.configuration.websocketProvider.connect();
|
|
2468
|
+
}
|
|
2469
|
+
disconnect() {
|
|
2470
|
+
this.disconnectBroadcastChannel();
|
|
2471
|
+
this.configuration.websocketProvider.detach(this);
|
|
2472
|
+
}
|
|
2473
|
+
async onOpen(event) {
|
|
2474
|
+
this.isAuthenticated = false;
|
|
2475
|
+
this.emit('open', { event });
|
|
2476
|
+
if (this.isAuthenticationRequired) {
|
|
2477
|
+
this.send(AuthenticationMessage, {
|
|
2478
|
+
token: await this.getToken(),
|
|
2479
|
+
documentName: this.configuration.name,
|
|
2480
|
+
});
|
|
2481
|
+
}
|
|
2482
|
+
this.startSync();
|
|
2483
|
+
}
|
|
2484
|
+
async getToken() {
|
|
2485
|
+
if (typeof this.configuration.token === 'function') {
|
|
2486
|
+
const token = await this.configuration.token();
|
|
2487
|
+
return token;
|
|
2488
|
+
}
|
|
2489
|
+
return this.configuration.token;
|
|
2490
|
+
}
|
|
2491
|
+
startSync() {
|
|
2492
|
+
this.send(SyncStepOneMessage, { document: this.document, documentName: this.configuration.name });
|
|
2493
|
+
if (this.awareness.getLocalState() !== null) {
|
|
2494
|
+
this.send(AwarenessMessage, {
|
|
2495
|
+
awareness: this.awareness,
|
|
2496
|
+
clients: [this.document.clientID],
|
|
2497
|
+
documentName: this.configuration.name,
|
|
2498
|
+
});
|
|
2499
|
+
}
|
|
2500
|
+
}
|
|
2501
|
+
send(message, args, broadcast = false) {
|
|
2502
|
+
if (!this.isConnected)
|
|
2503
|
+
return;
|
|
2504
|
+
if (broadcast) {
|
|
2505
|
+
this.mux(() => { this.broadcast(message, args); });
|
|
2506
|
+
}
|
|
2507
|
+
const messageSender = new MessageSender(message, args);
|
|
2508
|
+
this.emit('outgoingMessage', { message: messageSender.message });
|
|
2509
|
+
messageSender.send(this.configuration.websocketProvider);
|
|
2510
|
+
}
|
|
2511
|
+
onMessage(event) {
|
|
2512
|
+
const message = new IncomingMessage(event.data);
|
|
2513
|
+
const documentName = message.readVarString();
|
|
2514
|
+
if (documentName !== this.configuration.name) {
|
|
2515
|
+
return; // message is meant for another provider
|
|
2516
|
+
}
|
|
2517
|
+
message.writeVarString(documentName);
|
|
2518
|
+
this.emit('message', { event, message: new IncomingMessage(event.data) });
|
|
2519
|
+
new MessageReceiver(message).apply(this);
|
|
2520
|
+
}
|
|
2521
|
+
onClose(event) {
|
|
2522
|
+
this.isAuthenticated = false;
|
|
2523
|
+
this.synced = false;
|
|
2524
|
+
// update awareness (all users except local left)
|
|
2525
|
+
removeAwarenessStates(this.awareness, Array.from(this.awareness.getStates().keys()).filter(client => client !== this.document.clientID), this);
|
|
2526
|
+
}
|
|
2527
|
+
destroy() {
|
|
2528
|
+
this.emit('destroy');
|
|
2529
|
+
if (this.intervals.forceSync) {
|
|
2530
|
+
clearInterval(this.intervals.forceSync);
|
|
2531
|
+
}
|
|
2532
|
+
removeAwarenessStates(this.awareness, [this.document.clientID], 'provider destroy');
|
|
2533
|
+
this.disconnect();
|
|
2534
|
+
this.awareness.off('update', this.awarenessUpdateHandler);
|
|
2535
|
+
this.document.off('update', this.documentUpdateHandler);
|
|
2536
|
+
this.removeAllListeners();
|
|
2537
|
+
this.send(CloseMessage, { documentName: this.configuration.name });
|
|
2538
|
+
this.isConnected = false;
|
|
2539
|
+
if (typeof window === 'undefined') {
|
|
2540
|
+
return;
|
|
2541
|
+
}
|
|
2542
|
+
window.removeEventListener('beforeunload', this.boundBeforeUnload);
|
|
2543
|
+
}
|
|
2544
|
+
permissionDeniedHandler(reason) {
|
|
2545
|
+
this.emit('authenticationFailed', { reason });
|
|
2546
|
+
this.isAuthenticated = false;
|
|
2547
|
+
this.disconnect();
|
|
2548
|
+
this.status = exports.WebSocketStatus.Disconnected;
|
|
2549
|
+
}
|
|
2550
|
+
authenticatedHandler(scope) {
|
|
2551
|
+
this.isAuthenticated = true;
|
|
2552
|
+
this.authorizedScope = scope;
|
|
2553
|
+
this.emit('authenticated');
|
|
2554
|
+
this.startSync();
|
|
2555
|
+
}
|
|
2556
|
+
get broadcastChannel() {
|
|
2557
|
+
return `${this.configuration.name}`;
|
|
2558
|
+
}
|
|
2559
|
+
broadcastChannelSubscriber(data) {
|
|
2560
|
+
this.mux(() => {
|
|
2561
|
+
const message = new IncomingMessage(data);
|
|
2562
|
+
const documentName = message.readVarString();
|
|
2563
|
+
message.writeVarString(documentName);
|
|
2564
|
+
new MessageReceiver(message)
|
|
2565
|
+
.setBroadcasted(true)
|
|
2566
|
+
.apply(this, false);
|
|
2567
|
+
});
|
|
2568
|
+
}
|
|
2569
|
+
subscribeToBroadcastChannel() {
|
|
2570
|
+
if (!this.subscribedToBroadcastChannel) {
|
|
2571
|
+
subscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber);
|
|
2572
|
+
this.subscribedToBroadcastChannel = true;
|
|
2573
|
+
}
|
|
2574
|
+
this.mux(() => {
|
|
2575
|
+
this.broadcast(SyncStepOneMessage, { document: this.document });
|
|
2576
|
+
this.broadcast(SyncStepTwoMessage, { document: this.document });
|
|
2577
|
+
this.broadcast(QueryAwarenessMessage, { document: this.document });
|
|
2578
|
+
this.broadcast(AwarenessMessage, { awareness: this.awareness, clients: [this.document.clientID], document: this.document });
|
|
2579
|
+
});
|
|
2580
|
+
}
|
|
2581
|
+
disconnectBroadcastChannel() {
|
|
2582
|
+
// broadcast message with local awareness state set to null (indicating disconnect)
|
|
2583
|
+
this.send(AwarenessMessage, {
|
|
2584
|
+
awareness: this.awareness,
|
|
2585
|
+
clients: [this.document.clientID],
|
|
2586
|
+
states: new Map(),
|
|
2587
|
+
documentName: this.configuration.name,
|
|
2588
|
+
}, true);
|
|
2589
|
+
if (this.subscribedToBroadcastChannel) {
|
|
2590
|
+
unsubscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber);
|
|
2591
|
+
this.subscribedToBroadcastChannel = false;
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
broadcast(Message, args) {
|
|
2595
|
+
if (!this.configuration.broadcast) {
|
|
2596
|
+
return;
|
|
2597
|
+
}
|
|
2598
|
+
if (!this.subscribedToBroadcastChannel) {
|
|
2599
|
+
return;
|
|
2600
|
+
}
|
|
2601
|
+
new MessageSender(Message, args).broadcast(this.broadcastChannel);
|
|
2602
|
+
}
|
|
2603
|
+
setAwarenessField(key, value) {
|
|
2604
|
+
this.awareness.setLocalStateField(key, value);
|
|
2605
|
+
}
|
|
2604
2606
|
}
|
|
2605
2607
|
|
|
2606
|
-
class TiptapCollabProviderWebsocket extends HocuspocusProviderWebsocket {
|
|
2607
|
-
constructor(configuration) {
|
|
2608
|
-
super({ ...configuration, url: `wss://${configuration.appId}.collab.tiptap.cloud` });
|
|
2609
|
-
}
|
|
2608
|
+
class TiptapCollabProviderWebsocket extends HocuspocusProviderWebsocket {
|
|
2609
|
+
constructor(configuration) {
|
|
2610
|
+
super({ ...configuration, url: `wss://${configuration.appId}.collab.tiptap.cloud` });
|
|
2611
|
+
}
|
|
2610
2612
|
}
|
|
2611
2613
|
|
|
2612
|
-
class TiptapCollabProvider extends HocuspocusProvider {
|
|
2613
|
-
constructor(configuration) {
|
|
2614
|
-
if (!configuration.websocketProvider) {
|
|
2615
|
-
configuration.websocketProvider = new TiptapCollabProviderWebsocket({ appId: configuration.appId });
|
|
2616
|
-
}
|
|
2617
|
-
if (!configuration.token) {
|
|
2618
|
-
configuration.token = 'notoken'; // need to send a token anyway (which will be ignored)
|
|
2619
|
-
}
|
|
2620
|
-
super(configuration);
|
|
2621
|
-
}
|
|
2614
|
+
class TiptapCollabProvider extends HocuspocusProvider {
|
|
2615
|
+
constructor(configuration) {
|
|
2616
|
+
if (!configuration.websocketProvider) {
|
|
2617
|
+
configuration.websocketProvider = new TiptapCollabProviderWebsocket({ appId: configuration.appId });
|
|
2618
|
+
}
|
|
2619
|
+
if (!configuration.token) {
|
|
2620
|
+
configuration.token = 'notoken'; // need to send a token anyway (which will be ignored)
|
|
2621
|
+
}
|
|
2622
|
+
super(configuration);
|
|
2623
|
+
}
|
|
2622
2624
|
}
|
|
2623
2625
|
|
|
2624
2626
|
exports.HocuspocusProvider = HocuspocusProvider;
|