@hocuspocus/provider 1.0.2 → 2.0.0-alpha.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 +370 -209
- package/dist/hocuspocus-provider.cjs.map +1 -1
- package/dist/hocuspocus-provider.esm.js +370 -210
- package/dist/hocuspocus-provider.esm.js.map +1 -1
- package/dist/packages/extension-monitor/src/Dashboard.d.ts +1 -1
- package/dist/packages/extension-monitor/src/index.d.ts +1 -1
- package/dist/packages/extension-redis/src/Redis.d.ts +19 -5
- package/dist/packages/provider/src/HocuspocusCloudProvider.d.ts +2 -1
- package/dist/packages/provider/src/HocuspocusProvider.d.ts +14 -70
- package/dist/packages/provider/src/HocuspocusProviderWebsocket.d.ts +115 -0
- package/dist/packages/provider/src/IncomingMessage.d.ts +2 -0
- package/dist/packages/provider/src/OutgoingMessages/StatelessMessage.d.ts +7 -0
- package/dist/packages/provider/src/index.d.ts +1 -0
- package/dist/packages/provider/src/types.d.ts +7 -1
- package/dist/packages/server/src/Connection.d.ts +10 -11
- package/dist/packages/server/src/Document.d.ts +9 -0
- package/dist/packages/server/src/Hocuspocus.d.ts +3 -8
- package/dist/packages/server/src/IncomingMessage.d.ts +2 -0
- package/dist/packages/server/src/MessageReceiver.d.ts +1 -2
- package/dist/packages/server/src/OutgoingMessage.d.ts +3 -1
- package/dist/packages/server/src/types.d.ts +19 -3
- package/dist/packages/transformer/src/Prosemirror.d.ts +1 -1
- package/dist/tests/providerwebsocket/configuration.d.ts +1 -0
- package/dist/tests/server/beforeBroadcastStateless.d.ts +1 -0
- package/dist/tests/server/onStateless.d.ts +1 -0
- package/dist/tests/utils/index.d.ts +1 -0
- package/dist/tests/utils/newHocuspocusProvider.d.ts +2 -2
- package/dist/tests/utils/newHocuspocusProviderWebsocket.d.ts +3 -0
- package/package.json +3 -3
- package/src/HocuspocusCloudProvider.ts +8 -1
- package/src/HocuspocusProvider.ts +111 -358
- package/src/HocuspocusProviderWebsocket.ts +475 -0
- package/src/IncomingMessage.ts +10 -0
- package/src/MessageReceiver.ts +9 -2
- package/src/OutgoingMessages/AuthenticationMessage.ts +2 -1
- package/src/OutgoingMessages/AwarenessMessage.ts +1 -0
- package/src/OutgoingMessages/QueryAwarenessMessage.ts +5 -0
- package/src/OutgoingMessages/StatelessMessage.ts +17 -0
- package/src/OutgoingMessages/SyncStepOneMessage.ts +1 -0
- package/src/OutgoingMessages/SyncStepTwoMessage.ts +1 -1
- package/src/OutgoingMessages/UpdateMessage.ts +3 -1
- package/src/index.ts +1 -0
- package/src/types.ts +7 -0
- /package/dist/tests/{provider/configuration.d.ts → extension-redis/onStateless.d.ts} +0 -0
- /package/dist/tests/{server/getDocumentName.d.ts → provider/onStateless.d.ts} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Y from 'yjs';
|
|
2
|
-
import { retry } from '@lifeomic/attempt';
|
|
3
2
|
import { readAuthMessage, writeAuthentication, awarenessStatesToArray, WsReadyStates, Unauthorized, Forbidden } from '@hocuspocus/common';
|
|
3
|
+
import { retry } from '@lifeomic/attempt';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Utility module to work with key-value stores.
|
|
@@ -1324,19 +1324,6 @@ const createMutex = () => {
|
|
|
1324
1324
|
}
|
|
1325
1325
|
};
|
|
1326
1326
|
|
|
1327
|
-
/**
|
|
1328
|
-
* Utility module to work with urls.
|
|
1329
|
-
*
|
|
1330
|
-
* @module url
|
|
1331
|
-
*/
|
|
1332
|
-
|
|
1333
|
-
/**
|
|
1334
|
-
* @param {Object<string,string>} params
|
|
1335
|
-
* @return {string}
|
|
1336
|
-
*/
|
|
1337
|
-
const encodeQueryParams = params =>
|
|
1338
|
-
map(params, (val, key) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`).join('&');
|
|
1339
|
-
|
|
1340
1327
|
class EventEmitter {
|
|
1341
1328
|
constructor() {
|
|
1342
1329
|
this.callbacks = {};
|
|
@@ -1381,12 +1368,18 @@ class IncomingMessage {
|
|
|
1381
1368
|
readVarUint() {
|
|
1382
1369
|
return readVarUint(this.decoder);
|
|
1383
1370
|
}
|
|
1371
|
+
readVarString() {
|
|
1372
|
+
return readVarString(this.decoder);
|
|
1373
|
+
}
|
|
1384
1374
|
readVarUint8Array() {
|
|
1385
1375
|
return readVarUint8Array(this.decoder);
|
|
1386
1376
|
}
|
|
1387
1377
|
writeVarUint(type) {
|
|
1388
1378
|
return writeVarUint(this.encoder, type);
|
|
1389
1379
|
}
|
|
1380
|
+
writeVarString(string) {
|
|
1381
|
+
return writeVarString(this.encoder, string);
|
|
1382
|
+
}
|
|
1390
1383
|
writeVarUint8Array(data) {
|
|
1391
1384
|
return writeVarUint8Array(this.encoder, data);
|
|
1392
1385
|
}
|
|
@@ -1528,6 +1521,7 @@ var MessageType;
|
|
|
1528
1521
|
MessageType[MessageType["Awareness"] = 1] = "Awareness";
|
|
1529
1522
|
MessageType[MessageType["Auth"] = 2] = "Auth";
|
|
1530
1523
|
MessageType[MessageType["QueryAwareness"] = 3] = "QueryAwareness";
|
|
1524
|
+
MessageType[MessageType["Stateless"] = 5] = "Stateless";
|
|
1531
1525
|
})(MessageType || (MessageType = {}));
|
|
1532
1526
|
var WebSocketStatus;
|
|
1533
1527
|
(function (WebSocketStatus) {
|
|
@@ -1560,6 +1554,7 @@ class MessageReceiver {
|
|
|
1560
1554
|
apply(provider, emitSynced = true) {
|
|
1561
1555
|
const { message } = this;
|
|
1562
1556
|
const type = message.readVarUint();
|
|
1557
|
+
const emptyMessageLength = message.length();
|
|
1563
1558
|
switch (type) {
|
|
1564
1559
|
case MessageType.Sync:
|
|
1565
1560
|
this.applySyncMessage(provider, emitSynced);
|
|
@@ -1573,11 +1568,14 @@ class MessageReceiver {
|
|
|
1573
1568
|
case MessageType.QueryAwareness:
|
|
1574
1569
|
this.applyQueryAwarenessMessage(provider);
|
|
1575
1570
|
break;
|
|
1571
|
+
case MessageType.Stateless:
|
|
1572
|
+
provider.receiveStateless(readVarString(message.decoder));
|
|
1573
|
+
break;
|
|
1576
1574
|
default:
|
|
1577
1575
|
throw new Error(`Can’t apply message of unknown type: ${type}`);
|
|
1578
1576
|
}
|
|
1579
1577
|
// Reply
|
|
1580
|
-
if (message.length() > 1) {
|
|
1578
|
+
if (message.length() > emptyMessageLength + 1) { // length of documentName (considered in emptyMessageLength plus length of yjs sync type, set in applySyncMessage)
|
|
1581
1579
|
if (this.broadcasted) {
|
|
1582
1580
|
// TODO: Some weird TypeScript error
|
|
1583
1581
|
// @ts-ignore
|
|
@@ -1596,7 +1594,7 @@ class MessageReceiver {
|
|
|
1596
1594
|
// Apply update
|
|
1597
1595
|
const syncMessageType = readSyncMessage(message.decoder, message.encoder, provider.document, provider);
|
|
1598
1596
|
// Synced once we receive Step2
|
|
1599
|
-
if (emitSynced &&
|
|
1597
|
+
if (emitSynced && syncMessageType === messageYjsSyncStep2) {
|
|
1600
1598
|
provider.synced = true;
|
|
1601
1599
|
}
|
|
1602
1600
|
if (syncMessageType === messageYjsUpdate || syncMessageType === messageYjsSyncStep2) {
|
|
@@ -1646,6 +1644,7 @@ class SyncStepOneMessage extends OutgoingMessage {
|
|
|
1646
1644
|
if (typeof args.document === 'undefined') {
|
|
1647
1645
|
throw new Error('The sync step one message requires document as an argument');
|
|
1648
1646
|
}
|
|
1647
|
+
writeVarString(this.encoder, args.documentName);
|
|
1649
1648
|
writeVarUint(this.encoder, this.type);
|
|
1650
1649
|
writeSyncStep1(this.encoder, args.document);
|
|
1651
1650
|
return this.encoder;
|
|
@@ -1662,6 +1661,7 @@ class SyncStepTwoMessage extends OutgoingMessage {
|
|
|
1662
1661
|
if (typeof args.document === 'undefined') {
|
|
1663
1662
|
throw new Error('The sync step two message requires document as an argument');
|
|
1664
1663
|
}
|
|
1664
|
+
writeVarString(this.encoder, args.documentName);
|
|
1665
1665
|
writeVarUint(this.encoder, this.type);
|
|
1666
1666
|
writeSyncStep2(this.encoder, args.document);
|
|
1667
1667
|
return this.encoder;
|
|
@@ -1675,6 +1675,9 @@ class QueryAwarenessMessage extends OutgoingMessage {
|
|
|
1675
1675
|
this.description = 'Queries awareness states';
|
|
1676
1676
|
}
|
|
1677
1677
|
get(args) {
|
|
1678
|
+
console.log('queryAwareness: writing string docName', args.documentName);
|
|
1679
|
+
console.log(this.encoder.cpos);
|
|
1680
|
+
writeVarString(this.encoder, args.documentName);
|
|
1678
1681
|
writeVarUint(this.encoder, this.type);
|
|
1679
1682
|
return this.encoder;
|
|
1680
1683
|
}
|
|
@@ -1690,6 +1693,7 @@ class AuthenticationMessage extends OutgoingMessage {
|
|
|
1690
1693
|
if (typeof args.token === 'undefined') {
|
|
1691
1694
|
throw new Error('The authentication message requires `token` as an argument.');
|
|
1692
1695
|
}
|
|
1696
|
+
writeVarString(this.encoder, args.documentName);
|
|
1693
1697
|
writeVarUint(this.encoder, this.type);
|
|
1694
1698
|
writeAuthentication(this.encoder, args.token);
|
|
1695
1699
|
return this.encoder;
|
|
@@ -1709,6 +1713,7 @@ class AwarenessMessage extends OutgoingMessage {
|
|
|
1709
1713
|
if (typeof args.clients === 'undefined') {
|
|
1710
1714
|
throw new Error('The awareness message requires clients as an argument');
|
|
1711
1715
|
}
|
|
1716
|
+
writeVarString(this.encoder, args.documentName);
|
|
1712
1717
|
writeVarUint(this.encoder, this.type);
|
|
1713
1718
|
let awarenessUpdate;
|
|
1714
1719
|
if (args.states === undefined) {
|
|
@@ -1729,24 +1734,329 @@ class UpdateMessage extends OutgoingMessage {
|
|
|
1729
1734
|
this.description = 'A document update';
|
|
1730
1735
|
}
|
|
1731
1736
|
get(args) {
|
|
1737
|
+
writeVarString(this.encoder, args.documentName);
|
|
1732
1738
|
writeVarUint(this.encoder, this.type);
|
|
1733
1739
|
writeUpdate(this.encoder, args.update);
|
|
1734
1740
|
return this.encoder;
|
|
1735
1741
|
}
|
|
1736
1742
|
}
|
|
1737
1743
|
|
|
1744
|
+
class StatelessMessage extends OutgoingMessage {
|
|
1745
|
+
constructor() {
|
|
1746
|
+
super(...arguments);
|
|
1747
|
+
this.type = MessageType.Stateless;
|
|
1748
|
+
this.description = 'A stateless message';
|
|
1749
|
+
}
|
|
1750
|
+
get(args) {
|
|
1751
|
+
var _a;
|
|
1752
|
+
writeVarString(this.encoder, args.documentName);
|
|
1753
|
+
writeVarUint(this.encoder, this.type);
|
|
1754
|
+
writeVarString(this.encoder, (_a = args.payload) !== null && _a !== void 0 ? _a : '');
|
|
1755
|
+
return this.encoder;
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1738
1759
|
class HocuspocusProvider extends EventEmitter {
|
|
1739
1760
|
constructor(configuration) {
|
|
1740
1761
|
super();
|
|
1741
1762
|
this.configuration = {
|
|
1742
1763
|
name: '',
|
|
1764
|
+
// @ts-ignore
|
|
1765
|
+
document: undefined,
|
|
1766
|
+
// @ts-ignore
|
|
1767
|
+
awareness: undefined,
|
|
1768
|
+
token: null,
|
|
1769
|
+
parameters: {},
|
|
1770
|
+
broadcast: true,
|
|
1771
|
+
forceSyncInterval: false,
|
|
1772
|
+
onAuthenticated: () => null,
|
|
1773
|
+
onAuthenticationFailed: () => null,
|
|
1774
|
+
onOpen: () => null,
|
|
1775
|
+
onConnect: () => null,
|
|
1776
|
+
onMessage: () => null,
|
|
1777
|
+
onOutgoingMessage: () => null,
|
|
1778
|
+
onStatus: () => null,
|
|
1779
|
+
onSynced: () => null,
|
|
1780
|
+
onDisconnect: () => null,
|
|
1781
|
+
onClose: () => null,
|
|
1782
|
+
onDestroy: () => null,
|
|
1783
|
+
onAwarenessUpdate: () => null,
|
|
1784
|
+
onAwarenessChange: () => null,
|
|
1785
|
+
onStateless: () => null,
|
|
1786
|
+
quiet: false,
|
|
1787
|
+
};
|
|
1788
|
+
this.subscribedToBroadcastChannel = false;
|
|
1789
|
+
this.isSynced = false;
|
|
1790
|
+
this.unsyncedChanges = 0;
|
|
1791
|
+
this.status = WebSocketStatus.Disconnected;
|
|
1792
|
+
this.isAuthenticated = false;
|
|
1793
|
+
this.mux = createMutex();
|
|
1794
|
+
this.intervals = {
|
|
1795
|
+
forceSync: null,
|
|
1796
|
+
};
|
|
1797
|
+
this.boundBeforeUnload = this.beforeUnload.bind(this);
|
|
1798
|
+
this.boundBroadcastChannelSubscriber = this.broadcastChannelSubscriber.bind(this);
|
|
1799
|
+
this.setConfiguration(configuration);
|
|
1800
|
+
this.configuration.document = configuration.document ? configuration.document : new Y.Doc();
|
|
1801
|
+
this.configuration.awareness = configuration.awareness ? configuration.awareness : new Awareness(this.document);
|
|
1802
|
+
this.on('open', this.configuration.onOpen);
|
|
1803
|
+
this.on('message', this.configuration.onMessage);
|
|
1804
|
+
this.on('outgoingMessage', this.configuration.onOutgoingMessage);
|
|
1805
|
+
this.on('synced', this.configuration.onSynced);
|
|
1806
|
+
this.on('destroy', this.configuration.onDestroy);
|
|
1807
|
+
this.on('awarenessUpdate', this.configuration.onAwarenessUpdate);
|
|
1808
|
+
this.on('awarenessChange', this.configuration.onAwarenessChange);
|
|
1809
|
+
this.on('stateless', this.configuration.onStateless);
|
|
1810
|
+
this.on('authenticated', this.configuration.onAuthenticated);
|
|
1811
|
+
this.on('authenticationFailed', this.configuration.onAuthenticationFailed);
|
|
1812
|
+
this.configuration.websocketProvider.on('connect', this.configuration.onConnect);
|
|
1813
|
+
this.configuration.websocketProvider.on('connect', (e) => this.emit('connect', e));
|
|
1814
|
+
this.configuration.websocketProvider.on('open', this.onOpen.bind(this));
|
|
1815
|
+
this.configuration.websocketProvider.on('open', (e) => this.emit('open', e));
|
|
1816
|
+
this.configuration.websocketProvider.on('message', this.onMessage.bind(this));
|
|
1817
|
+
this.configuration.websocketProvider.on('close', this.onClose.bind(this));
|
|
1818
|
+
this.configuration.websocketProvider.on('close', this.configuration.onClose);
|
|
1819
|
+
this.configuration.websocketProvider.on('close', (e) => this.emit('close', e));
|
|
1820
|
+
this.configuration.websocketProvider.on('status', this.onStatus.bind(this));
|
|
1821
|
+
this.configuration.websocketProvider.on('disconnect', this.configuration.onDisconnect);
|
|
1822
|
+
this.configuration.websocketProvider.on('disconnect', (e) => this.emit('disconnect', e));
|
|
1823
|
+
this.configuration.websocketProvider.on('destroy', this.configuration.onDestroy);
|
|
1824
|
+
this.configuration.websocketProvider.on('destroy', (e) => this.emit('destroy', e));
|
|
1825
|
+
this.awareness.on('update', () => {
|
|
1826
|
+
this.emit('awarenessUpdate', { states: awarenessStatesToArray(this.awareness.getStates()) });
|
|
1827
|
+
});
|
|
1828
|
+
this.awareness.on('change', () => {
|
|
1829
|
+
this.emit('awarenessChange', { states: awarenessStatesToArray(this.awareness.getStates()) });
|
|
1830
|
+
});
|
|
1831
|
+
this.document.on('update', this.documentUpdateHandler.bind(this));
|
|
1832
|
+
this.awareness.on('update', this.awarenessUpdateHandler.bind(this));
|
|
1833
|
+
this.registerEventListeners();
|
|
1834
|
+
if (this.configuration.forceSyncInterval) {
|
|
1835
|
+
this.intervals.forceSync = setInterval(this.forceSync.bind(this), this.configuration.forceSyncInterval);
|
|
1836
|
+
}
|
|
1837
|
+
this.configuration.websocketProvider.attach(this);
|
|
1838
|
+
}
|
|
1839
|
+
onStatus({ status }) {
|
|
1840
|
+
this.status = status;
|
|
1841
|
+
this.configuration.onStatus({ status });
|
|
1842
|
+
this.emit('status', { status });
|
|
1843
|
+
}
|
|
1844
|
+
setConfiguration(configuration = {}) {
|
|
1845
|
+
this.configuration = { ...this.configuration, ...configuration };
|
|
1846
|
+
}
|
|
1847
|
+
get document() {
|
|
1848
|
+
return this.configuration.document;
|
|
1849
|
+
}
|
|
1850
|
+
get awareness() {
|
|
1851
|
+
return this.configuration.awareness;
|
|
1852
|
+
}
|
|
1853
|
+
get hasUnsyncedChanges() {
|
|
1854
|
+
return this.unsyncedChanges > 0;
|
|
1855
|
+
}
|
|
1856
|
+
forceSync() {
|
|
1857
|
+
this.send(SyncStepOneMessage, { document: this.document, documentName: this.configuration.name });
|
|
1858
|
+
}
|
|
1859
|
+
beforeUnload() {
|
|
1860
|
+
removeAwarenessStates(this.awareness, [this.document.clientID], 'window unload');
|
|
1861
|
+
}
|
|
1862
|
+
registerEventListeners() {
|
|
1863
|
+
if (typeof window === 'undefined') {
|
|
1864
|
+
return;
|
|
1865
|
+
}
|
|
1866
|
+
window.addEventListener('beforeunload', this.boundBeforeUnload);
|
|
1867
|
+
}
|
|
1868
|
+
sendStateless(payload) {
|
|
1869
|
+
this.send(StatelessMessage, { documentName: this.configuration.name, payload });
|
|
1870
|
+
}
|
|
1871
|
+
documentUpdateHandler(update, origin) {
|
|
1872
|
+
if (origin === this) {
|
|
1873
|
+
return;
|
|
1874
|
+
}
|
|
1875
|
+
this.unsyncedChanges += 1;
|
|
1876
|
+
this.send(UpdateMessage, { update, documentName: this.configuration.name }, true);
|
|
1877
|
+
}
|
|
1878
|
+
awarenessUpdateHandler({ added, updated, removed }, origin) {
|
|
1879
|
+
const changedClients = added.concat(updated).concat(removed);
|
|
1880
|
+
this.send(AwarenessMessage, {
|
|
1881
|
+
awareness: this.awareness,
|
|
1882
|
+
clients: changedClients,
|
|
1883
|
+
documentName: this.configuration.name,
|
|
1884
|
+
}, true);
|
|
1885
|
+
}
|
|
1886
|
+
get synced() {
|
|
1887
|
+
return this.isSynced;
|
|
1888
|
+
}
|
|
1889
|
+
set synced(state) {
|
|
1890
|
+
if (this.isSynced === state) {
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1893
|
+
this.isSynced = state;
|
|
1894
|
+
this.emit('synced', { state });
|
|
1895
|
+
this.emit('sync', { state });
|
|
1896
|
+
}
|
|
1897
|
+
receiveStateless(payload) {
|
|
1898
|
+
this.emit('stateless', { payload });
|
|
1899
|
+
}
|
|
1900
|
+
get isAuthenticationRequired() {
|
|
1901
|
+
return !!this.configuration.token && !this.isAuthenticated;
|
|
1902
|
+
}
|
|
1903
|
+
disconnect() {
|
|
1904
|
+
this.disconnectBroadcastChannel();
|
|
1905
|
+
this.configuration.websocketProvider.detach(this);
|
|
1906
|
+
}
|
|
1907
|
+
async onOpen(event) {
|
|
1908
|
+
this.emit('open', { event });
|
|
1909
|
+
if (this.isAuthenticationRequired) {
|
|
1910
|
+
this.send(AuthenticationMessage, {
|
|
1911
|
+
token: await this.getToken(),
|
|
1912
|
+
documentName: this.configuration.name,
|
|
1913
|
+
});
|
|
1914
|
+
return;
|
|
1915
|
+
}
|
|
1916
|
+
this.startSync();
|
|
1917
|
+
}
|
|
1918
|
+
async getToken() {
|
|
1919
|
+
if (typeof this.configuration.token === 'function') {
|
|
1920
|
+
const token = await this.configuration.token();
|
|
1921
|
+
return token;
|
|
1922
|
+
}
|
|
1923
|
+
return this.configuration.token;
|
|
1924
|
+
}
|
|
1925
|
+
startSync() {
|
|
1926
|
+
this.send(SyncStepOneMessage, { document: this.document, documentName: this.configuration.name });
|
|
1927
|
+
if (this.awareness.getLocalState() !== null) {
|
|
1928
|
+
this.send(AwarenessMessage, {
|
|
1929
|
+
awareness: this.awareness,
|
|
1930
|
+
clients: [this.document.clientID],
|
|
1931
|
+
documentName: this.configuration.name,
|
|
1932
|
+
});
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
send(message, args, broadcast = false) {
|
|
1936
|
+
if (broadcast) {
|
|
1937
|
+
this.mux(() => { this.broadcast(message, args); });
|
|
1938
|
+
}
|
|
1939
|
+
const messageSender = new MessageSender(message, args);
|
|
1940
|
+
this.emit('outgoingMessage', { message: messageSender.message });
|
|
1941
|
+
messageSender.send(this.configuration.websocketProvider);
|
|
1942
|
+
}
|
|
1943
|
+
onMessage(event) {
|
|
1944
|
+
const message = new IncomingMessage(event.data);
|
|
1945
|
+
const documentName = message.readVarString();
|
|
1946
|
+
if (documentName !== this.configuration.name) {
|
|
1947
|
+
return; // message is meant for another provider
|
|
1948
|
+
}
|
|
1949
|
+
message.writeVarString(documentName);
|
|
1950
|
+
this.emit('message', { event, message: new IncomingMessage(event.data) });
|
|
1951
|
+
new MessageReceiver(message).apply(this);
|
|
1952
|
+
}
|
|
1953
|
+
onClose(event) {
|
|
1954
|
+
this.isAuthenticated = false;
|
|
1955
|
+
this.synced = false;
|
|
1956
|
+
// update awareness (all users except local left)
|
|
1957
|
+
removeAwarenessStates(this.awareness, Array.from(this.awareness.getStates().keys()).filter(client => client !== this.document.clientID), this);
|
|
1958
|
+
}
|
|
1959
|
+
destroy() {
|
|
1960
|
+
this.emit('destroy');
|
|
1961
|
+
if (this.intervals.forceSync) {
|
|
1962
|
+
clearInterval(this.intervals.forceSync);
|
|
1963
|
+
}
|
|
1964
|
+
removeAwarenessStates(this.awareness, [this.document.clientID], 'provider destroy');
|
|
1965
|
+
this.disconnect();
|
|
1966
|
+
this.awareness.off('update', this.awarenessUpdateHandler);
|
|
1967
|
+
this.document.off('update', this.documentUpdateHandler);
|
|
1968
|
+
this.removeAllListeners();
|
|
1969
|
+
if (typeof window === 'undefined') {
|
|
1970
|
+
return;
|
|
1971
|
+
}
|
|
1972
|
+
window.removeEventListener('beforeunload', this.boundBeforeUnload);
|
|
1973
|
+
}
|
|
1974
|
+
permissionDeniedHandler(reason) {
|
|
1975
|
+
this.emit('authenticationFailed', { reason });
|
|
1976
|
+
this.isAuthenticated = false;
|
|
1977
|
+
this.disconnect();
|
|
1978
|
+
this.status = WebSocketStatus.Disconnected;
|
|
1979
|
+
}
|
|
1980
|
+
authenticatedHandler() {
|
|
1981
|
+
this.isAuthenticated = true;
|
|
1982
|
+
this.emit('authenticated');
|
|
1983
|
+
this.startSync();
|
|
1984
|
+
}
|
|
1985
|
+
get broadcastChannel() {
|
|
1986
|
+
return `${this.configuration.name}`;
|
|
1987
|
+
}
|
|
1988
|
+
broadcastChannelSubscriber(data) {
|
|
1989
|
+
this.mux(() => {
|
|
1990
|
+
const message = new IncomingMessage(data);
|
|
1991
|
+
const documentName = message.readVarString();
|
|
1992
|
+
message.writeVarString(documentName);
|
|
1993
|
+
new MessageReceiver(message)
|
|
1994
|
+
.setBroadcasted(true)
|
|
1995
|
+
.apply(this, false);
|
|
1996
|
+
});
|
|
1997
|
+
}
|
|
1998
|
+
subscribeToBroadcastChannel() {
|
|
1999
|
+
if (!this.subscribedToBroadcastChannel) {
|
|
2000
|
+
subscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber);
|
|
2001
|
+
this.subscribedToBroadcastChannel = true;
|
|
2002
|
+
}
|
|
2003
|
+
this.mux(() => {
|
|
2004
|
+
this.broadcast(SyncStepOneMessage, { document: this.document });
|
|
2005
|
+
this.broadcast(SyncStepTwoMessage, { document: this.document });
|
|
2006
|
+
this.broadcast(QueryAwarenessMessage, { document: this.document });
|
|
2007
|
+
this.broadcast(AwarenessMessage, { awareness: this.awareness, clients: [this.document.clientID], document: this.document });
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
disconnectBroadcastChannel() {
|
|
2011
|
+
// broadcast message with local awareness state set to null (indicating disconnect)
|
|
2012
|
+
this.send(AwarenessMessage, {
|
|
2013
|
+
awareness: this.awareness,
|
|
2014
|
+
clients: [this.document.clientID],
|
|
2015
|
+
states: new Map(),
|
|
2016
|
+
documentName: this.configuration.name,
|
|
2017
|
+
}, true);
|
|
2018
|
+
if (this.subscribedToBroadcastChannel) {
|
|
2019
|
+
unsubscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber);
|
|
2020
|
+
this.subscribedToBroadcastChannel = false;
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
broadcast(Message, args) {
|
|
2024
|
+
if (!this.configuration.broadcast) {
|
|
2025
|
+
return;
|
|
2026
|
+
}
|
|
2027
|
+
if (!this.subscribedToBroadcastChannel) {
|
|
2028
|
+
return;
|
|
2029
|
+
}
|
|
2030
|
+
new MessageSender(Message, args).broadcast(this.broadcastChannel);
|
|
2031
|
+
}
|
|
2032
|
+
setAwarenessField(key, value) {
|
|
2033
|
+
this.awareness.setLocalStateField(key, value);
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
/**
|
|
2038
|
+
* Utility module to work with urls.
|
|
2039
|
+
*
|
|
2040
|
+
* @module url
|
|
2041
|
+
*/
|
|
2042
|
+
|
|
2043
|
+
/**
|
|
2044
|
+
* @param {Object<string,string>} params
|
|
2045
|
+
* @return {string}
|
|
2046
|
+
*/
|
|
2047
|
+
const encodeQueryParams = params =>
|
|
2048
|
+
map(params, (val, key) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`).join('&');
|
|
2049
|
+
|
|
2050
|
+
class HocuspocusProviderWebsocket extends EventEmitter {
|
|
2051
|
+
constructor(configuration) {
|
|
2052
|
+
super();
|
|
2053
|
+
this.configuration = {
|
|
1743
2054
|
url: '',
|
|
1744
2055
|
// @ts-ignore
|
|
1745
2056
|
document: undefined,
|
|
1746
2057
|
// @ts-ignore
|
|
1747
2058
|
awareness: undefined,
|
|
1748
2059
|
WebSocketPolyfill: undefined,
|
|
1749
|
-
token: null,
|
|
1750
2060
|
parameters: {},
|
|
1751
2061
|
connect: true,
|
|
1752
2062
|
broadcast: true,
|
|
@@ -1769,14 +2079,11 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1769
2079
|
jitter: true,
|
|
1770
2080
|
// retry forever
|
|
1771
2081
|
timeout: 0,
|
|
1772
|
-
onAuthenticated: () => null,
|
|
1773
|
-
onAuthenticationFailed: () => null,
|
|
1774
2082
|
onOpen: () => null,
|
|
1775
2083
|
onConnect: () => null,
|
|
1776
2084
|
onMessage: () => null,
|
|
1777
2085
|
onOutgoingMessage: () => null,
|
|
1778
2086
|
onStatus: () => null,
|
|
1779
|
-
onSynced: () => null,
|
|
1780
2087
|
onDisconnect: () => null,
|
|
1781
2088
|
onClose: () => null,
|
|
1782
2089
|
onDestroy: () => null,
|
|
@@ -1788,9 +2095,6 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1788
2095
|
this.webSocket = null;
|
|
1789
2096
|
this.shouldConnect = true;
|
|
1790
2097
|
this.status = WebSocketStatus.Disconnected;
|
|
1791
|
-
this.isSynced = false;
|
|
1792
|
-
this.unsyncedChanges = 0;
|
|
1793
|
-
this.isAuthenticated = false;
|
|
1794
2098
|
this.lastMessageReceived = 0;
|
|
1795
2099
|
this.mux = createMutex();
|
|
1796
2100
|
this.intervals = {
|
|
@@ -1798,39 +2102,27 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1798
2102
|
connectionChecker: null,
|
|
1799
2103
|
};
|
|
1800
2104
|
this.connectionAttempt = null;
|
|
2105
|
+
this.receivedOnOpenPayload = undefined;
|
|
2106
|
+
this.receivedOnStatusPayload = undefined;
|
|
1801
2107
|
this.boundConnect = this.connect.bind(this);
|
|
1802
|
-
this.boundBeforeUnload = this.beforeUnload.bind(this);
|
|
1803
|
-
this.boundBroadcastChannelSubscriber = this.broadcastChannelSubscriber.bind(this);
|
|
1804
2108
|
this.setConfiguration(configuration);
|
|
1805
|
-
this.configuration.document = configuration.document ? configuration.document : new Y.Doc();
|
|
1806
|
-
this.configuration.awareness = configuration.awareness ? configuration.awareness : new Awareness(this.document);
|
|
1807
2109
|
this.configuration.WebSocketPolyfill = configuration.WebSocketPolyfill ? configuration.WebSocketPolyfill : WebSocket;
|
|
1808
2110
|
this.on('open', this.configuration.onOpen);
|
|
1809
|
-
this.on('
|
|
1810
|
-
this.on('authenticationFailed', this.configuration.onAuthenticationFailed);
|
|
2111
|
+
this.on('open', this.onOpen.bind(this));
|
|
1811
2112
|
this.on('connect', this.configuration.onConnect);
|
|
1812
2113
|
this.on('message', this.configuration.onMessage);
|
|
1813
2114
|
this.on('outgoingMessage', this.configuration.onOutgoingMessage);
|
|
1814
|
-
this.on('synced', this.configuration.onSynced);
|
|
1815
2115
|
this.on('status', this.configuration.onStatus);
|
|
2116
|
+
this.on('status', this.onStatus.bind(this));
|
|
1816
2117
|
this.on('disconnect', this.configuration.onDisconnect);
|
|
1817
2118
|
this.on('close', this.configuration.onClose);
|
|
1818
2119
|
this.on('destroy', this.configuration.onDestroy);
|
|
1819
2120
|
this.on('awarenessUpdate', this.configuration.onAwarenessUpdate);
|
|
1820
2121
|
this.on('awarenessChange', this.configuration.onAwarenessChange);
|
|
1821
|
-
this.
|
|
1822
|
-
|
|
1823
|
-
});
|
|
1824
|
-
this.awareness.on('change', () => {
|
|
1825
|
-
this.emit('awarenessChange', { states: awarenessStatesToArray(this.awareness.getStates()) });
|
|
1826
|
-
});
|
|
1827
|
-
this.document.on('update', this.documentUpdateHandler.bind(this));
|
|
1828
|
-
this.awareness.on('update', this.awarenessUpdateHandler.bind(this));
|
|
2122
|
+
this.on('close', this.onClose.bind(this));
|
|
2123
|
+
this.on('message', this.onMessage.bind(this));
|
|
1829
2124
|
this.registerEventListeners();
|
|
1830
2125
|
this.intervals.connectionChecker = setInterval(this.checkConnection.bind(this), this.configuration.messageReconnectTimeout / 10);
|
|
1831
|
-
if (this.configuration.forceSyncInterval) {
|
|
1832
|
-
this.intervals.forceSync = setInterval(this.forceSync.bind(this), this.configuration.forceSyncInterval);
|
|
1833
|
-
}
|
|
1834
2126
|
if (typeof configuration.connect !== 'undefined') {
|
|
1835
2127
|
this.shouldConnect = configuration.connect;
|
|
1836
2128
|
}
|
|
@@ -1839,6 +2131,23 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1839
2131
|
}
|
|
1840
2132
|
this.connect();
|
|
1841
2133
|
}
|
|
2134
|
+
async onOpen(event) {
|
|
2135
|
+
this.receivedOnOpenPayload = event;
|
|
2136
|
+
}
|
|
2137
|
+
async onStatus(data) {
|
|
2138
|
+
this.receivedOnStatusPayload = data;
|
|
2139
|
+
}
|
|
2140
|
+
attach(provider) {
|
|
2141
|
+
if (this.receivedOnOpenPayload) {
|
|
2142
|
+
provider.onOpen(this.receivedOnOpenPayload);
|
|
2143
|
+
}
|
|
2144
|
+
if (this.receivedOnStatusPayload) {
|
|
2145
|
+
provider.onStatus(this.receivedOnStatusPayload);
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
detach(provider) {
|
|
2149
|
+
// tell the server to remove the listener
|
|
2150
|
+
}
|
|
1842
2151
|
setConfiguration(configuration = {}) {
|
|
1843
2152
|
this.configuration = { ...this.configuration, ...configuration };
|
|
1844
2153
|
}
|
|
@@ -1851,9 +2160,7 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1851
2160
|
this.cancelWebsocketRetry();
|
|
1852
2161
|
this.cancelWebsocketRetry = undefined;
|
|
1853
2162
|
}
|
|
1854
|
-
this.unsyncedChanges = 0; // set to 0 in case we got reconnected
|
|
1855
2163
|
this.shouldConnect = true;
|
|
1856
|
-
this.subscribeToBroadcastChannel();
|
|
1857
2164
|
const abortableRetry = () => {
|
|
1858
2165
|
let cancelAttempt = false;
|
|
1859
2166
|
const retryPromise = retry(this.createWebSocketConnection.bind(this), {
|
|
@@ -1897,15 +2204,14 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1897
2204
|
// Init the WebSocket connection
|
|
1898
2205
|
const ws = new this.configuration.WebSocketPolyfill(this.url);
|
|
1899
2206
|
ws.binaryType = 'arraybuffer';
|
|
1900
|
-
ws.onmessage = this.
|
|
1901
|
-
ws.onclose = this.
|
|
1902
|
-
ws.onopen = this.
|
|
2207
|
+
ws.onmessage = (payload) => this.emit('message', payload);
|
|
2208
|
+
ws.onclose = (payload) => this.emit('close', { event: payload });
|
|
2209
|
+
ws.onopen = (payload) => this.emit('open', payload);
|
|
1903
2210
|
ws.onerror = (err) => {
|
|
1904
2211
|
reject(err);
|
|
1905
2212
|
};
|
|
1906
2213
|
this.webSocket = ws;
|
|
1907
2214
|
// Reset the status
|
|
1908
|
-
this.synced = false;
|
|
1909
2215
|
this.status = WebSocketStatus.Connecting;
|
|
1910
2216
|
this.emit('status', { status: WebSocketStatus.Connecting });
|
|
1911
2217
|
// Store resolve/reject for later use
|
|
@@ -1915,13 +2221,17 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1915
2221
|
};
|
|
1916
2222
|
});
|
|
1917
2223
|
}
|
|
2224
|
+
onMessage(event) {
|
|
2225
|
+
this.resolveConnectionAttempt();
|
|
2226
|
+
}
|
|
1918
2227
|
resolveConnectionAttempt() {
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
2228
|
+
if (this.connectionAttempt) {
|
|
2229
|
+
this.connectionAttempt.resolve();
|
|
2230
|
+
this.connectionAttempt = null;
|
|
2231
|
+
this.status = WebSocketStatus.Connected;
|
|
2232
|
+
this.emit('status', { status: WebSocketStatus.Connected });
|
|
2233
|
+
this.emit('connect');
|
|
2234
|
+
}
|
|
1925
2235
|
}
|
|
1926
2236
|
stopConnectionAttempt() {
|
|
1927
2237
|
this.connectionAttempt = null;
|
|
@@ -1931,15 +2241,6 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1931
2241
|
(_a = this.connectionAttempt) === null || _a === void 0 ? void 0 : _a.reject();
|
|
1932
2242
|
this.connectionAttempt = null;
|
|
1933
2243
|
}
|
|
1934
|
-
get document() {
|
|
1935
|
-
return this.configuration.document;
|
|
1936
|
-
}
|
|
1937
|
-
get awareness() {
|
|
1938
|
-
return this.configuration.awareness;
|
|
1939
|
-
}
|
|
1940
|
-
get hasUnsyncedChanges() {
|
|
1941
|
-
return this.unsyncedChanges > 0;
|
|
1942
|
-
}
|
|
1943
2244
|
checkConnection() {
|
|
1944
2245
|
var _a;
|
|
1945
2246
|
// Don’t check the connection when it’s not even established
|
|
@@ -1958,45 +2259,11 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1958
2259
|
// Awareness updates, which are updated every 15 seconds.
|
|
1959
2260
|
(_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.close();
|
|
1960
2261
|
}
|
|
1961
|
-
forceSync() {
|
|
1962
|
-
if (!this.webSocket) {
|
|
1963
|
-
return;
|
|
1964
|
-
}
|
|
1965
|
-
this.send(SyncStepOneMessage, { document: this.document });
|
|
1966
|
-
}
|
|
1967
|
-
beforeUnload() {
|
|
1968
|
-
removeAwarenessStates(this.awareness, [this.document.clientID], 'window unload');
|
|
1969
|
-
}
|
|
1970
2262
|
registerEventListeners() {
|
|
1971
2263
|
if (typeof window === 'undefined') {
|
|
1972
2264
|
return;
|
|
1973
2265
|
}
|
|
1974
2266
|
window.addEventListener('online', this.boundConnect);
|
|
1975
|
-
window.addEventListener('beforeunload', this.boundBeforeUnload);
|
|
1976
|
-
}
|
|
1977
|
-
documentUpdateHandler(update, origin) {
|
|
1978
|
-
if (origin === this) {
|
|
1979
|
-
return;
|
|
1980
|
-
}
|
|
1981
|
-
this.unsyncedChanges += 1;
|
|
1982
|
-
this.send(UpdateMessage, { update }, true);
|
|
1983
|
-
}
|
|
1984
|
-
awarenessUpdateHandler({ added, updated, removed }, origin) {
|
|
1985
|
-
const changedClients = added.concat(updated).concat(removed);
|
|
1986
|
-
this.send(AwarenessMessage, {
|
|
1987
|
-
awareness: this.awareness,
|
|
1988
|
-
clients: changedClients,
|
|
1989
|
-
}, true);
|
|
1990
|
-
}
|
|
1991
|
-
permissionDeniedHandler(reason) {
|
|
1992
|
-
this.emit('authenticationFailed', { reason });
|
|
1993
|
-
this.isAuthenticated = false;
|
|
1994
|
-
this.shouldConnect = false;
|
|
1995
|
-
}
|
|
1996
|
-
authenticatedHandler() {
|
|
1997
|
-
this.isAuthenticated = true;
|
|
1998
|
-
this.emit('authenticated');
|
|
1999
|
-
this.startSync();
|
|
2000
2267
|
}
|
|
2001
2268
|
// Ensure that the URL always ends with /
|
|
2002
2269
|
get serverUrl() {
|
|
@@ -2007,25 +2274,10 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
2007
2274
|
}
|
|
2008
2275
|
get url() {
|
|
2009
2276
|
const encodedParams = encodeQueryParams(this.configuration.parameters);
|
|
2010
|
-
return `${this.serverUrl}
|
|
2011
|
-
}
|
|
2012
|
-
get synced() {
|
|
2013
|
-
return this.isSynced;
|
|
2014
|
-
}
|
|
2015
|
-
set synced(state) {
|
|
2016
|
-
if (this.isSynced === state) {
|
|
2017
|
-
return;
|
|
2018
|
-
}
|
|
2019
|
-
this.isSynced = state;
|
|
2020
|
-
this.emit('synced', { state });
|
|
2021
|
-
this.emit('sync', { state });
|
|
2022
|
-
}
|
|
2023
|
-
get isAuthenticationRequired() {
|
|
2024
|
-
return !!this.configuration.token && !this.isAuthenticated;
|
|
2277
|
+
return `${this.serverUrl}${encodedParams.length === 0 ? '' : `?${encodedParams}`}`;
|
|
2025
2278
|
}
|
|
2026
2279
|
disconnect() {
|
|
2027
2280
|
this.shouldConnect = false;
|
|
2028
|
-
this.disconnectBroadcastChannel();
|
|
2029
2281
|
if (this.webSocket === null) {
|
|
2030
2282
|
return;
|
|
2031
2283
|
}
|
|
@@ -2036,58 +2288,15 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
2036
2288
|
//
|
|
2037
2289
|
}
|
|
2038
2290
|
}
|
|
2039
|
-
|
|
2040
|
-
this.emit('open', { event });
|
|
2041
|
-
if (this.isAuthenticationRequired) {
|
|
2042
|
-
this.send(AuthenticationMessage, {
|
|
2043
|
-
token: await this.getToken(),
|
|
2044
|
-
});
|
|
2045
|
-
return;
|
|
2046
|
-
}
|
|
2047
|
-
this.startSync();
|
|
2048
|
-
}
|
|
2049
|
-
async getToken() {
|
|
2050
|
-
if (typeof this.configuration.token === 'function') {
|
|
2051
|
-
const token = await this.configuration.token();
|
|
2052
|
-
return token;
|
|
2053
|
-
}
|
|
2054
|
-
return this.configuration.token;
|
|
2055
|
-
}
|
|
2056
|
-
startSync() {
|
|
2057
|
-
this.send(SyncStepOneMessage, { document: this.document });
|
|
2058
|
-
if (this.awareness.getLocalState() !== null) {
|
|
2059
|
-
this.send(AwarenessMessage, {
|
|
2060
|
-
awareness: this.awareness,
|
|
2061
|
-
clients: [this.document.clientID],
|
|
2062
|
-
});
|
|
2063
|
-
}
|
|
2064
|
-
}
|
|
2065
|
-
send(Message, args, broadcast = false) {
|
|
2291
|
+
send(message) {
|
|
2066
2292
|
var _a;
|
|
2067
|
-
if (broadcast) {
|
|
2068
|
-
this.mux(() => { this.broadcast(Message, args); });
|
|
2069
|
-
}
|
|
2070
2293
|
if (((_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.readyState) === WsReadyStates.Open) {
|
|
2071
|
-
|
|
2072
|
-
this.emit('outgoingMessage', { message: messageSender.message });
|
|
2073
|
-
messageSender.send(this.webSocket);
|
|
2294
|
+
this.webSocket.send(message);
|
|
2074
2295
|
}
|
|
2075
2296
|
}
|
|
2076
|
-
|
|
2077
|
-
this.resolveConnectionAttempt();
|
|
2078
|
-
this.lastMessageReceived = getUnixTime();
|
|
2079
|
-
const message = new IncomingMessage(event.data);
|
|
2080
|
-
this.emit('message', { event, message });
|
|
2081
|
-
new MessageReceiver(message).apply(this);
|
|
2082
|
-
}
|
|
2083
|
-
onClose(event) {
|
|
2084
|
-
this.emit('close', { event });
|
|
2297
|
+
onClose({ event }) {
|
|
2085
2298
|
this.webSocket = null;
|
|
2086
|
-
this.isAuthenticated = false;
|
|
2087
|
-
this.synced = false;
|
|
2088
2299
|
if (this.status === WebSocketStatus.Connected) {
|
|
2089
|
-
// update awareness (all users except local left)
|
|
2090
|
-
removeAwarenessStates(this.awareness, Array.from(this.awareness.getStates().keys()).filter(client => client !== this.document.clientID), this);
|
|
2091
2300
|
this.status = WebSocketStatus.Disconnected;
|
|
2092
2301
|
this.emit('status', { status: WebSocketStatus.Disconnected });
|
|
2093
2302
|
this.emit('disconnect', { event });
|
|
@@ -2101,6 +2310,7 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
2101
2310
|
if (event.code === Forbidden.code) {
|
|
2102
2311
|
if (!this.configuration.quiet) {
|
|
2103
2312
|
console.warn('[HocuspocusProvider] The provided authentication token isn’t allowed to connect to this server. Will try again.');
|
|
2313
|
+
return; // TODO REMOVE ME
|
|
2104
2314
|
}
|
|
2105
2315
|
}
|
|
2106
2316
|
if (this.connectionAttempt) {
|
|
@@ -2130,67 +2340,16 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
2130
2340
|
clearInterval(this.intervals.forceSync);
|
|
2131
2341
|
}
|
|
2132
2342
|
clearInterval(this.intervals.connectionChecker);
|
|
2133
|
-
removeAwarenessStates(this.awareness, [this.document.clientID], 'provider destroy');
|
|
2134
2343
|
// If there is still a connection attempt outstanding then we should stop
|
|
2135
2344
|
// it before calling disconnect, otherwise it will be rejected in the onClose
|
|
2136
2345
|
// handler and trigger a retry
|
|
2137
2346
|
this.stopConnectionAttempt();
|
|
2138
2347
|
this.disconnect();
|
|
2139
|
-
this.awareness.off('update', this.awarenessUpdateHandler);
|
|
2140
|
-
this.document.off('update', this.documentUpdateHandler);
|
|
2141
2348
|
this.removeAllListeners();
|
|
2142
2349
|
if (typeof window === 'undefined') {
|
|
2143
2350
|
return;
|
|
2144
2351
|
}
|
|
2145
2352
|
window.removeEventListener('online', this.boundConnect);
|
|
2146
|
-
window.removeEventListener('beforeunload', this.boundBeforeUnload);
|
|
2147
|
-
}
|
|
2148
|
-
get broadcastChannel() {
|
|
2149
|
-
return `${this.serverUrl}/${this.configuration.name}`;
|
|
2150
|
-
}
|
|
2151
|
-
broadcastChannelSubscriber(data) {
|
|
2152
|
-
this.mux(() => {
|
|
2153
|
-
const message = new IncomingMessage(data);
|
|
2154
|
-
new MessageReceiver(message)
|
|
2155
|
-
.setBroadcasted(true)
|
|
2156
|
-
.apply(this, false);
|
|
2157
|
-
});
|
|
2158
|
-
}
|
|
2159
|
-
subscribeToBroadcastChannel() {
|
|
2160
|
-
if (!this.subscribedToBroadcastChannel) {
|
|
2161
|
-
subscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber);
|
|
2162
|
-
this.subscribedToBroadcastChannel = true;
|
|
2163
|
-
}
|
|
2164
|
-
this.mux(() => {
|
|
2165
|
-
this.broadcast(SyncStepOneMessage, { document: this.document });
|
|
2166
|
-
this.broadcast(SyncStepTwoMessage, { document: this.document });
|
|
2167
|
-
this.broadcast(QueryAwarenessMessage);
|
|
2168
|
-
this.broadcast(AwarenessMessage, { awareness: this.awareness, clients: [this.document.clientID] });
|
|
2169
|
-
});
|
|
2170
|
-
}
|
|
2171
|
-
disconnectBroadcastChannel() {
|
|
2172
|
-
// broadcast message with local awareness state set to null (indicating disconnect)
|
|
2173
|
-
this.send(AwarenessMessage, {
|
|
2174
|
-
awareness: this.awareness,
|
|
2175
|
-
clients: [this.document.clientID],
|
|
2176
|
-
states: new Map(),
|
|
2177
|
-
}, true);
|
|
2178
|
-
if (this.subscribedToBroadcastChannel) {
|
|
2179
|
-
unsubscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber);
|
|
2180
|
-
this.subscribedToBroadcastChannel = false;
|
|
2181
|
-
}
|
|
2182
|
-
}
|
|
2183
|
-
broadcast(Message, args) {
|
|
2184
|
-
if (!this.configuration.broadcast) {
|
|
2185
|
-
return;
|
|
2186
|
-
}
|
|
2187
|
-
if (!this.subscribedToBroadcastChannel) {
|
|
2188
|
-
return;
|
|
2189
|
-
}
|
|
2190
|
-
new MessageSender(Message, args).broadcast(this.broadcastChannel);
|
|
2191
|
-
}
|
|
2192
|
-
setAwarenessField(key, value) {
|
|
2193
|
-
this.awareness.setLocalStateField(key, value);
|
|
2194
2353
|
}
|
|
2195
2354
|
}
|
|
2196
2355
|
|
|
@@ -2205,9 +2364,10 @@ class HocuspocusCloudProvider extends HocuspocusProvider {
|
|
|
2205
2364
|
}
|
|
2206
2365
|
configuration.parameters.key = configuration.key;
|
|
2207
2366
|
}
|
|
2367
|
+
configuration.websocketProvider = new HocuspocusProviderWebsocket({ url: configuration.url });
|
|
2208
2368
|
super(configuration);
|
|
2209
2369
|
}
|
|
2210
2370
|
}
|
|
2211
2371
|
|
|
2212
|
-
export { HocuspocusCloudProvider, HocuspocusProvider, MessageType, WebSocketStatus };
|
|
2372
|
+
export { HocuspocusCloudProvider, HocuspocusProvider, HocuspocusProviderWebsocket, MessageType, WebSocketStatus };
|
|
2213
2373
|
//# sourceMappingURL=hocuspocus-provider.esm.js.map
|