@hocuspocus/provider 2.0.0-alpha.1 → 2.0.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 +427 -421
- package/dist/hocuspocus-provider.cjs.map +1 -1
- package/dist/hocuspocus-provider.esm.js +428 -422
- package/dist/hocuspocus-provider.esm.js.map +1 -1
- package/dist/packages/extension-monitor/src/Dashboard.d.ts +1 -0
- package/dist/packages/extension-redis/src/Redis.d.ts +1 -1
- package/dist/packages/extension-webhook/src/index.d.ts +1 -2
- package/dist/packages/provider/src/HocuspocusCloudProvider.d.ts +1 -1
- package/dist/packages/provider/src/HocuspocusProvider.d.ts +3 -2
- package/dist/packages/provider/src/HocuspocusProviderWebsocket.d.ts +1 -1
- package/dist/packages/provider/src/TiptapCollabProvider.d.ts +11 -0
- package/dist/packages/provider/src/index.d.ts +1 -1
- package/dist/packages/provider/src/types.d.ts +13 -13
- package/dist/packages/server/src/Connection.d.ts +2 -1
- package/dist/packages/server/src/Hocuspocus.d.ts +1 -0
- package/dist/packages/server/src/types.d.ts +5 -3
- package/dist/tests/server/onClose.d.ts +1 -0
- package/dist/tests/utils/newHocuspocus.d.ts +1 -1
- package/package.json +2 -2
- package/src/HocuspocusProvider.ts +18 -3
- package/src/HocuspocusProviderWebsocket.ts +3 -1
- package/src/TiptapCollabProvider.ts +33 -0
- package/src/index.ts +1 -1
|
@@ -1766,151 +1766,477 @@ class UpdateMessage extends OutgoingMessage {
|
|
|
1766
1766
|
}
|
|
1767
1767
|
}
|
|
1768
1768
|
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
}
|
|
1775
|
-
get(args) {
|
|
1776
|
-
var _a;
|
|
1777
|
-
writeVarString(this.encoder, args.documentName);
|
|
1778
|
-
writeVarUint(this.encoder, this.type);
|
|
1779
|
-
writeVarString(this.encoder, (_a = args.payload) !== null && _a !== void 0 ? _a : '');
|
|
1780
|
-
return this.encoder;
|
|
1781
|
-
}
|
|
1782
|
-
}
|
|
1769
|
+
/**
|
|
1770
|
+
* Utility module to work with urls.
|
|
1771
|
+
*
|
|
1772
|
+
* @module url
|
|
1773
|
+
*/
|
|
1783
1774
|
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
get(args) {
|
|
1791
|
-
writeVarString(this.encoder, args.documentName);
|
|
1792
|
-
writeVarUint(this.encoder, this.type);
|
|
1793
|
-
return this.encoder;
|
|
1794
|
-
}
|
|
1795
|
-
}
|
|
1775
|
+
/**
|
|
1776
|
+
* @param {Object<string,string>} params
|
|
1777
|
+
* @return {string}
|
|
1778
|
+
*/
|
|
1779
|
+
const encodeQueryParams = params =>
|
|
1780
|
+
map(params, (val, key) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`).join('&');
|
|
1796
1781
|
|
|
1797
|
-
class
|
|
1782
|
+
class HocuspocusProviderWebsocket extends EventEmitter {
|
|
1798
1783
|
constructor(configuration) {
|
|
1799
1784
|
super();
|
|
1800
1785
|
this.configuration = {
|
|
1801
|
-
|
|
1786
|
+
url: '',
|
|
1802
1787
|
// @ts-ignore
|
|
1803
1788
|
document: undefined,
|
|
1804
1789
|
// @ts-ignore
|
|
1805
1790
|
awareness: undefined,
|
|
1806
|
-
|
|
1791
|
+
WebSocketPolyfill: undefined,
|
|
1807
1792
|
parameters: {},
|
|
1793
|
+
connect: true,
|
|
1808
1794
|
broadcast: true,
|
|
1809
1795
|
forceSyncInterval: false,
|
|
1810
|
-
|
|
1811
|
-
|
|
1796
|
+
// TODO: this should depend on awareness.outdatedTime
|
|
1797
|
+
messageReconnectTimeout: 30000,
|
|
1798
|
+
// 1 second
|
|
1799
|
+
delay: 1000,
|
|
1800
|
+
// instant
|
|
1801
|
+
initialDelay: 0,
|
|
1802
|
+
// double the delay each time
|
|
1803
|
+
factor: 2,
|
|
1804
|
+
// unlimited retries
|
|
1805
|
+
maxAttempts: 0,
|
|
1806
|
+
// wait at least 1 second
|
|
1807
|
+
minDelay: 1000,
|
|
1808
|
+
// at least every 30 seconds
|
|
1809
|
+
maxDelay: 30000,
|
|
1810
|
+
// randomize
|
|
1811
|
+
jitter: true,
|
|
1812
|
+
// retry forever
|
|
1813
|
+
timeout: 0,
|
|
1812
1814
|
onOpen: () => null,
|
|
1813
1815
|
onConnect: () => null,
|
|
1814
1816
|
onMessage: () => null,
|
|
1815
1817
|
onOutgoingMessage: () => null,
|
|
1816
1818
|
onStatus: () => null,
|
|
1817
|
-
onSynced: () => null,
|
|
1818
1819
|
onDisconnect: () => null,
|
|
1819
1820
|
onClose: () => null,
|
|
1820
1821
|
onDestroy: () => null,
|
|
1821
1822
|
onAwarenessUpdate: () => null,
|
|
1822
1823
|
onAwarenessChange: () => null,
|
|
1823
|
-
onStateless: () => null,
|
|
1824
1824
|
quiet: false,
|
|
1825
1825
|
};
|
|
1826
1826
|
this.subscribedToBroadcastChannel = false;
|
|
1827
|
-
this.
|
|
1828
|
-
this.
|
|
1827
|
+
this.webSocket = null;
|
|
1828
|
+
this.shouldConnect = true;
|
|
1829
1829
|
this.status = exports.WebSocketStatus.Disconnected;
|
|
1830
|
-
this.
|
|
1830
|
+
this.lastMessageReceived = 0;
|
|
1831
1831
|
this.mux = createMutex();
|
|
1832
1832
|
this.intervals = {
|
|
1833
1833
|
forceSync: null,
|
|
1834
|
+
connectionChecker: null,
|
|
1834
1835
|
};
|
|
1835
|
-
this.
|
|
1836
|
-
this.
|
|
1836
|
+
this.connectionAttempt = null;
|
|
1837
|
+
this.receivedOnOpenPayload = undefined;
|
|
1838
|
+
this.receivedOnStatusPayload = undefined;
|
|
1839
|
+
this.boundConnect = this.connect.bind(this);
|
|
1837
1840
|
this.setConfiguration(configuration);
|
|
1838
|
-
this.configuration.
|
|
1839
|
-
this.configuration.awareness = configuration.awareness ? configuration.awareness : new Awareness(this.document);
|
|
1841
|
+
this.configuration.WebSocketPolyfill = configuration.WebSocketPolyfill ? configuration.WebSocketPolyfill : WebSocket;
|
|
1840
1842
|
this.on('open', this.configuration.onOpen);
|
|
1843
|
+
this.on('open', this.onOpen.bind(this));
|
|
1844
|
+
this.on('connect', this.configuration.onConnect);
|
|
1841
1845
|
this.on('message', this.configuration.onMessage);
|
|
1842
1846
|
this.on('outgoingMessage', this.configuration.onOutgoingMessage);
|
|
1843
|
-
this.on('
|
|
1847
|
+
this.on('status', this.configuration.onStatus);
|
|
1848
|
+
this.on('status', this.onStatus.bind(this));
|
|
1849
|
+
this.on('disconnect', this.configuration.onDisconnect);
|
|
1850
|
+
this.on('close', this.configuration.onClose);
|
|
1844
1851
|
this.on('destroy', this.configuration.onDestroy);
|
|
1845
1852
|
this.on('awarenessUpdate', this.configuration.onAwarenessUpdate);
|
|
1846
1853
|
this.on('awarenessChange', this.configuration.onAwarenessChange);
|
|
1847
|
-
this.on('
|
|
1848
|
-
this.on('
|
|
1849
|
-
this.on('authenticationFailed', this.configuration.onAuthenticationFailed);
|
|
1850
|
-
this.configuration.websocketProvider.on('connect', this.configuration.onConnect);
|
|
1851
|
-
this.configuration.websocketProvider.on('connect', (e) => this.emit('connect', e));
|
|
1852
|
-
this.configuration.websocketProvider.on('open', this.onOpen.bind(this));
|
|
1853
|
-
this.configuration.websocketProvider.on('open', (e) => this.emit('open', e));
|
|
1854
|
-
this.configuration.websocketProvider.on('message', this.onMessage.bind(this));
|
|
1855
|
-
this.configuration.websocketProvider.on('close', this.onClose.bind(this));
|
|
1856
|
-
this.configuration.websocketProvider.on('close', this.configuration.onClose);
|
|
1857
|
-
this.configuration.websocketProvider.on('close', (e) => this.emit('close', e));
|
|
1858
|
-
this.configuration.websocketProvider.on('status', this.onStatus.bind(this));
|
|
1859
|
-
this.configuration.websocketProvider.on('disconnect', this.configuration.onDisconnect);
|
|
1860
|
-
this.configuration.websocketProvider.on('disconnect', (e) => this.emit('disconnect', e));
|
|
1861
|
-
this.configuration.websocketProvider.on('destroy', this.configuration.onDestroy);
|
|
1862
|
-
this.configuration.websocketProvider.on('destroy', (e) => this.emit('destroy', e));
|
|
1863
|
-
this.awareness.on('update', () => {
|
|
1864
|
-
this.emit('awarenessUpdate', { states: common.awarenessStatesToArray(this.awareness.getStates()) });
|
|
1865
|
-
});
|
|
1866
|
-
this.awareness.on('change', () => {
|
|
1867
|
-
this.emit('awarenessChange', { states: common.awarenessStatesToArray(this.awareness.getStates()) });
|
|
1868
|
-
});
|
|
1869
|
-
this.document.on('update', this.documentUpdateHandler.bind(this));
|
|
1870
|
-
this.awareness.on('update', this.awarenessUpdateHandler.bind(this));
|
|
1854
|
+
this.on('close', this.onClose.bind(this));
|
|
1855
|
+
this.on('message', this.onMessage.bind(this));
|
|
1871
1856
|
this.registerEventListeners();
|
|
1872
|
-
|
|
1873
|
-
|
|
1857
|
+
this.intervals.connectionChecker = setInterval(this.checkConnection.bind(this), this.configuration.messageReconnectTimeout / 10);
|
|
1858
|
+
if (typeof configuration.connect !== 'undefined') {
|
|
1859
|
+
this.shouldConnect = configuration.connect;
|
|
1874
1860
|
}
|
|
1875
|
-
this.
|
|
1861
|
+
if (!this.shouldConnect) {
|
|
1862
|
+
return;
|
|
1863
|
+
}
|
|
1864
|
+
this.connect();
|
|
1876
1865
|
}
|
|
1877
|
-
|
|
1878
|
-
this.
|
|
1879
|
-
|
|
1880
|
-
|
|
1866
|
+
async onOpen(event) {
|
|
1867
|
+
this.receivedOnOpenPayload = event;
|
|
1868
|
+
}
|
|
1869
|
+
async onStatus(data) {
|
|
1870
|
+
this.receivedOnStatusPayload = data;
|
|
1871
|
+
}
|
|
1872
|
+
attach(provider) {
|
|
1873
|
+
if (this.receivedOnOpenPayload) {
|
|
1874
|
+
provider.onOpen(this.receivedOnOpenPayload);
|
|
1875
|
+
}
|
|
1876
|
+
if (this.receivedOnStatusPayload) {
|
|
1877
|
+
provider.onStatus(this.receivedOnStatusPayload);
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
detach(provider) {
|
|
1881
|
+
// tell the server to remove the listener
|
|
1881
1882
|
}
|
|
1882
1883
|
setConfiguration(configuration = {}) {
|
|
1883
1884
|
this.configuration = { ...this.configuration, ...configuration };
|
|
1884
1885
|
}
|
|
1885
|
-
|
|
1886
|
-
|
|
1886
|
+
async connect() {
|
|
1887
|
+
if (this.status === exports.WebSocketStatus.Connected) {
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1890
|
+
// Always cancel any previously initiated connection retryer instances
|
|
1891
|
+
if (this.cancelWebsocketRetry) {
|
|
1892
|
+
this.cancelWebsocketRetry();
|
|
1893
|
+
this.cancelWebsocketRetry = undefined;
|
|
1894
|
+
}
|
|
1895
|
+
this.shouldConnect = true;
|
|
1896
|
+
const abortableRetry = () => {
|
|
1897
|
+
let cancelAttempt = false;
|
|
1898
|
+
const retryPromise = attempt.retry(this.createWebSocketConnection.bind(this), {
|
|
1899
|
+
delay: this.configuration.delay,
|
|
1900
|
+
initialDelay: this.configuration.initialDelay,
|
|
1901
|
+
factor: this.configuration.factor,
|
|
1902
|
+
maxAttempts: this.configuration.maxAttempts,
|
|
1903
|
+
minDelay: this.configuration.minDelay,
|
|
1904
|
+
maxDelay: this.configuration.maxDelay,
|
|
1905
|
+
jitter: this.configuration.jitter,
|
|
1906
|
+
timeout: this.configuration.timeout,
|
|
1907
|
+
beforeAttempt: context => {
|
|
1908
|
+
if (!this.shouldConnect || cancelAttempt) {
|
|
1909
|
+
context.abort();
|
|
1910
|
+
}
|
|
1911
|
+
},
|
|
1912
|
+
}).catch((error) => {
|
|
1913
|
+
// If we aborted the connection attempt then don’t throw an error
|
|
1914
|
+
// ref: https://github.com/lifeomic/attempt/blob/master/src/index.ts#L136
|
|
1915
|
+
if (error && error.code !== 'ATTEMPT_ABORTED') {
|
|
1916
|
+
throw error;
|
|
1917
|
+
}
|
|
1918
|
+
});
|
|
1919
|
+
return {
|
|
1920
|
+
retryPromise,
|
|
1921
|
+
cancelFunc: () => {
|
|
1922
|
+
cancelAttempt = true;
|
|
1923
|
+
},
|
|
1924
|
+
};
|
|
1925
|
+
};
|
|
1926
|
+
const { retryPromise, cancelFunc } = abortableRetry();
|
|
1927
|
+
this.cancelWebsocketRetry = cancelFunc;
|
|
1928
|
+
return retryPromise;
|
|
1887
1929
|
}
|
|
1888
|
-
|
|
1889
|
-
return
|
|
1930
|
+
createWebSocketConnection() {
|
|
1931
|
+
return new Promise((resolve, reject) => {
|
|
1932
|
+
if (this.webSocket) {
|
|
1933
|
+
this.webSocket.close();
|
|
1934
|
+
this.webSocket = null;
|
|
1935
|
+
}
|
|
1936
|
+
// Init the WebSocket connection
|
|
1937
|
+
const ws = new this.configuration.WebSocketPolyfill(this.url);
|
|
1938
|
+
ws.binaryType = 'arraybuffer';
|
|
1939
|
+
ws.onmessage = (payload) => this.emit('message', payload);
|
|
1940
|
+
ws.onclose = (payload) => this.emit('close', { event: payload });
|
|
1941
|
+
ws.onopen = (payload) => this.emit('open', payload);
|
|
1942
|
+
ws.onerror = (err) => {
|
|
1943
|
+
reject(err);
|
|
1944
|
+
};
|
|
1945
|
+
this.webSocket = ws;
|
|
1946
|
+
// Reset the status
|
|
1947
|
+
this.status = exports.WebSocketStatus.Connecting;
|
|
1948
|
+
this.emit('status', { status: exports.WebSocketStatus.Connecting });
|
|
1949
|
+
// Store resolve/reject for later use
|
|
1950
|
+
this.connectionAttempt = {
|
|
1951
|
+
resolve,
|
|
1952
|
+
reject,
|
|
1953
|
+
};
|
|
1954
|
+
});
|
|
1890
1955
|
}
|
|
1891
|
-
|
|
1892
|
-
|
|
1956
|
+
onMessage(event) {
|
|
1957
|
+
this.resolveConnectionAttempt();
|
|
1893
1958
|
}
|
|
1894
|
-
|
|
1895
|
-
this.
|
|
1959
|
+
resolveConnectionAttempt() {
|
|
1960
|
+
if (this.connectionAttempt) {
|
|
1961
|
+
this.connectionAttempt.resolve();
|
|
1962
|
+
this.connectionAttempt = null;
|
|
1963
|
+
this.status = exports.WebSocketStatus.Connected;
|
|
1964
|
+
this.emit('status', { status: exports.WebSocketStatus.Connected });
|
|
1965
|
+
this.emit('connect');
|
|
1966
|
+
}
|
|
1896
1967
|
}
|
|
1897
|
-
|
|
1898
|
-
|
|
1968
|
+
stopConnectionAttempt() {
|
|
1969
|
+
this.connectionAttempt = null;
|
|
1899
1970
|
}
|
|
1900
|
-
|
|
1901
|
-
|
|
1971
|
+
rejectConnectionAttempt() {
|
|
1972
|
+
var _a;
|
|
1973
|
+
(_a = this.connectionAttempt) === null || _a === void 0 ? void 0 : _a.reject();
|
|
1974
|
+
this.connectionAttempt = null;
|
|
1975
|
+
}
|
|
1976
|
+
checkConnection() {
|
|
1977
|
+
var _a;
|
|
1978
|
+
// Don’t check the connection when it’s not even established
|
|
1979
|
+
if (this.status !== exports.WebSocketStatus.Connected) {
|
|
1902
1980
|
return;
|
|
1903
1981
|
}
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
sendStateless(payload) {
|
|
1907
|
-
this.send(StatelessMessage, { documentName: this.configuration.name, payload });
|
|
1908
|
-
}
|
|
1909
|
-
documentUpdateHandler(update, origin) {
|
|
1910
|
-
if (origin === this) {
|
|
1982
|
+
// Don’t close then connection while waiting for the first message
|
|
1983
|
+
if (!this.lastMessageReceived) {
|
|
1911
1984
|
return;
|
|
1912
1985
|
}
|
|
1913
|
-
|
|
1986
|
+
// Don’t close the connection when a message was received recently
|
|
1987
|
+
if (this.configuration.messageReconnectTimeout >= getUnixTime() - this.lastMessageReceived) {
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1990
|
+
// No message received in a long time, not even your own
|
|
1991
|
+
// Awareness updates, which are updated every 15 seconds.
|
|
1992
|
+
(_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.close();
|
|
1993
|
+
}
|
|
1994
|
+
registerEventListeners() {
|
|
1995
|
+
if (typeof window === 'undefined') {
|
|
1996
|
+
return;
|
|
1997
|
+
}
|
|
1998
|
+
window.addEventListener('online', this.boundConnect);
|
|
1999
|
+
}
|
|
2000
|
+
// Ensure that the URL always ends with /
|
|
2001
|
+
get serverUrl() {
|
|
2002
|
+
while (this.configuration.url[this.configuration.url.length - 1] === '/') {
|
|
2003
|
+
return this.configuration.url.slice(0, this.configuration.url.length - 1);
|
|
2004
|
+
}
|
|
2005
|
+
return this.configuration.url;
|
|
2006
|
+
}
|
|
2007
|
+
get url() {
|
|
2008
|
+
const encodedParams = encodeQueryParams(this.configuration.parameters);
|
|
2009
|
+
return `${this.serverUrl}${encodedParams.length === 0 ? '' : `?${encodedParams}`}`;
|
|
2010
|
+
}
|
|
2011
|
+
disconnect() {
|
|
2012
|
+
this.shouldConnect = false;
|
|
2013
|
+
if (this.webSocket === null) {
|
|
2014
|
+
return;
|
|
2015
|
+
}
|
|
2016
|
+
try {
|
|
2017
|
+
this.webSocket.close();
|
|
2018
|
+
}
|
|
2019
|
+
catch {
|
|
2020
|
+
//
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
send(message) {
|
|
2024
|
+
var _a;
|
|
2025
|
+
if (((_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.readyState) === common.WsReadyStates.Open) {
|
|
2026
|
+
this.webSocket.send(message);
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
onClose({ event }) {
|
|
2030
|
+
this.webSocket = null;
|
|
2031
|
+
if (this.status === exports.WebSocketStatus.Connected) {
|
|
2032
|
+
this.status = exports.WebSocketStatus.Disconnected;
|
|
2033
|
+
this.emit('status', { status: exports.WebSocketStatus.Disconnected });
|
|
2034
|
+
this.emit('disconnect', { event });
|
|
2035
|
+
}
|
|
2036
|
+
if (event.code === common.Unauthorized.code) {
|
|
2037
|
+
if (event.reason === common.Unauthorized.reason) {
|
|
2038
|
+
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.');
|
|
2039
|
+
}
|
|
2040
|
+
else {
|
|
2041
|
+
console.warn(`[HocuspocusProvider] Connection closed with status Unauthorized: ${event.reason}`);
|
|
2042
|
+
}
|
|
2043
|
+
this.shouldConnect = false;
|
|
2044
|
+
}
|
|
2045
|
+
if (event.code === common.Forbidden.code) {
|
|
2046
|
+
if (!this.configuration.quiet) {
|
|
2047
|
+
console.warn('[HocuspocusProvider] The provided authentication token isn’t allowed to connect to this server. Will try again.');
|
|
2048
|
+
return; // TODO REMOVE ME
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
if (this.connectionAttempt) {
|
|
2052
|
+
// That connection attempt failed.
|
|
2053
|
+
this.rejectConnectionAttempt();
|
|
2054
|
+
}
|
|
2055
|
+
else if (this.shouldConnect) {
|
|
2056
|
+
// The connection was closed by the server. Let’s just try again.
|
|
2057
|
+
this.connect();
|
|
2058
|
+
}
|
|
2059
|
+
// If we’ll reconnect, we’re done for now.
|
|
2060
|
+
if (this.shouldConnect) {
|
|
2061
|
+
return;
|
|
2062
|
+
}
|
|
2063
|
+
// The status is set correctly already.
|
|
2064
|
+
if (this.status === exports.WebSocketStatus.Disconnected) {
|
|
2065
|
+
return;
|
|
2066
|
+
}
|
|
2067
|
+
// Let’s update the connection status.
|
|
2068
|
+
this.status = exports.WebSocketStatus.Disconnected;
|
|
2069
|
+
this.emit('status', { status: exports.WebSocketStatus.Disconnected });
|
|
2070
|
+
this.emit('disconnect', { event });
|
|
2071
|
+
}
|
|
2072
|
+
destroy() {
|
|
2073
|
+
this.emit('destroy');
|
|
2074
|
+
if (this.intervals.forceSync) {
|
|
2075
|
+
clearInterval(this.intervals.forceSync);
|
|
2076
|
+
}
|
|
2077
|
+
clearInterval(this.intervals.connectionChecker);
|
|
2078
|
+
// If there is still a connection attempt outstanding then we should stop
|
|
2079
|
+
// it before calling disconnect, otherwise it will be rejected in the onClose
|
|
2080
|
+
// handler and trigger a retry
|
|
2081
|
+
this.stopConnectionAttempt();
|
|
2082
|
+
this.disconnect();
|
|
2083
|
+
this.removeAllListeners();
|
|
2084
|
+
if (typeof window === 'undefined') {
|
|
2085
|
+
return;
|
|
2086
|
+
}
|
|
2087
|
+
window.removeEventListener('online', this.boundConnect);
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
class StatelessMessage extends OutgoingMessage {
|
|
2092
|
+
constructor() {
|
|
2093
|
+
super(...arguments);
|
|
2094
|
+
this.type = exports.MessageType.Stateless;
|
|
2095
|
+
this.description = 'A stateless message';
|
|
2096
|
+
}
|
|
2097
|
+
get(args) {
|
|
2098
|
+
var _a;
|
|
2099
|
+
writeVarString(this.encoder, args.documentName);
|
|
2100
|
+
writeVarUint(this.encoder, this.type);
|
|
2101
|
+
writeVarString(this.encoder, (_a = args.payload) !== null && _a !== void 0 ? _a : '');
|
|
2102
|
+
return this.encoder;
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
class CloseMessage extends OutgoingMessage {
|
|
2107
|
+
constructor() {
|
|
2108
|
+
super(...arguments);
|
|
2109
|
+
this.type = exports.MessageType.CLOSE;
|
|
2110
|
+
this.description = 'Ask the server to close the connection';
|
|
2111
|
+
}
|
|
2112
|
+
get(args) {
|
|
2113
|
+
writeVarString(this.encoder, args.documentName);
|
|
2114
|
+
writeVarUint(this.encoder, this.type);
|
|
2115
|
+
return this.encoder;
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
class HocuspocusProvider extends EventEmitter {
|
|
2120
|
+
constructor(configuration) {
|
|
2121
|
+
super();
|
|
2122
|
+
this.configuration = {
|
|
2123
|
+
name: '',
|
|
2124
|
+
// @ts-ignore
|
|
2125
|
+
document: undefined,
|
|
2126
|
+
// @ts-ignore
|
|
2127
|
+
awareness: undefined,
|
|
2128
|
+
token: null,
|
|
2129
|
+
parameters: {},
|
|
2130
|
+
broadcast: true,
|
|
2131
|
+
forceSyncInterval: false,
|
|
2132
|
+
onAuthenticated: () => null,
|
|
2133
|
+
onAuthenticationFailed: () => null,
|
|
2134
|
+
onOpen: () => null,
|
|
2135
|
+
onConnect: () => null,
|
|
2136
|
+
onMessage: () => null,
|
|
2137
|
+
onOutgoingMessage: () => null,
|
|
2138
|
+
onStatus: () => null,
|
|
2139
|
+
onSynced: () => null,
|
|
2140
|
+
onDisconnect: () => null,
|
|
2141
|
+
onClose: () => null,
|
|
2142
|
+
onDestroy: () => null,
|
|
2143
|
+
onAwarenessUpdate: () => null,
|
|
2144
|
+
onAwarenessChange: () => null,
|
|
2145
|
+
onStateless: () => null,
|
|
2146
|
+
quiet: false,
|
|
2147
|
+
};
|
|
2148
|
+
this.subscribedToBroadcastChannel = false;
|
|
2149
|
+
this.isSynced = false;
|
|
2150
|
+
this.unsyncedChanges = 0;
|
|
2151
|
+
this.status = exports.WebSocketStatus.Disconnected;
|
|
2152
|
+
this.isAuthenticated = false;
|
|
2153
|
+
this.mux = createMutex();
|
|
2154
|
+
this.intervals = {
|
|
2155
|
+
forceSync: null,
|
|
2156
|
+
};
|
|
2157
|
+
this.isConnected = true;
|
|
2158
|
+
this.boundBeforeUnload = this.beforeUnload.bind(this);
|
|
2159
|
+
this.boundBroadcastChannelSubscriber = this.broadcastChannelSubscriber.bind(this);
|
|
2160
|
+
this.setConfiguration(configuration);
|
|
2161
|
+
this.configuration.document = configuration.document ? configuration.document : new Y__namespace.Doc();
|
|
2162
|
+
this.configuration.awareness = configuration.awareness ? configuration.awareness : new Awareness(this.document);
|
|
2163
|
+
this.on('open', this.configuration.onOpen);
|
|
2164
|
+
this.on('message', this.configuration.onMessage);
|
|
2165
|
+
this.on('outgoingMessage', this.configuration.onOutgoingMessage);
|
|
2166
|
+
this.on('synced', this.configuration.onSynced);
|
|
2167
|
+
this.on('destroy', this.configuration.onDestroy);
|
|
2168
|
+
this.on('awarenessUpdate', this.configuration.onAwarenessUpdate);
|
|
2169
|
+
this.on('awarenessChange', this.configuration.onAwarenessChange);
|
|
2170
|
+
this.on('stateless', this.configuration.onStateless);
|
|
2171
|
+
this.on('authenticated', this.configuration.onAuthenticated);
|
|
2172
|
+
this.on('authenticationFailed', this.configuration.onAuthenticationFailed);
|
|
2173
|
+
this.configuration.websocketProvider.on('connect', this.configuration.onConnect);
|
|
2174
|
+
this.configuration.websocketProvider.on('connect', (e) => this.emit('connect', e));
|
|
2175
|
+
this.configuration.websocketProvider.on('open', this.onOpen.bind(this));
|
|
2176
|
+
this.configuration.websocketProvider.on('open', (e) => this.emit('open', e));
|
|
2177
|
+
this.configuration.websocketProvider.on('message', this.onMessage.bind(this));
|
|
2178
|
+
this.configuration.websocketProvider.on('close', this.onClose.bind(this));
|
|
2179
|
+
this.configuration.websocketProvider.on('close', this.configuration.onClose);
|
|
2180
|
+
this.configuration.websocketProvider.on('close', (e) => this.emit('close', e));
|
|
2181
|
+
this.configuration.websocketProvider.on('status', this.onStatus.bind(this));
|
|
2182
|
+
this.configuration.websocketProvider.on('disconnect', this.configuration.onDisconnect);
|
|
2183
|
+
this.configuration.websocketProvider.on('disconnect', (e) => this.emit('disconnect', e));
|
|
2184
|
+
this.configuration.websocketProvider.on('destroy', this.configuration.onDestroy);
|
|
2185
|
+
this.configuration.websocketProvider.on('destroy', (e) => this.emit('destroy', e));
|
|
2186
|
+
this.awareness.on('update', () => {
|
|
2187
|
+
this.emit('awarenessUpdate', { states: common.awarenessStatesToArray(this.awareness.getStates()) });
|
|
2188
|
+
});
|
|
2189
|
+
this.awareness.on('change', () => {
|
|
2190
|
+
this.emit('awarenessChange', { states: common.awarenessStatesToArray(this.awareness.getStates()) });
|
|
2191
|
+
});
|
|
2192
|
+
this.document.on('update', this.documentUpdateHandler.bind(this));
|
|
2193
|
+
this.awareness.on('update', this.awarenessUpdateHandler.bind(this));
|
|
2194
|
+
this.registerEventListeners();
|
|
2195
|
+
if (this.configuration.forceSyncInterval) {
|
|
2196
|
+
this.intervals.forceSync = setInterval(this.forceSync.bind(this), this.configuration.forceSyncInterval);
|
|
2197
|
+
}
|
|
2198
|
+
this.configuration.websocketProvider.attach(this);
|
|
2199
|
+
}
|
|
2200
|
+
onStatus({ status }) {
|
|
2201
|
+
this.status = status;
|
|
2202
|
+
this.configuration.onStatus({ status });
|
|
2203
|
+
this.emit('status', { status });
|
|
2204
|
+
}
|
|
2205
|
+
setConfiguration(configuration = {}) {
|
|
2206
|
+
if (!configuration.websocketProvider && configuration.url) {
|
|
2207
|
+
this.configuration.websocketProvider = new HocuspocusProviderWebsocket({ url: configuration.url });
|
|
2208
|
+
}
|
|
2209
|
+
this.configuration = { ...this.configuration, ...configuration };
|
|
2210
|
+
}
|
|
2211
|
+
get document() {
|
|
2212
|
+
return this.configuration.document;
|
|
2213
|
+
}
|
|
2214
|
+
get awareness() {
|
|
2215
|
+
return this.configuration.awareness;
|
|
2216
|
+
}
|
|
2217
|
+
get hasUnsyncedChanges() {
|
|
2218
|
+
return this.unsyncedChanges > 0;
|
|
2219
|
+
}
|
|
2220
|
+
forceSync() {
|
|
2221
|
+
this.send(SyncStepOneMessage, { document: this.document, documentName: this.configuration.name });
|
|
2222
|
+
}
|
|
2223
|
+
beforeUnload() {
|
|
2224
|
+
removeAwarenessStates(this.awareness, [this.document.clientID], 'window unload');
|
|
2225
|
+
}
|
|
2226
|
+
registerEventListeners() {
|
|
2227
|
+
if (typeof window === 'undefined') {
|
|
2228
|
+
return;
|
|
2229
|
+
}
|
|
2230
|
+
window.addEventListener('beforeunload', this.boundBeforeUnload);
|
|
2231
|
+
}
|
|
2232
|
+
sendStateless(payload) {
|
|
2233
|
+
this.send(StatelessMessage, { documentName: this.configuration.name, payload });
|
|
2234
|
+
}
|
|
2235
|
+
documentUpdateHandler(update, origin) {
|
|
2236
|
+
if (origin === this) {
|
|
2237
|
+
return;
|
|
2238
|
+
}
|
|
2239
|
+
this.unsyncedChanges += 1;
|
|
1914
2240
|
this.send(UpdateMessage, { update, documentName: this.configuration.name }, true);
|
|
1915
2241
|
}
|
|
1916
2242
|
awarenessUpdateHandler({ added, updated, removed }, origin) {
|
|
@@ -1974,6 +2300,8 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1974
2300
|
}
|
|
1975
2301
|
}
|
|
1976
2302
|
send(message, args, broadcast = false) {
|
|
2303
|
+
if (!this.isConnected)
|
|
2304
|
+
return;
|
|
1977
2305
|
if (broadcast) {
|
|
1978
2306
|
this.mux(() => { this.broadcast(message, args); });
|
|
1979
2307
|
}
|
|
@@ -2008,6 +2336,7 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
2008
2336
|
this.document.off('update', this.documentUpdateHandler);
|
|
2009
2337
|
this.removeAllListeners();
|
|
2010
2338
|
this.send(CloseMessage, { documentName: this.configuration.name });
|
|
2339
|
+
this.isConnected = false;
|
|
2011
2340
|
if (typeof window === 'undefined') {
|
|
2012
2341
|
return;
|
|
2013
2342
|
}
|
|
@@ -2076,342 +2405,19 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
2076
2405
|
}
|
|
2077
2406
|
}
|
|
2078
2407
|
|
|
2079
|
-
|
|
2080
|
-
* Utility module to work with urls.
|
|
2081
|
-
*
|
|
2082
|
-
* @module url
|
|
2083
|
-
*/
|
|
2084
|
-
|
|
2085
|
-
/**
|
|
2086
|
-
* @param {Object<string,string>} params
|
|
2087
|
-
* @return {string}
|
|
2088
|
-
*/
|
|
2089
|
-
const encodeQueryParams = params =>
|
|
2090
|
-
map(params, (val, key) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`).join('&');
|
|
2091
|
-
|
|
2092
|
-
class HocuspocusProviderWebsocket extends EventEmitter {
|
|
2093
|
-
constructor(configuration) {
|
|
2094
|
-
super();
|
|
2095
|
-
this.configuration = {
|
|
2096
|
-
url: '',
|
|
2097
|
-
// @ts-ignore
|
|
2098
|
-
document: undefined,
|
|
2099
|
-
// @ts-ignore
|
|
2100
|
-
awareness: undefined,
|
|
2101
|
-
WebSocketPolyfill: undefined,
|
|
2102
|
-
parameters: {},
|
|
2103
|
-
connect: true,
|
|
2104
|
-
broadcast: true,
|
|
2105
|
-
forceSyncInterval: false,
|
|
2106
|
-
// TODO: this should depend on awareness.outdatedTime
|
|
2107
|
-
messageReconnectTimeout: 30000,
|
|
2108
|
-
// 1 second
|
|
2109
|
-
delay: 1000,
|
|
2110
|
-
// instant
|
|
2111
|
-
initialDelay: 0,
|
|
2112
|
-
// double the delay each time
|
|
2113
|
-
factor: 2,
|
|
2114
|
-
// unlimited retries
|
|
2115
|
-
maxAttempts: 0,
|
|
2116
|
-
// wait at least 1 second
|
|
2117
|
-
minDelay: 1000,
|
|
2118
|
-
// at least every 30 seconds
|
|
2119
|
-
maxDelay: 30000,
|
|
2120
|
-
// randomize
|
|
2121
|
-
jitter: true,
|
|
2122
|
-
// retry forever
|
|
2123
|
-
timeout: 0,
|
|
2124
|
-
onOpen: () => null,
|
|
2125
|
-
onConnect: () => null,
|
|
2126
|
-
onMessage: () => null,
|
|
2127
|
-
onOutgoingMessage: () => null,
|
|
2128
|
-
onStatus: () => null,
|
|
2129
|
-
onDisconnect: () => null,
|
|
2130
|
-
onClose: () => null,
|
|
2131
|
-
onDestroy: () => null,
|
|
2132
|
-
onAwarenessUpdate: () => null,
|
|
2133
|
-
onAwarenessChange: () => null,
|
|
2134
|
-
quiet: false,
|
|
2135
|
-
};
|
|
2136
|
-
this.subscribedToBroadcastChannel = false;
|
|
2137
|
-
this.webSocket = null;
|
|
2138
|
-
this.shouldConnect = true;
|
|
2139
|
-
this.status = exports.WebSocketStatus.Disconnected;
|
|
2140
|
-
this.lastMessageReceived = 0;
|
|
2141
|
-
this.mux = createMutex();
|
|
2142
|
-
this.intervals = {
|
|
2143
|
-
forceSync: null,
|
|
2144
|
-
connectionChecker: null,
|
|
2145
|
-
};
|
|
2146
|
-
this.connectionAttempt = null;
|
|
2147
|
-
this.receivedOnOpenPayload = undefined;
|
|
2148
|
-
this.receivedOnStatusPayload = undefined;
|
|
2149
|
-
this.boundConnect = this.connect.bind(this);
|
|
2150
|
-
this.setConfiguration(configuration);
|
|
2151
|
-
this.configuration.WebSocketPolyfill = configuration.WebSocketPolyfill ? configuration.WebSocketPolyfill : WebSocket;
|
|
2152
|
-
this.on('open', this.configuration.onOpen);
|
|
2153
|
-
this.on('open', this.onOpen.bind(this));
|
|
2154
|
-
this.on('connect', this.configuration.onConnect);
|
|
2155
|
-
this.on('message', this.configuration.onMessage);
|
|
2156
|
-
this.on('outgoingMessage', this.configuration.onOutgoingMessage);
|
|
2157
|
-
this.on('status', this.configuration.onStatus);
|
|
2158
|
-
this.on('status', this.onStatus.bind(this));
|
|
2159
|
-
this.on('disconnect', this.configuration.onDisconnect);
|
|
2160
|
-
this.on('close', this.configuration.onClose);
|
|
2161
|
-
this.on('destroy', this.configuration.onDestroy);
|
|
2162
|
-
this.on('awarenessUpdate', this.configuration.onAwarenessUpdate);
|
|
2163
|
-
this.on('awarenessChange', this.configuration.onAwarenessChange);
|
|
2164
|
-
this.on('close', this.onClose.bind(this));
|
|
2165
|
-
this.on('message', this.onMessage.bind(this));
|
|
2166
|
-
this.registerEventListeners();
|
|
2167
|
-
this.intervals.connectionChecker = setInterval(this.checkConnection.bind(this), this.configuration.messageReconnectTimeout / 10);
|
|
2168
|
-
if (typeof configuration.connect !== 'undefined') {
|
|
2169
|
-
this.shouldConnect = configuration.connect;
|
|
2170
|
-
}
|
|
2171
|
-
if (!this.shouldConnect) {
|
|
2172
|
-
return;
|
|
2173
|
-
}
|
|
2174
|
-
this.connect();
|
|
2175
|
-
}
|
|
2176
|
-
async onOpen(event) {
|
|
2177
|
-
this.receivedOnOpenPayload = event;
|
|
2178
|
-
}
|
|
2179
|
-
async onStatus(data) {
|
|
2180
|
-
this.receivedOnStatusPayload = data;
|
|
2181
|
-
}
|
|
2182
|
-
attach(provider) {
|
|
2183
|
-
if (this.receivedOnOpenPayload) {
|
|
2184
|
-
provider.onOpen(this.receivedOnOpenPayload);
|
|
2185
|
-
}
|
|
2186
|
-
if (this.receivedOnStatusPayload) {
|
|
2187
|
-
provider.onStatus(this.receivedOnStatusPayload);
|
|
2188
|
-
}
|
|
2189
|
-
}
|
|
2190
|
-
detach(provider) {
|
|
2191
|
-
// tell the server to remove the listener
|
|
2192
|
-
}
|
|
2193
|
-
setConfiguration(configuration = {}) {
|
|
2194
|
-
this.configuration = { ...this.configuration, ...configuration };
|
|
2195
|
-
}
|
|
2196
|
-
async connect() {
|
|
2197
|
-
if (this.status === exports.WebSocketStatus.Connected) {
|
|
2198
|
-
return;
|
|
2199
|
-
}
|
|
2200
|
-
// Always cancel any previously initiated connection retryer instances
|
|
2201
|
-
if (this.cancelWebsocketRetry) {
|
|
2202
|
-
this.cancelWebsocketRetry();
|
|
2203
|
-
this.cancelWebsocketRetry = undefined;
|
|
2204
|
-
}
|
|
2205
|
-
this.shouldConnect = true;
|
|
2206
|
-
const abortableRetry = () => {
|
|
2207
|
-
let cancelAttempt = false;
|
|
2208
|
-
const retryPromise = attempt.retry(this.createWebSocketConnection.bind(this), {
|
|
2209
|
-
delay: this.configuration.delay,
|
|
2210
|
-
initialDelay: this.configuration.initialDelay,
|
|
2211
|
-
factor: this.configuration.factor,
|
|
2212
|
-
maxAttempts: this.configuration.maxAttempts,
|
|
2213
|
-
minDelay: this.configuration.minDelay,
|
|
2214
|
-
maxDelay: this.configuration.maxDelay,
|
|
2215
|
-
jitter: this.configuration.jitter,
|
|
2216
|
-
timeout: this.configuration.timeout,
|
|
2217
|
-
beforeAttempt: context => {
|
|
2218
|
-
if (!this.shouldConnect || cancelAttempt) {
|
|
2219
|
-
context.abort();
|
|
2220
|
-
}
|
|
2221
|
-
},
|
|
2222
|
-
}).catch((error) => {
|
|
2223
|
-
// If we aborted the connection attempt then don’t throw an error
|
|
2224
|
-
// ref: https://github.com/lifeomic/attempt/blob/master/src/index.ts#L136
|
|
2225
|
-
if (error && error.code !== 'ATTEMPT_ABORTED') {
|
|
2226
|
-
throw error;
|
|
2227
|
-
}
|
|
2228
|
-
});
|
|
2229
|
-
return {
|
|
2230
|
-
retryPromise,
|
|
2231
|
-
cancelFunc: () => {
|
|
2232
|
-
cancelAttempt = true;
|
|
2233
|
-
},
|
|
2234
|
-
};
|
|
2235
|
-
};
|
|
2236
|
-
const { retryPromise, cancelFunc } = abortableRetry();
|
|
2237
|
-
this.cancelWebsocketRetry = cancelFunc;
|
|
2238
|
-
return retryPromise;
|
|
2239
|
-
}
|
|
2240
|
-
createWebSocketConnection() {
|
|
2241
|
-
return new Promise((resolve, reject) => {
|
|
2242
|
-
if (this.webSocket) {
|
|
2243
|
-
this.webSocket.close();
|
|
2244
|
-
this.webSocket = null;
|
|
2245
|
-
}
|
|
2246
|
-
// Init the WebSocket connection
|
|
2247
|
-
const ws = new this.configuration.WebSocketPolyfill(this.url);
|
|
2248
|
-
ws.binaryType = 'arraybuffer';
|
|
2249
|
-
ws.onmessage = (payload) => this.emit('message', payload);
|
|
2250
|
-
ws.onclose = (payload) => this.emit('close', { event: payload });
|
|
2251
|
-
ws.onopen = (payload) => this.emit('open', payload);
|
|
2252
|
-
ws.onerror = (err) => {
|
|
2253
|
-
reject(err);
|
|
2254
|
-
};
|
|
2255
|
-
this.webSocket = ws;
|
|
2256
|
-
// Reset the status
|
|
2257
|
-
this.status = exports.WebSocketStatus.Connecting;
|
|
2258
|
-
this.emit('status', { status: exports.WebSocketStatus.Connecting });
|
|
2259
|
-
// Store resolve/reject for later use
|
|
2260
|
-
this.connectionAttempt = {
|
|
2261
|
-
resolve,
|
|
2262
|
-
reject,
|
|
2263
|
-
};
|
|
2264
|
-
});
|
|
2265
|
-
}
|
|
2266
|
-
onMessage(event) {
|
|
2267
|
-
this.resolveConnectionAttempt();
|
|
2268
|
-
}
|
|
2269
|
-
resolveConnectionAttempt() {
|
|
2270
|
-
if (this.connectionAttempt) {
|
|
2271
|
-
this.connectionAttempt.resolve();
|
|
2272
|
-
this.connectionAttempt = null;
|
|
2273
|
-
this.status = exports.WebSocketStatus.Connected;
|
|
2274
|
-
this.emit('status', { status: exports.WebSocketStatus.Connected });
|
|
2275
|
-
this.emit('connect');
|
|
2276
|
-
}
|
|
2277
|
-
}
|
|
2278
|
-
stopConnectionAttempt() {
|
|
2279
|
-
this.connectionAttempt = null;
|
|
2280
|
-
}
|
|
2281
|
-
rejectConnectionAttempt() {
|
|
2282
|
-
var _a;
|
|
2283
|
-
(_a = this.connectionAttempt) === null || _a === void 0 ? void 0 : _a.reject();
|
|
2284
|
-
this.connectionAttempt = null;
|
|
2285
|
-
}
|
|
2286
|
-
checkConnection() {
|
|
2287
|
-
var _a;
|
|
2288
|
-
// Don’t check the connection when it’s not even established
|
|
2289
|
-
if (this.status !== exports.WebSocketStatus.Connected) {
|
|
2290
|
-
return;
|
|
2291
|
-
}
|
|
2292
|
-
// Don’t close then connection while waiting for the first message
|
|
2293
|
-
if (!this.lastMessageReceived) {
|
|
2294
|
-
return;
|
|
2295
|
-
}
|
|
2296
|
-
// Don’t close the connection when a message was received recently
|
|
2297
|
-
if (this.configuration.messageReconnectTimeout >= getUnixTime() - this.lastMessageReceived) {
|
|
2298
|
-
return;
|
|
2299
|
-
}
|
|
2300
|
-
// No message received in a long time, not even your own
|
|
2301
|
-
// Awareness updates, which are updated every 15 seconds.
|
|
2302
|
-
(_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.close();
|
|
2303
|
-
}
|
|
2304
|
-
registerEventListeners() {
|
|
2305
|
-
if (typeof window === 'undefined') {
|
|
2306
|
-
return;
|
|
2307
|
-
}
|
|
2308
|
-
window.addEventListener('online', this.boundConnect);
|
|
2309
|
-
}
|
|
2310
|
-
// Ensure that the URL always ends with /
|
|
2311
|
-
get serverUrl() {
|
|
2312
|
-
while (this.configuration.url[this.configuration.url.length - 1] === '/') {
|
|
2313
|
-
return this.configuration.url.slice(0, this.configuration.url.length - 1);
|
|
2314
|
-
}
|
|
2315
|
-
return this.configuration.url;
|
|
2316
|
-
}
|
|
2317
|
-
get url() {
|
|
2318
|
-
const encodedParams = encodeQueryParams(this.configuration.parameters);
|
|
2319
|
-
return `${this.serverUrl}${encodedParams.length === 0 ? '' : `?${encodedParams}`}`;
|
|
2320
|
-
}
|
|
2321
|
-
disconnect() {
|
|
2322
|
-
this.shouldConnect = false;
|
|
2323
|
-
if (this.webSocket === null) {
|
|
2324
|
-
return;
|
|
2325
|
-
}
|
|
2326
|
-
try {
|
|
2327
|
-
this.webSocket.close();
|
|
2328
|
-
}
|
|
2329
|
-
catch {
|
|
2330
|
-
//
|
|
2331
|
-
}
|
|
2332
|
-
}
|
|
2333
|
-
send(message) {
|
|
2334
|
-
var _a;
|
|
2335
|
-
if (((_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.readyState) === common.WsReadyStates.Open) {
|
|
2336
|
-
this.webSocket.send(message);
|
|
2337
|
-
}
|
|
2338
|
-
}
|
|
2339
|
-
onClose({ event }) {
|
|
2340
|
-
this.webSocket = null;
|
|
2341
|
-
if (this.status === exports.WebSocketStatus.Connected) {
|
|
2342
|
-
this.status = exports.WebSocketStatus.Disconnected;
|
|
2343
|
-
this.emit('status', { status: exports.WebSocketStatus.Disconnected });
|
|
2344
|
-
this.emit('disconnect', { event });
|
|
2345
|
-
}
|
|
2346
|
-
if (event.code === common.Unauthorized.code) {
|
|
2347
|
-
if (!this.configuration.quiet) {
|
|
2348
|
-
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.');
|
|
2349
|
-
}
|
|
2350
|
-
this.shouldConnect = false;
|
|
2351
|
-
}
|
|
2352
|
-
if (event.code === common.Forbidden.code) {
|
|
2353
|
-
if (!this.configuration.quiet) {
|
|
2354
|
-
console.warn('[HocuspocusProvider] The provided authentication token isn’t allowed to connect to this server. Will try again.');
|
|
2355
|
-
return; // TODO REMOVE ME
|
|
2356
|
-
}
|
|
2357
|
-
}
|
|
2358
|
-
if (this.connectionAttempt) {
|
|
2359
|
-
// That connection attempt failed.
|
|
2360
|
-
this.rejectConnectionAttempt();
|
|
2361
|
-
}
|
|
2362
|
-
else if (this.shouldConnect) {
|
|
2363
|
-
// The connection was closed by the server. Let’s just try again.
|
|
2364
|
-
this.connect();
|
|
2365
|
-
}
|
|
2366
|
-
// If we’ll reconnect, we’re done for now.
|
|
2367
|
-
if (this.shouldConnect) {
|
|
2368
|
-
return;
|
|
2369
|
-
}
|
|
2370
|
-
// The status is set correctly already.
|
|
2371
|
-
if (this.status === exports.WebSocketStatus.Disconnected) {
|
|
2372
|
-
return;
|
|
2373
|
-
}
|
|
2374
|
-
// Let’s update the connection status.
|
|
2375
|
-
this.status = exports.WebSocketStatus.Disconnected;
|
|
2376
|
-
this.emit('status', { status: exports.WebSocketStatus.Disconnected });
|
|
2377
|
-
this.emit('disconnect', { event });
|
|
2378
|
-
}
|
|
2379
|
-
destroy() {
|
|
2380
|
-
this.emit('destroy');
|
|
2381
|
-
if (this.intervals.forceSync) {
|
|
2382
|
-
clearInterval(this.intervals.forceSync);
|
|
2383
|
-
}
|
|
2384
|
-
clearInterval(this.intervals.connectionChecker);
|
|
2385
|
-
// If there is still a connection attempt outstanding then we should stop
|
|
2386
|
-
// it before calling disconnect, otherwise it will be rejected in the onClose
|
|
2387
|
-
// handler and trigger a retry
|
|
2388
|
-
this.stopConnectionAttempt();
|
|
2389
|
-
this.disconnect();
|
|
2390
|
-
this.removeAllListeners();
|
|
2391
|
-
if (typeof window === 'undefined') {
|
|
2392
|
-
return;
|
|
2393
|
-
}
|
|
2394
|
-
window.removeEventListener('online', this.boundConnect);
|
|
2395
|
-
}
|
|
2396
|
-
}
|
|
2397
|
-
|
|
2398
|
-
class HocuspocusCloudProvider extends HocuspocusProvider {
|
|
2408
|
+
class TiptapCollabProvider extends HocuspocusProvider {
|
|
2399
2409
|
constructor(configuration) {
|
|
2400
|
-
if (!configuration.
|
|
2401
|
-
configuration.
|
|
2410
|
+
if (!configuration.websocketProvider) {
|
|
2411
|
+
configuration.websocketProvider = new HocuspocusProviderWebsocket({ url: `wss://${configuration.appId}.collab.tiptap.cloud` });
|
|
2402
2412
|
}
|
|
2403
|
-
if (configuration.
|
|
2404
|
-
|
|
2405
|
-
configuration.parameters = {};
|
|
2406
|
-
}
|
|
2407
|
-
configuration.parameters.key = configuration.key;
|
|
2413
|
+
if (!configuration.token) {
|
|
2414
|
+
configuration.token = 'notoken';
|
|
2408
2415
|
}
|
|
2409
|
-
configuration.websocketProvider = new HocuspocusProviderWebsocket({ url: configuration.url });
|
|
2410
2416
|
super(configuration);
|
|
2411
2417
|
}
|
|
2412
2418
|
}
|
|
2413
2419
|
|
|
2414
|
-
exports.HocuspocusCloudProvider = HocuspocusCloudProvider;
|
|
2415
2420
|
exports.HocuspocusProvider = HocuspocusProvider;
|
|
2416
2421
|
exports.HocuspocusProviderWebsocket = HocuspocusProviderWebsocket;
|
|
2422
|
+
exports.TiptapCollabProvider = TiptapCollabProvider;
|
|
2417
2423
|
//# sourceMappingURL=hocuspocus-provider.cjs.map
|