@hocuspocus/provider 1.0.0-alpha.9 → 1.0.0-beta.3
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 +374 -186
- package/dist/hocuspocus-provider.cjs.map +1 -1
- package/dist/hocuspocus-provider.esm.js +372 -182
- package/dist/hocuspocus-provider.esm.js.map +1 -1
- package/dist/packages/common/src/CloseEvents.d.ts +23 -0
- package/dist/packages/common/src/auth.d.ts +6 -0
- package/dist/packages/common/src/awarenessStatesToArray.d.ts +3 -0
- package/dist/packages/common/src/index.d.ts +4 -0
- package/dist/packages/common/src/types.d.ts +10 -0
- package/dist/packages/extension-database/src/Database.d.ts +30 -0
- package/dist/packages/extension-database/src/index.d.ts +1 -0
- package/dist/packages/extension-logger/src/Logger.d.ts +67 -0
- package/dist/packages/extension-logger/src/index.d.ts +1 -0
- package/dist/packages/{monitor → extension-monitor}/src/Collector.d.ts +4 -5
- package/dist/packages/{monitor → extension-monitor}/src/Dashboard.d.ts +2 -2
- package/dist/packages/{monitor → extension-monitor}/src/Storage.d.ts +0 -0
- package/dist/packages/{monitor → extension-monitor}/src/index.d.ts +3 -5
- package/dist/packages/extension-redis/src/Redis.d.ts +98 -0
- package/dist/packages/extension-redis/src/index.d.ts +1 -0
- package/dist/packages/extension-sqlite/src/SQLite.d.ts +26 -0
- package/dist/packages/extension-sqlite/src/index.d.ts +1 -0
- package/dist/packages/extension-throttle/src/index.d.ts +24 -0
- package/dist/packages/{webhook → extension-webhook}/src/index.d.ts +5 -11
- package/dist/packages/provider/src/EventEmitter.d.ts +1 -1
- package/dist/packages/provider/src/HocuspocusCloudProvider.d.ts +11 -0
- package/dist/packages/provider/src/HocuspocusProvider.d.ts +116 -33
- package/dist/packages/provider/src/IncomingMessage.d.ts +9 -6
- package/dist/packages/provider/src/MessageReceiver.d.ts +3 -2
- package/dist/packages/provider/src/MessageSender.d.ts +4 -9
- package/dist/packages/provider/src/OutgoingMessage.d.ts +5 -4
- package/dist/packages/provider/src/OutgoingMessages/AuthenticationMessage.d.ts +7 -0
- package/dist/packages/provider/src/OutgoingMessages/UpdateMessage.d.ts +1 -2
- package/dist/packages/provider/src/index.d.ts +1 -1
- package/dist/packages/provider/src/types.d.ts +54 -2
- package/dist/packages/server/src/Connection.d.ts +20 -7
- package/dist/packages/server/src/Debugger.d.ts +14 -0
- package/dist/packages/server/src/Document.d.ts +11 -5
- package/dist/packages/server/src/Hocuspocus.d.ts +63 -17
- package/dist/packages/server/src/IncomingMessage.d.ts +11 -7
- package/dist/packages/server/src/MessageReceiver.d.ts +13 -0
- package/dist/packages/server/src/OutgoingMessage.d.ts +6 -0
- package/dist/packages/server/src/index.d.ts +6 -0
- package/dist/packages/server/src/types.d.ts +180 -26
- package/dist/{demos/backend/src/create-document.d.ts → playground/backend/src/default.d.ts} +0 -0
- package/dist/{demos → playground}/backend/src/express.d.ts +0 -0
- package/dist/{demos → playground}/backend/src/koa.d.ts +0 -0
- package/dist/{demos/backend/src/minimal.d.ts → playground/backend/src/load-document.d.ts} +0 -0
- package/dist/{demos → playground}/backend/src/monitor.d.ts +0 -0
- package/dist/{demos → playground}/backend/src/redis.d.ts +0 -0
- package/dist/{demos → playground}/backend/src/slow.d.ts +0 -0
- package/dist/{demos → playground}/backend/src/webhook.d.ts +0 -0
- package/dist/tests/extension-database/fetch.d.ts +1 -0
- package/dist/tests/extension-logger/onListen.d.ts +1 -0
- package/dist/tests/extension-redis/closeConnections.d.ts +1 -0
- package/dist/tests/extension-redis/getConnectionCount.d.ts +1 -0
- package/dist/tests/extension-redis/getDocumentsCount.d.ts +1 -0
- package/dist/tests/extension-redis/onAwarenessChange.d.ts +1 -0
- package/dist/tests/extension-redis/onChange.d.ts +1 -0
- package/dist/tests/extension-redis/onStoreDocument.d.ts +1 -0
- package/dist/tests/extension-throttle/configuration.d.ts +1 -0
- package/dist/tests/provider/configuration.d.ts +1 -0
- package/dist/tests/provider/observe.d.ts +1 -0
- package/dist/tests/provider/observeDeep.d.ts +1 -0
- package/dist/tests/provider/onAuthenticated.d.ts +1 -0
- package/dist/tests/provider/onAuthenticationFailed.d.ts +1 -0
- package/dist/tests/provider/onAwarenessChange.d.ts +1 -0
- package/dist/tests/provider/onAwarenessUpdate.d.ts +1 -0
- package/dist/tests/provider/onClose.d.ts +1 -0
- package/dist/tests/provider/onConnect.d.ts +1 -0
- package/dist/tests/provider/onDisconnect.d.ts +1 -0
- package/dist/tests/provider/onMessage.d.ts +1 -0
- package/dist/tests/provider/onOpen.d.ts +1 -0
- package/dist/tests/provider/onSynced.d.ts +1 -0
- package/dist/tests/server/address.d.ts +1 -0
- package/dist/tests/server/afterStoreDocument.d.ts +1 -0
- package/dist/tests/server/beforeHandleMessage.d.ts +1 -0
- package/dist/tests/server/closeConnections.d.ts +1 -0
- package/dist/tests/server/getConnectionsCount.d.ts +1 -0
- package/dist/tests/server/getDocumentName.d.ts +1 -0
- package/dist/tests/server/getDocumentsCount.d.ts +1 -0
- package/dist/tests/server/getMessageLogs.d.ts +1 -0
- package/dist/tests/server/listen.d.ts +1 -0
- package/dist/tests/server/onAuthenticate.d.ts +1 -0
- package/dist/tests/server/onAwarenessUpdate.d.ts +1 -0
- package/dist/tests/server/onChange.d.ts +1 -0
- package/dist/tests/server/onConfigure.d.ts +1 -0
- package/dist/tests/server/onConnect.d.ts +1 -0
- package/dist/tests/server/onDestroy.d.ts +1 -0
- package/dist/tests/server/onDisconnect.d.ts +1 -0
- package/dist/tests/server/onListen.d.ts +1 -0
- package/dist/tests/server/onLoadDocument.d.ts +1 -0
- package/dist/tests/server/onRequest.d.ts +1 -0
- package/dist/tests/server/onStoreDocument.d.ts +1 -0
- package/dist/tests/server/onUpgrade.d.ts +1 -0
- package/dist/tests/server/requiresAuthentication.d.ts +1 -0
- package/dist/tests/server/websocketError.d.ts +1 -0
- package/dist/tests/transformer/TiptapTransformer.d.ts +1 -0
- package/dist/tests/utils/createDirectory.d.ts +1 -0
- package/dist/tests/utils/flushRedis.d.ts +1 -0
- package/dist/tests/utils/index.d.ts +8 -0
- package/dist/tests/utils/newHocuspocus.d.ts +2 -0
- package/dist/tests/utils/newHocuspocusProvider.d.ts +3 -0
- package/dist/tests/utils/randomInteger.d.ts +1 -0
- package/dist/tests/utils/redisConnectionSettings.d.ts +4 -0
- package/dist/tests/utils/removeDirectory.d.ts +1 -0
- package/dist/tests/utils/retryableAssertion.d.ts +2 -0
- package/dist/tests/utils/sleep.d.ts +1 -0
- package/package.json +16 -10
- package/src/EventEmitter.ts +1 -1
- package/src/HocuspocusCloudProvider.ts +34 -0
- package/src/HocuspocusProvider.ts +410 -162
- package/src/IncomingMessage.ts +35 -11
- package/src/MessageReceiver.ts +56 -24
- package/src/MessageSender.ts +5 -17
- package/src/OutgoingMessage.ts +9 -9
- package/src/OutgoingMessages/AuthenticationMessage.ts +21 -0
- package/src/OutgoingMessages/AwarenessMessage.ts +1 -1
- package/src/OutgoingMessages/SyncStepOneMessage.ts +0 -1
- package/src/OutgoingMessages/UpdateMessage.ts +4 -4
- package/src/index.ts +1 -1
- package/src/types.ts +70 -3
- package/CHANGELOG.md +0 -64
- package/LICENSE.md +0 -21
- package/dist/packages/logger/src/index.d.ts +0 -13
- package/dist/packages/provider/src/utils/awarenessStatesToArray.d.ts +0 -4
- package/dist/packages/provider/src/utils/index.d.ts +0 -1
- package/dist/packages/redis/src/Redis.d.ts +0 -22
- package/dist/packages/redis/src/RedisCluster.d.ts +0 -4
- package/dist/packages/redis/src/index.d.ts +0 -2
- package/dist/packages/rocksdb/src/index.d.ts +0 -30
- package/dist/packages/server/src/CloseEvents.d.ts +0 -3
- package/dist/packages/throttle/src/index.d.ts +0 -28
- package/src/utils/awarenessStatesToArray.ts +0 -8
- package/src/utils/index.ts +0 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import * as Y from 'yjs';
|
|
2
|
+
import { retry } from '@lifeomic/attempt';
|
|
3
|
+
import { readAuthMessage, writeAuthentication, awarenessStatesToArray, WsReadyStates, Unauthorized, Forbidden } from '@hocuspocus/common';
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* Utility module to work with key-value stores.
|
|
@@ -258,8 +260,6 @@ hasConf('production');
|
|
|
258
260
|
*/
|
|
259
261
|
|
|
260
262
|
const floor = Math.floor;
|
|
261
|
-
const round = Math.round;
|
|
262
|
-
const log10 = Math.log10;
|
|
263
263
|
|
|
264
264
|
/**
|
|
265
265
|
* @function
|
|
@@ -1372,23 +1372,26 @@ class EventEmitter {
|
|
|
1372
1372
|
}
|
|
1373
1373
|
}
|
|
1374
1374
|
|
|
1375
|
-
var MessageType;
|
|
1376
|
-
(function (MessageType) {
|
|
1377
|
-
MessageType[MessageType["Sync"] = 0] = "Sync";
|
|
1378
|
-
MessageType[MessageType["Awareness"] = 1] = "Awareness";
|
|
1379
|
-
MessageType[MessageType["Auth"] = 2] = "Auth";
|
|
1380
|
-
MessageType[MessageType["QueryAwareness"] = 3] = "QueryAwareness";
|
|
1381
|
-
})(MessageType || (MessageType = {}));
|
|
1382
|
-
|
|
1383
1375
|
class IncomingMessage {
|
|
1384
1376
|
constructor(data) {
|
|
1385
1377
|
this.data = data;
|
|
1386
1378
|
this.encoder = createEncoder();
|
|
1387
1379
|
this.decoder = createDecoder(new Uint8Array(this.data));
|
|
1388
|
-
this.type = readVarUint(this.decoder);
|
|
1389
1380
|
}
|
|
1390
|
-
|
|
1391
|
-
return
|
|
1381
|
+
readVarUint() {
|
|
1382
|
+
return readVarUint(this.decoder);
|
|
1383
|
+
}
|
|
1384
|
+
readVarUint8Array() {
|
|
1385
|
+
return readVarUint8Array(this.decoder);
|
|
1386
|
+
}
|
|
1387
|
+
writeVarUint(type) {
|
|
1388
|
+
return writeVarUint(this.encoder, type);
|
|
1389
|
+
}
|
|
1390
|
+
writeVarUint8Array(data) {
|
|
1391
|
+
return writeVarUint8Array(this.encoder, data);
|
|
1392
|
+
}
|
|
1393
|
+
length() {
|
|
1394
|
+
return length$1(this.encoder);
|
|
1392
1395
|
}
|
|
1393
1396
|
}
|
|
1394
1397
|
|
|
@@ -1519,32 +1522,45 @@ const readSyncMessage = (decoder, encoder, doc, transactionOrigin) => {
|
|
|
1519
1522
|
return messageType
|
|
1520
1523
|
};
|
|
1521
1524
|
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1525
|
+
var MessageType;
|
|
1526
|
+
(function (MessageType) {
|
|
1527
|
+
MessageType[MessageType["Sync"] = 0] = "Sync";
|
|
1528
|
+
MessageType[MessageType["Awareness"] = 1] = "Awareness";
|
|
1529
|
+
MessageType[MessageType["Auth"] = 2] = "Auth";
|
|
1530
|
+
MessageType[MessageType["QueryAwareness"] = 3] = "QueryAwareness";
|
|
1531
|
+
})(MessageType || (MessageType = {}));
|
|
1532
|
+
var WebSocketStatus;
|
|
1533
|
+
(function (WebSocketStatus) {
|
|
1534
|
+
WebSocketStatus["Connecting"] = "connecting";
|
|
1535
|
+
WebSocketStatus["Connected"] = "connected";
|
|
1536
|
+
WebSocketStatus["Disconnected"] = "disconnected";
|
|
1537
|
+
})(WebSocketStatus || (WebSocketStatus = {}));
|
|
1529
1538
|
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
}
|
|
1539
|
+
class OutgoingMessage {
|
|
1540
|
+
constructor() {
|
|
1541
|
+
this.encoder = createEncoder();
|
|
1542
|
+
}
|
|
1543
|
+
get(args) {
|
|
1544
|
+
return args.encoder;
|
|
1545
|
+
}
|
|
1546
|
+
toUint8Array() {
|
|
1547
|
+
return toUint8Array(this.encoder);
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1541
1550
|
|
|
1542
1551
|
class MessageReceiver {
|
|
1543
1552
|
constructor(message) {
|
|
1553
|
+
this.broadcasted = false;
|
|
1544
1554
|
this.message = message;
|
|
1545
1555
|
}
|
|
1556
|
+
setBroadcasted(value) {
|
|
1557
|
+
this.broadcasted = value;
|
|
1558
|
+
return this;
|
|
1559
|
+
}
|
|
1546
1560
|
apply(provider, emitSynced = true) {
|
|
1547
|
-
|
|
1561
|
+
const { message } = this;
|
|
1562
|
+
const type = message.readVarUint();
|
|
1563
|
+
switch (type) {
|
|
1548
1564
|
case MessageType.Sync:
|
|
1549
1565
|
this.applySyncMessage(provider, emitSynced);
|
|
1550
1566
|
break;
|
|
@@ -1558,31 +1574,49 @@ class MessageReceiver {
|
|
|
1558
1574
|
this.applyQueryAwarenessMessage(provider);
|
|
1559
1575
|
break;
|
|
1560
1576
|
default:
|
|
1561
|
-
throw new Error(`Can’t apply unknown type
|
|
1577
|
+
throw new Error(`Can’t apply message of unknown type: ${type}`);
|
|
1578
|
+
}
|
|
1579
|
+
// Reply
|
|
1580
|
+
if (message.length() > 1) {
|
|
1581
|
+
if (this.broadcasted) {
|
|
1582
|
+
// TODO: Some weird TypeScript error
|
|
1583
|
+
// @ts-ignore
|
|
1584
|
+
provider.broadcast(OutgoingMessage, { encoder: message.encoder });
|
|
1585
|
+
}
|
|
1586
|
+
else {
|
|
1587
|
+
// TODO: Some weird TypeScript error
|
|
1588
|
+
// @ts-ignore
|
|
1589
|
+
provider.send(OutgoingMessage, { encoder: message.encoder });
|
|
1590
|
+
}
|
|
1562
1591
|
}
|
|
1563
|
-
return this.message.encoder;
|
|
1564
1592
|
}
|
|
1565
1593
|
applySyncMessage(provider, emitSynced) {
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1594
|
+
const { message } = this;
|
|
1595
|
+
message.writeVarUint(MessageType.Sync);
|
|
1596
|
+
// Apply update
|
|
1597
|
+
const syncMessageType = readSyncMessage(message.decoder, message.encoder, provider.document, provider);
|
|
1598
|
+
// Synced once we receive Step2
|
|
1599
|
+
if (emitSynced && (syncMessageType === messageYjsSyncStep2)) {
|
|
1569
1600
|
provider.synced = true;
|
|
1570
1601
|
}
|
|
1602
|
+
if (syncMessageType === messageYjsUpdate || syncMessageType === messageYjsSyncStep2) {
|
|
1603
|
+
if (provider.unsyncedChanges > 0) {
|
|
1604
|
+
provider.unsyncedChanges -= 1;
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1571
1607
|
}
|
|
1572
1608
|
applyAwarenessMessage(provider) {
|
|
1573
|
-
|
|
1609
|
+
const { message } = this;
|
|
1610
|
+
applyAwarenessUpdate(provider.awareness, message.readVarUint8Array(), provider);
|
|
1574
1611
|
}
|
|
1575
|
-
// TODO: This isn’t really used. Needs to be implemented in the server, or removed here.
|
|
1576
1612
|
applyAuthMessage(provider) {
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
(provider, reason) => {
|
|
1580
|
-
console.warn(`Permission denied to access ${provider.url}.\n${reason}`);
|
|
1581
|
-
});
|
|
1613
|
+
const { message } = this;
|
|
1614
|
+
readAuthMessage(message.decoder, provider.permissionDeniedHandler.bind(provider), provider.authenticatedHandler.bind(provider));
|
|
1582
1615
|
}
|
|
1583
1616
|
applyQueryAwarenessMessage(provider) {
|
|
1584
|
-
|
|
1585
|
-
|
|
1617
|
+
const { message } = this;
|
|
1618
|
+
message.writeVarUint(MessageType.Awareness);
|
|
1619
|
+
message.writeVarUint8Array(encodeAwarenessUpdate(provider.awareness, Array.from(provider.awareness.getStates().keys())));
|
|
1586
1620
|
}
|
|
1587
1621
|
}
|
|
1588
1622
|
|
|
@@ -1602,18 +1636,6 @@ class MessageSender {
|
|
|
1602
1636
|
}
|
|
1603
1637
|
}
|
|
1604
1638
|
|
|
1605
|
-
class OutgoingMessage {
|
|
1606
|
-
constructor() {
|
|
1607
|
-
this.encoder = createEncoder();
|
|
1608
|
-
}
|
|
1609
|
-
get name() {
|
|
1610
|
-
if (typeof this.type === 'number') {
|
|
1611
|
-
return MessageType[this.type];
|
|
1612
|
-
}
|
|
1613
|
-
throw new Error('Type for outgoing message not set.');
|
|
1614
|
-
}
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
1639
|
class SyncStepOneMessage extends OutgoingMessage {
|
|
1618
1640
|
constructor() {
|
|
1619
1641
|
super(...arguments);
|
|
@@ -1658,6 +1680,22 @@ class QueryAwarenessMessage extends OutgoingMessage {
|
|
|
1658
1680
|
}
|
|
1659
1681
|
}
|
|
1660
1682
|
|
|
1683
|
+
class AuthenticationMessage extends OutgoingMessage {
|
|
1684
|
+
constructor() {
|
|
1685
|
+
super(...arguments);
|
|
1686
|
+
this.type = MessageType.Auth;
|
|
1687
|
+
this.description = 'Authentication';
|
|
1688
|
+
}
|
|
1689
|
+
get(args) {
|
|
1690
|
+
if (typeof args.token === 'undefined') {
|
|
1691
|
+
throw new Error('The authentication message requires `token` as an argument.');
|
|
1692
|
+
}
|
|
1693
|
+
writeVarUint(this.encoder, this.type);
|
|
1694
|
+
writeAuthentication(this.encoder, args.token);
|
|
1695
|
+
return this.encoder;
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1661
1699
|
class AwarenessMessage extends OutgoingMessage {
|
|
1662
1700
|
constructor() {
|
|
1663
1701
|
super(...arguments);
|
|
@@ -1697,37 +1735,42 @@ class UpdateMessage extends OutgoingMessage {
|
|
|
1697
1735
|
}
|
|
1698
1736
|
}
|
|
1699
1737
|
|
|
1700
|
-
var awarenessStatesToArray = (states) => {
|
|
1701
|
-
return Array.from(states.entries()).map(([key, value]) => {
|
|
1702
|
-
return {
|
|
1703
|
-
clientId: key,
|
|
1704
|
-
...value,
|
|
1705
|
-
};
|
|
1706
|
-
});
|
|
1707
|
-
};
|
|
1708
|
-
|
|
1709
|
-
// @ts-nocheck
|
|
1710
|
-
var WebSocketStatus;
|
|
1711
|
-
(function (WebSocketStatus) {
|
|
1712
|
-
WebSocketStatus["Connecting"] = "connecting";
|
|
1713
|
-
WebSocketStatus["Connected"] = "connected";
|
|
1714
|
-
WebSocketStatus["Disconnected"] = "disconnected";
|
|
1715
|
-
})(WebSocketStatus || (WebSocketStatus = {}));
|
|
1716
1738
|
class HocuspocusProvider extends EventEmitter {
|
|
1717
|
-
constructor(
|
|
1739
|
+
constructor(configuration) {
|
|
1718
1740
|
super();
|
|
1719
|
-
this.
|
|
1720
|
-
url: '',
|
|
1741
|
+
this.configuration = {
|
|
1721
1742
|
name: '',
|
|
1743
|
+
url: '',
|
|
1744
|
+
// @ts-ignore
|
|
1745
|
+
document: undefined,
|
|
1746
|
+
// @ts-ignore
|
|
1747
|
+
awareness: undefined,
|
|
1748
|
+
WebSocketPolyfill: undefined,
|
|
1749
|
+
token: null,
|
|
1722
1750
|
parameters: {},
|
|
1723
|
-
debug: false,
|
|
1724
1751
|
connect: true,
|
|
1725
1752
|
broadcast: true,
|
|
1726
1753
|
forceSyncInterval: false,
|
|
1727
|
-
reconnectTimeoutBase: 1200,
|
|
1728
|
-
maxReconnectTimeout: 2500,
|
|
1729
1754
|
// TODO: this should depend on awareness.outdatedTime
|
|
1730
1755
|
messageReconnectTimeout: 30000,
|
|
1756
|
+
// 1 second
|
|
1757
|
+
delay: 1000,
|
|
1758
|
+
// instant
|
|
1759
|
+
initialDelay: 0,
|
|
1760
|
+
// double the delay each time
|
|
1761
|
+
factor: 2,
|
|
1762
|
+
// unlimited retries
|
|
1763
|
+
maxAttempts: 0,
|
|
1764
|
+
// wait at least 1 second
|
|
1765
|
+
minDelay: 1000,
|
|
1766
|
+
// at least every 30 seconds
|
|
1767
|
+
maxDelay: 30000,
|
|
1768
|
+
// randomize
|
|
1769
|
+
jitter: true,
|
|
1770
|
+
// retry forever
|
|
1771
|
+
timeout: 0,
|
|
1772
|
+
onAuthenticated: () => null,
|
|
1773
|
+
onAuthenticationFailed: () => null,
|
|
1731
1774
|
onOpen: () => null,
|
|
1732
1775
|
onConnect: () => null,
|
|
1733
1776
|
onMessage: () => null,
|
|
@@ -1737,70 +1780,183 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1737
1780
|
onDisconnect: () => null,
|
|
1738
1781
|
onClose: () => null,
|
|
1739
1782
|
onDestroy: () => null,
|
|
1783
|
+
onAwarenessUpdate: () => null,
|
|
1740
1784
|
onAwarenessChange: () => null,
|
|
1785
|
+
quiet: false,
|
|
1741
1786
|
};
|
|
1742
1787
|
this.subscribedToBroadcastChannel = false;
|
|
1743
1788
|
this.webSocket = null;
|
|
1744
1789
|
this.shouldConnect = true;
|
|
1745
1790
|
this.status = WebSocketStatus.Disconnected;
|
|
1746
|
-
this.failedConnectionAttempts = 0;
|
|
1747
1791
|
this.isSynced = false;
|
|
1792
|
+
this.unsyncedChanges = 0;
|
|
1793
|
+
this.isAuthenticated = false;
|
|
1748
1794
|
this.lastMessageReceived = 0;
|
|
1749
1795
|
this.mux = createMutex();
|
|
1750
1796
|
this.intervals = {
|
|
1751
1797
|
forceSync: null,
|
|
1752
1798
|
connectionChecker: null,
|
|
1753
1799
|
};
|
|
1754
|
-
this.
|
|
1755
|
-
this.
|
|
1756
|
-
this.
|
|
1757
|
-
this.
|
|
1758
|
-
this.
|
|
1759
|
-
this.
|
|
1760
|
-
this.
|
|
1761
|
-
this.
|
|
1762
|
-
this.on('
|
|
1763
|
-
this.on('
|
|
1764
|
-
this.on('
|
|
1765
|
-
this.on('
|
|
1766
|
-
this.on('
|
|
1767
|
-
this.on('
|
|
1768
|
-
this.on('
|
|
1800
|
+
this.connectionAttempt = null;
|
|
1801
|
+
this.boundConnect = this.connect.bind(this);
|
|
1802
|
+
this.boundBeforeUnload = this.beforeUnload.bind(this);
|
|
1803
|
+
this.boundBroadcastChannelSubscriber = this.broadcastChannelSubscriber.bind(this);
|
|
1804
|
+
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
|
+
this.configuration.WebSocketPolyfill = configuration.WebSocketPolyfill ? configuration.WebSocketPolyfill : WebSocket;
|
|
1808
|
+
this.on('open', this.configuration.onOpen);
|
|
1809
|
+
this.on('authenticated', this.configuration.onAuthenticated);
|
|
1810
|
+
this.on('authenticationFailed', this.configuration.onAuthenticationFailed);
|
|
1811
|
+
this.on('connect', this.configuration.onConnect);
|
|
1812
|
+
this.on('message', this.configuration.onMessage);
|
|
1813
|
+
this.on('outgoingMessage', this.configuration.onOutgoingMessage);
|
|
1814
|
+
this.on('synced', this.configuration.onSynced);
|
|
1815
|
+
this.on('status', this.configuration.onStatus);
|
|
1816
|
+
this.on('disconnect', this.configuration.onDisconnect);
|
|
1817
|
+
this.on('close', this.configuration.onClose);
|
|
1818
|
+
this.on('destroy', this.configuration.onDestroy);
|
|
1819
|
+
this.on('awarenessUpdate', this.configuration.onAwarenessUpdate);
|
|
1820
|
+
this.on('awarenessChange', this.configuration.onAwarenessChange);
|
|
1821
|
+
this.awareness.on('update', () => {
|
|
1822
|
+
this.emit('awarenessUpdate', { states: awarenessStatesToArray(this.awareness.getStates()) });
|
|
1823
|
+
});
|
|
1769
1824
|
this.awareness.on('change', () => {
|
|
1770
|
-
this.emit('awarenessChange', {
|
|
1771
|
-
states: awarenessStatesToArray(this.awareness.getStates()),
|
|
1772
|
-
});
|
|
1825
|
+
this.emit('awarenessChange', { states: awarenessStatesToArray(this.awareness.getStates()) });
|
|
1773
1826
|
});
|
|
1774
|
-
this.intervals.connectionChecker = setInterval(this.checkConnection.bind(this), this.options.messageReconnectTimeout / 10);
|
|
1775
1827
|
this.document.on('update', this.documentUpdateHandler.bind(this));
|
|
1776
1828
|
this.awareness.on('update', this.awarenessUpdateHandler.bind(this));
|
|
1777
|
-
this.
|
|
1778
|
-
|
|
1779
|
-
|
|
1829
|
+
this.registerEventListeners();
|
|
1830
|
+
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);
|
|
1780
1833
|
}
|
|
1781
|
-
if (
|
|
1782
|
-
this.connect
|
|
1834
|
+
if (typeof configuration.connect !== 'undefined') {
|
|
1835
|
+
this.shouldConnect = configuration.connect;
|
|
1836
|
+
}
|
|
1837
|
+
if (!this.shouldConnect) {
|
|
1838
|
+
return;
|
|
1783
1839
|
}
|
|
1840
|
+
this.connect();
|
|
1784
1841
|
}
|
|
1785
|
-
|
|
1786
|
-
this.
|
|
1842
|
+
setConfiguration(configuration = {}) {
|
|
1843
|
+
this.configuration = { ...this.configuration, ...configuration };
|
|
1844
|
+
}
|
|
1845
|
+
async connect() {
|
|
1846
|
+
if (this.status === WebSocketStatus.Connected) {
|
|
1847
|
+
return;
|
|
1848
|
+
}
|
|
1849
|
+
// Always cancel any previously initiated connection retryer instances
|
|
1850
|
+
if (this.cancelWebsocketRetry) {
|
|
1851
|
+
this.cancelWebsocketRetry();
|
|
1852
|
+
this.cancelWebsocketRetry = undefined;
|
|
1853
|
+
}
|
|
1854
|
+
this.unsyncedChanges = 0; // set to 0 in case we got reconnected
|
|
1855
|
+
this.shouldConnect = true;
|
|
1856
|
+
this.subscribeToBroadcastChannel();
|
|
1857
|
+
const abortableRetry = () => {
|
|
1858
|
+
let cancelAttempt = false;
|
|
1859
|
+
const retryPromise = retry(this.createWebSocketConnection.bind(this), {
|
|
1860
|
+
delay: this.configuration.delay,
|
|
1861
|
+
initialDelay: this.configuration.initialDelay,
|
|
1862
|
+
factor: this.configuration.factor,
|
|
1863
|
+
maxAttempts: this.configuration.maxAttempts,
|
|
1864
|
+
minDelay: this.configuration.minDelay,
|
|
1865
|
+
maxDelay: this.configuration.maxDelay,
|
|
1866
|
+
jitter: this.configuration.jitter,
|
|
1867
|
+
timeout: this.configuration.timeout,
|
|
1868
|
+
beforeAttempt: context => {
|
|
1869
|
+
if (!this.shouldConnect || cancelAttempt) {
|
|
1870
|
+
context.abort();
|
|
1871
|
+
}
|
|
1872
|
+
},
|
|
1873
|
+
}).catch((error) => {
|
|
1874
|
+
// If we aborted the connection attempt then don’t throw an error
|
|
1875
|
+
// ref: https://github.com/lifeomic/attempt/blob/master/src/index.ts#L136
|
|
1876
|
+
if (error && error.code !== 'ATTEMPT_ABORTED') {
|
|
1877
|
+
throw error;
|
|
1878
|
+
}
|
|
1879
|
+
});
|
|
1880
|
+
return {
|
|
1881
|
+
retryPromise,
|
|
1882
|
+
cancelFunc: () => {
|
|
1883
|
+
cancelAttempt = true;
|
|
1884
|
+
},
|
|
1885
|
+
};
|
|
1886
|
+
};
|
|
1887
|
+
const { retryPromise, cancelFunc } = abortableRetry();
|
|
1888
|
+
this.cancelWebsocketRetry = cancelFunc;
|
|
1889
|
+
return retryPromise;
|
|
1890
|
+
}
|
|
1891
|
+
createWebSocketConnection() {
|
|
1892
|
+
return new Promise((resolve, reject) => {
|
|
1893
|
+
if (this.webSocket) {
|
|
1894
|
+
this.webSocket.close();
|
|
1895
|
+
this.webSocket = null;
|
|
1896
|
+
}
|
|
1897
|
+
// Init the WebSocket connection
|
|
1898
|
+
const ws = new this.configuration.WebSocketPolyfill(this.url);
|
|
1899
|
+
ws.binaryType = 'arraybuffer';
|
|
1900
|
+
ws.onmessage = this.onMessage.bind(this);
|
|
1901
|
+
ws.onclose = this.onClose.bind(this);
|
|
1902
|
+
ws.onopen = this.onOpen.bind(this);
|
|
1903
|
+
ws.onerror = (err) => {
|
|
1904
|
+
reject(err);
|
|
1905
|
+
};
|
|
1906
|
+
this.webSocket = ws;
|
|
1907
|
+
// Reset the status
|
|
1908
|
+
this.synced = false;
|
|
1909
|
+
this.status = WebSocketStatus.Connecting;
|
|
1910
|
+
this.emit('status', { status: WebSocketStatus.Connecting });
|
|
1911
|
+
// Store resolve/reject for later use
|
|
1912
|
+
this.connectionAttempt = {
|
|
1913
|
+
resolve,
|
|
1914
|
+
reject,
|
|
1915
|
+
};
|
|
1916
|
+
});
|
|
1917
|
+
}
|
|
1918
|
+
resolveConnectionAttempt() {
|
|
1919
|
+
var _a;
|
|
1920
|
+
(_a = this.connectionAttempt) === null || _a === void 0 ? void 0 : _a.resolve();
|
|
1921
|
+
this.connectionAttempt = null;
|
|
1922
|
+
this.status = WebSocketStatus.Connected;
|
|
1923
|
+
this.emit('status', { status: WebSocketStatus.Connected });
|
|
1924
|
+
this.emit('connect');
|
|
1925
|
+
}
|
|
1926
|
+
stopConnectionAttempt() {
|
|
1927
|
+
this.connectionAttempt = null;
|
|
1928
|
+
}
|
|
1929
|
+
rejectConnectionAttempt() {
|
|
1930
|
+
var _a;
|
|
1931
|
+
(_a = this.connectionAttempt) === null || _a === void 0 ? void 0 : _a.reject();
|
|
1932
|
+
this.connectionAttempt = null;
|
|
1787
1933
|
}
|
|
1788
1934
|
get document() {
|
|
1789
|
-
return this.
|
|
1935
|
+
return this.configuration.document;
|
|
1790
1936
|
}
|
|
1791
1937
|
get awareness() {
|
|
1792
|
-
return this.
|
|
1938
|
+
return this.configuration.awareness;
|
|
1939
|
+
}
|
|
1940
|
+
get hasUnsyncedChanges() {
|
|
1941
|
+
return this.unsyncedChanges > 0;
|
|
1793
1942
|
}
|
|
1794
1943
|
checkConnection() {
|
|
1944
|
+
var _a;
|
|
1945
|
+
// Don’t check the connection when it’s not even established
|
|
1795
1946
|
if (this.status !== WebSocketStatus.Connected) {
|
|
1796
1947
|
return;
|
|
1797
1948
|
}
|
|
1798
|
-
|
|
1949
|
+
// Don’t close then connection while waiting for the first message
|
|
1950
|
+
if (!this.lastMessageReceived) {
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
// Don’t close the connection when a message was received recently
|
|
1954
|
+
if (this.configuration.messageReconnectTimeout >= getUnixTime() - this.lastMessageReceived) {
|
|
1799
1955
|
return;
|
|
1800
1956
|
}
|
|
1801
1957
|
// No message received in a long time, not even your own
|
|
1802
1958
|
// Awareness updates, which are updated every 15 seconds.
|
|
1803
|
-
this.webSocket.close();
|
|
1959
|
+
(_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.close();
|
|
1804
1960
|
}
|
|
1805
1961
|
forceSync() {
|
|
1806
1962
|
if (!this.webSocket) {
|
|
@@ -1808,18 +1964,21 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1808
1964
|
}
|
|
1809
1965
|
this.send(SyncStepOneMessage, { document: this.document });
|
|
1810
1966
|
}
|
|
1811
|
-
|
|
1967
|
+
beforeUnload() {
|
|
1968
|
+
removeAwarenessStates(this.awareness, [this.document.clientID], 'window unload');
|
|
1969
|
+
}
|
|
1970
|
+
registerEventListeners() {
|
|
1812
1971
|
if (typeof window === 'undefined') {
|
|
1813
1972
|
return;
|
|
1814
1973
|
}
|
|
1815
|
-
window.addEventListener('
|
|
1816
|
-
|
|
1817
|
-
});
|
|
1974
|
+
window.addEventListener('online', this.boundConnect);
|
|
1975
|
+
window.addEventListener('beforeunload', this.boundBeforeUnload);
|
|
1818
1976
|
}
|
|
1819
1977
|
documentUpdateHandler(update, origin) {
|
|
1820
1978
|
if (origin === this) {
|
|
1821
1979
|
return;
|
|
1822
1980
|
}
|
|
1981
|
+
this.unsyncedChanges += 1;
|
|
1823
1982
|
this.send(UpdateMessage, { update }, true);
|
|
1824
1983
|
}
|
|
1825
1984
|
awarenessUpdateHandler({ added, updated, removed }, origin) {
|
|
@@ -1829,16 +1988,26 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1829
1988
|
clients: changedClients,
|
|
1830
1989
|
}, true);
|
|
1831
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
|
+
}
|
|
1832
2001
|
// Ensure that the URL always ends with /
|
|
1833
2002
|
get serverUrl() {
|
|
1834
|
-
while (this.
|
|
1835
|
-
return this.
|
|
2003
|
+
while (this.configuration.url[this.configuration.url.length - 1] === '/') {
|
|
2004
|
+
return this.configuration.url.slice(0, this.configuration.url.length - 1);
|
|
1836
2005
|
}
|
|
1837
|
-
return this.
|
|
2006
|
+
return this.configuration.url;
|
|
1838
2007
|
}
|
|
1839
2008
|
get url() {
|
|
1840
|
-
const encodedParams = encodeQueryParams(this.
|
|
1841
|
-
return `${this.serverUrl}/${this.
|
|
2009
|
+
const encodedParams = encodeQueryParams(this.configuration.parameters);
|
|
2010
|
+
return `${this.serverUrl}/${this.configuration.name}${encodedParams.length === 0 ? '' : `?${encodedParams}`}`;
|
|
1842
2011
|
}
|
|
1843
2012
|
get synced() {
|
|
1844
2013
|
return this.isSynced;
|
|
@@ -1851,12 +2020,8 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1851
2020
|
this.emit('synced', { state });
|
|
1852
2021
|
this.emit('sync', { state });
|
|
1853
2022
|
}
|
|
1854
|
-
|
|
1855
|
-
this.
|
|
1856
|
-
if (this.status !== WebSocketStatus.Connected) {
|
|
1857
|
-
this.createWebSocketConnection();
|
|
1858
|
-
this.subscribeToBroadcastChannel();
|
|
1859
|
-
}
|
|
2023
|
+
get isAuthenticationRequired() {
|
|
2024
|
+
return !!this.configuration.token && !this.isAuthenticated;
|
|
1860
2025
|
}
|
|
1861
2026
|
disconnect() {
|
|
1862
2027
|
this.shouldConnect = false;
|
|
@@ -1871,27 +2036,24 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1871
2036
|
//
|
|
1872
2037
|
}
|
|
1873
2038
|
}
|
|
1874
|
-
|
|
1875
|
-
|
|
2039
|
+
async onOpen(event) {
|
|
2040
|
+
this.emit('open', { event });
|
|
2041
|
+
if (this.isAuthenticationRequired) {
|
|
2042
|
+
this.send(AuthenticationMessage, {
|
|
2043
|
+
token: await this.getToken(),
|
|
2044
|
+
});
|
|
1876
2045
|
return;
|
|
1877
2046
|
}
|
|
1878
|
-
this.
|
|
1879
|
-
this.webSocket.binaryType = 'arraybuffer';
|
|
1880
|
-
this.status = WebSocketStatus.Connecting;
|
|
1881
|
-
this.synced = false;
|
|
1882
|
-
this.webSocket.onmessage = this.onMessage.bind(this);
|
|
1883
|
-
this.webSocket.onclose = this.onClose.bind(this);
|
|
1884
|
-
this.webSocket.onopen = this.onOpen.bind(this);
|
|
1885
|
-
this.emit('status', { status: 'connecting' });
|
|
2047
|
+
this.startSync();
|
|
1886
2048
|
}
|
|
1887
|
-
|
|
1888
|
-
this.
|
|
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;
|
|
1889
2055
|
}
|
|
1890
|
-
|
|
1891
|
-
this.failedConnectionAttempts = 0;
|
|
1892
|
-
this.status = WebSocketStatus.Connected;
|
|
1893
|
-
this.emit('status', { status: 'connected' });
|
|
1894
|
-
this.emit('connect');
|
|
2056
|
+
startSync() {
|
|
1895
2057
|
this.send(SyncStepOneMessage, { document: this.document });
|
|
1896
2058
|
if (this.awareness.getLocalState() !== null) {
|
|
1897
2059
|
this.send(AwarenessMessage, {
|
|
@@ -1901,55 +2063,66 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1901
2063
|
}
|
|
1902
2064
|
}
|
|
1903
2065
|
send(Message, args, broadcast = false) {
|
|
2066
|
+
var _a;
|
|
1904
2067
|
if (broadcast) {
|
|
1905
|
-
this.mux(() => {
|
|
1906
|
-
this.broadcast(Message, args);
|
|
1907
|
-
});
|
|
2068
|
+
this.mux(() => { this.broadcast(Message, args); });
|
|
1908
2069
|
}
|
|
1909
|
-
if (this.
|
|
2070
|
+
if (((_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.readyState) === WsReadyStates.Open) {
|
|
1910
2071
|
const messageSender = new MessageSender(Message, args);
|
|
1911
2072
|
this.emit('outgoingMessage', { message: messageSender.message });
|
|
1912
2073
|
messageSender.send(this.webSocket);
|
|
1913
2074
|
}
|
|
1914
2075
|
}
|
|
1915
2076
|
onMessage(event) {
|
|
1916
|
-
|
|
1917
|
-
this.webSocketConnectionEstablished();
|
|
1918
|
-
}
|
|
2077
|
+
this.resolveConnectionAttempt();
|
|
1919
2078
|
this.lastMessageReceived = getUnixTime();
|
|
1920
2079
|
const message = new IncomingMessage(event.data);
|
|
1921
2080
|
this.emit('message', { event, message });
|
|
1922
|
-
new MessageReceiver(message
|
|
1923
|
-
// TODO: What’s that doing?
|
|
1924
|
-
// if (encoding.length(encoder) > 1) {
|
|
1925
|
-
// this.send(encoding.toUint8Array(encoder))
|
|
1926
|
-
// }
|
|
2081
|
+
new MessageReceiver(message).apply(this);
|
|
1927
2082
|
}
|
|
1928
2083
|
onClose(event) {
|
|
1929
2084
|
this.emit('close', { event });
|
|
1930
2085
|
this.webSocket = null;
|
|
2086
|
+
this.isAuthenticated = false;
|
|
2087
|
+
this.synced = false;
|
|
1931
2088
|
if (this.status === WebSocketStatus.Connected) {
|
|
1932
|
-
this.synced = false;
|
|
1933
2089
|
// update awareness (all users except local left)
|
|
1934
2090
|
removeAwarenessStates(this.awareness, Array.from(this.awareness.getStates().keys()).filter(client => client !== this.document.clientID), this);
|
|
1935
2091
|
this.status = WebSocketStatus.Disconnected;
|
|
1936
|
-
this.emit('status', { status:
|
|
2092
|
+
this.emit('status', { status: WebSocketStatus.Disconnected });
|
|
1937
2093
|
this.emit('disconnect', { event });
|
|
1938
2094
|
}
|
|
1939
|
-
|
|
1940
|
-
this.
|
|
2095
|
+
if (event.code === Unauthorized.code) {
|
|
2096
|
+
if (!this.configuration.quiet) {
|
|
2097
|
+
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.');
|
|
2098
|
+
}
|
|
2099
|
+
this.shouldConnect = false;
|
|
2100
|
+
}
|
|
2101
|
+
if (event.code === Forbidden.code) {
|
|
2102
|
+
if (!this.configuration.quiet) {
|
|
2103
|
+
console.warn('[HocuspocusProvider] The provided authentication token isn’t allowed to connect to this server. Will try again.');
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
if (this.connectionAttempt) {
|
|
2107
|
+
// That connection attempt failed.
|
|
2108
|
+
this.rejectConnectionAttempt();
|
|
1941
2109
|
}
|
|
2110
|
+
else if (this.shouldConnect) {
|
|
2111
|
+
// The connection was closed by the server. Let’s just try again.
|
|
2112
|
+
this.connect();
|
|
2113
|
+
}
|
|
2114
|
+
// If we’ll reconnect, we’re done for now.
|
|
1942
2115
|
if (this.shouldConnect) {
|
|
1943
|
-
const wait = round(min(log10(this.failedConnectionAttempts + 1) * this.options.reconnectTimeoutBase, this.options.maxReconnectTimeout));
|
|
1944
|
-
this.log(`[close] Reconnecting in ${wait}ms …`);
|
|
1945
|
-
setTimeout(this.createWebSocketConnection.bind(this), wait);
|
|
1946
2116
|
return;
|
|
1947
2117
|
}
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
this.emit('disconnect', { event });
|
|
2118
|
+
// The status is set correctly already.
|
|
2119
|
+
if (this.status === WebSocketStatus.Disconnected) {
|
|
2120
|
+
return;
|
|
1952
2121
|
}
|
|
2122
|
+
// Let’s update the connection status.
|
|
2123
|
+
this.status = WebSocketStatus.Disconnected;
|
|
2124
|
+
this.emit('status', { status: WebSocketStatus.Disconnected });
|
|
2125
|
+
this.emit('disconnect', { event });
|
|
1953
2126
|
}
|
|
1954
2127
|
destroy() {
|
|
1955
2128
|
this.emit('destroy');
|
|
@@ -1957,27 +2130,35 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1957
2130
|
clearInterval(this.intervals.forceSync);
|
|
1958
2131
|
}
|
|
1959
2132
|
clearInterval(this.intervals.connectionChecker);
|
|
2133
|
+
removeAwarenessStates(this.awareness, [this.document.clientID], 'provider destroy');
|
|
2134
|
+
// If there is still a connection attempt outstanding then we should stop
|
|
2135
|
+
// it before calling disconnect, otherwise it will be rejected in the onClose
|
|
2136
|
+
// handler and trigger a retry
|
|
2137
|
+
this.stopConnectionAttempt();
|
|
1960
2138
|
this.disconnect();
|
|
1961
2139
|
this.awareness.off('update', this.awarenessUpdateHandler);
|
|
1962
2140
|
this.document.off('update', this.documentUpdateHandler);
|
|
1963
2141
|
this.removeAllListeners();
|
|
2142
|
+
if (typeof window === 'undefined') {
|
|
2143
|
+
return;
|
|
2144
|
+
}
|
|
2145
|
+
window.removeEventListener('online', this.boundConnect);
|
|
2146
|
+
window.removeEventListener('beforeunload', this.boundBeforeUnload);
|
|
1964
2147
|
}
|
|
1965
2148
|
get broadcastChannel() {
|
|
1966
|
-
return `${this.serverUrl}/${this.
|
|
2149
|
+
return `${this.serverUrl}/${this.configuration.name}`;
|
|
1967
2150
|
}
|
|
1968
2151
|
broadcastChannelSubscriber(data) {
|
|
1969
2152
|
this.mux(() => {
|
|
1970
2153
|
const message = new IncomingMessage(data);
|
|
1971
|
-
new MessageReceiver(message
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
// this.broadcast(encoding.toUint8Array(encoder))
|
|
1975
|
-
// }
|
|
2154
|
+
new MessageReceiver(message)
|
|
2155
|
+
.setBroadcasted(true)
|
|
2156
|
+
.apply(this, false);
|
|
1976
2157
|
});
|
|
1977
2158
|
}
|
|
1978
2159
|
subscribeToBroadcastChannel() {
|
|
1979
2160
|
if (!this.subscribedToBroadcastChannel) {
|
|
1980
|
-
subscribe(this.broadcastChannel, this.
|
|
2161
|
+
subscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber);
|
|
1981
2162
|
this.subscribedToBroadcastChannel = true;
|
|
1982
2163
|
}
|
|
1983
2164
|
this.mux(() => {
|
|
@@ -1995,12 +2176,12 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1995
2176
|
states: new Map(),
|
|
1996
2177
|
}, true);
|
|
1997
2178
|
if (this.subscribedToBroadcastChannel) {
|
|
1998
|
-
unsubscribe(this.broadcastChannel, this.
|
|
2179
|
+
unsubscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber);
|
|
1999
2180
|
this.subscribedToBroadcastChannel = false;
|
|
2000
2181
|
}
|
|
2001
2182
|
}
|
|
2002
2183
|
broadcast(Message, args) {
|
|
2003
|
-
if (!this.
|
|
2184
|
+
if (!this.configuration.broadcast) {
|
|
2004
2185
|
return;
|
|
2005
2186
|
}
|
|
2006
2187
|
if (!this.subscribedToBroadcastChannel) {
|
|
@@ -2008,16 +2189,25 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
2008
2189
|
}
|
|
2009
2190
|
new MessageSender(Message, args).broadcast(this.broadcastChannel);
|
|
2010
2191
|
}
|
|
2011
|
-
log(message) {
|
|
2012
|
-
if (!this.options.debug) {
|
|
2013
|
-
return;
|
|
2014
|
-
}
|
|
2015
|
-
console.log(message);
|
|
2016
|
-
}
|
|
2017
2192
|
setAwarenessField(key, value) {
|
|
2018
2193
|
this.awareness.setLocalStateField(key, value);
|
|
2019
2194
|
}
|
|
2020
2195
|
}
|
|
2021
2196
|
|
|
2022
|
-
|
|
2197
|
+
class HocuspocusCloudProvider extends HocuspocusProvider {
|
|
2198
|
+
constructor(configuration) {
|
|
2199
|
+
if (!configuration.url) {
|
|
2200
|
+
configuration.url = 'wss://connect.hocuspocus.cloud';
|
|
2201
|
+
}
|
|
2202
|
+
if (configuration.key) {
|
|
2203
|
+
if (!configuration.parameters) {
|
|
2204
|
+
configuration.parameters = {};
|
|
2205
|
+
}
|
|
2206
|
+
configuration.parameters.key = configuration.key;
|
|
2207
|
+
}
|
|
2208
|
+
super(configuration);
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
|
|
2212
|
+
export { HocuspocusCloudProvider, HocuspocusProvider, MessageType, WebSocketStatus };
|
|
2023
2213
|
//# sourceMappingURL=hocuspocus-provider.esm.js.map
|