@hocuspocus/provider 2.3.1 → 2.4.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,8 +21,13 @@ export interface CompleteHocuspocusProviderConfiguration {
21
21
  broadcast: boolean;
22
22
  /**
23
23
  * An Awareness instance to keep the presence state of all clients.
24
+ *
25
+ * You can disable sharing awareness information by passing `null`.
26
+ * Note that having no awareness information shared across all connections will break our ping checks
27
+ * and thus trigger reconnects. You should always have at least one Provider with enabled awareness per
28
+ * socket connection, or ensure that the Provider receives messages before running into `HocuspocusProviderWebsocket.messageReconnectTimeout`.
24
29
  */
25
- awareness: Awareness;
30
+ awareness: Awareness | null;
26
31
  /**
27
32
  * A token that’s sent to the backend for authentication purposes.
28
33
  */
@@ -68,6 +73,9 @@ export interface CompleteHocuspocusProviderConfiguration {
68
73
  */
69
74
  preserveConnection: boolean;
70
75
  }
76
+ export declare class AwarenessError extends Error {
77
+ code: number;
78
+ }
71
79
  export declare class HocuspocusProvider extends EventEmitter {
72
80
  configuration: CompleteHocuspocusProviderConfiguration;
73
81
  subscribedToBroadcastChannel: boolean;
@@ -94,7 +102,7 @@ export declare class HocuspocusProvider extends EventEmitter {
94
102
  onStatus({ status }: onStatusParameters): void;
95
103
  setConfiguration(configuration?: Partial<HocuspocusProviderConfiguration>): void;
96
104
  get document(): Y.Doc;
97
- get awareness(): Awareness;
105
+ get awareness(): Awareness | null;
98
106
  get hasUnsyncedChanges(): boolean;
99
107
  incrementUnsyncedChanges(): void;
100
108
  decrementUnsyncedChanges(): void;
@@ -24,7 +24,7 @@ export declare class Document extends Doc {
24
24
  */
25
25
  constructor(name: string, logger: Debugger, yDocOptions: {});
26
26
  /**
27
- * Check if the Document is empty
27
+ * Check if the Document (XMLFragment or Map) is empty
28
28
  */
29
29
  isEmpty(fieldName: string): boolean;
30
30
  /**
@@ -7,10 +7,13 @@ export declare class IncomingMessage {
7
7
  */
8
8
  decoder: Decoder;
9
9
  /**
10
- * Access to the reply.
10
+ * Private encoder; can be undefined.
11
+ *
12
+ * Lazy creation of the encoder speeds up IncomingMessages that need only a decoder.
11
13
  */
12
- encoder: Encoder;
14
+ private encoderInternal?;
13
15
  constructor(input: any);
16
+ get encoder(): Encoder;
14
17
  readVarUint8Array(): Uint8Array;
15
18
  readVarUint(): number;
16
19
  readVarString(): string;
@@ -31,6 +31,7 @@ export interface ConnectionConfiguration {
31
31
  }
32
32
  export interface Extension {
33
33
  priority?: number;
34
+ extensionName?: string;
34
35
  onConfigure?(data: onConfigurePayload): Promise<any>;
35
36
  onListen?(data: onListenPayload): Promise<any>;
36
37
  onUpgrade?(data: onUpgradePayload): Promise<any>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hocuspocus/provider",
3
- "version": "2.3.1",
3
+ "version": "2.4.0-rc.1",
4
4
  "description": "hocuspocus provider",
5
5
  "homepage": "https://hocuspocus.dev",
6
6
  "keywords": [
@@ -29,7 +29,7 @@
29
29
  "dist"
30
30
  ],
31
31
  "dependencies": {
32
- "@hocuspocus/common": "^2.3.1",
32
+ "@hocuspocus/common": "^2.4.0-rc.1",
33
33
  "@lifeomic/attempt": "^3.0.2",
34
34
  "lib0": "^0.2.47",
35
35
  "ws": "^7.5.9"
@@ -58,8 +58,13 @@ export interface CompleteHocuspocusProviderConfiguration {
58
58
  broadcast: boolean,
59
59
  /**
60
60
  * An Awareness instance to keep the presence state of all clients.
61
+ *
62
+ * You can disable sharing awareness information by passing `null`.
63
+ * Note that having no awareness information shared across all connections will break our ping checks
64
+ * and thus trigger reconnects. You should always have at least one Provider with enabled awareness per
65
+ * socket connection, or ensure that the Provider receives messages before running into `HocuspocusProviderWebsocket.messageReconnectTimeout`.
61
66
  */
62
- awareness: Awareness,
67
+ awareness: Awareness | null,
63
68
  /**
64
69
  * A token that’s sent to the backend for authentication purposes.
65
70
  */
@@ -108,6 +113,10 @@ export interface CompleteHocuspocusProviderConfiguration {
108
113
  preserveConnection: boolean,
109
114
  }
110
115
 
116
+ export class AwarenessError extends Error {
117
+ code = 1001
118
+ }
119
+
111
120
  export class HocuspocusProvider extends EventEmitter {
112
121
  public configuration: CompleteHocuspocusProviderConfiguration = {
113
122
  name: '',
@@ -163,7 +172,7 @@ export class HocuspocusProvider extends EventEmitter {
163
172
  this.setConfiguration(configuration)
164
173
 
165
174
  this.configuration.document = configuration.document ? configuration.document : new Y.Doc()
166
- this.configuration.awareness = configuration.awareness ? configuration.awareness : new Awareness(this.document)
175
+ this.configuration.awareness = configuration.awareness !== undefined ? configuration.awareness : new Awareness(this.document)
167
176
 
168
177
  this.on('open', this.configuration.onOpen)
169
178
  this.on('message', this.configuration.onMessage)
@@ -197,16 +206,16 @@ export class HocuspocusProvider extends EventEmitter {
197
206
  this.configuration.websocketProvider.on('destroy', this.configuration.onDestroy)
198
207
  this.configuration.websocketProvider.on('destroy', this.forwardDestroy)
199
208
 
200
- this.awareness.on('update', () => {
201
- this.emit('awarenessUpdate', { states: awarenessStatesToArray(this.awareness.getStates()) })
209
+ this.awareness?.on('update', () => {
210
+ this.emit('awarenessUpdate', { states: awarenessStatesToArray(this.awareness!.getStates()) })
202
211
  })
203
212
 
204
- this.awareness.on('change', () => {
205
- this.emit('awarenessChange', { states: awarenessStatesToArray(this.awareness.getStates()) })
213
+ this.awareness?.on('change', () => {
214
+ this.emit('awarenessChange', { states: awarenessStatesToArray(this.awareness!.getStates()) })
206
215
  })
207
216
 
208
217
  this.document.on('update', this.documentUpdateHandler.bind(this))
209
- this.awareness.on('update', this.awarenessUpdateHandler.bind(this))
218
+ this.awareness?.on('update', this.awarenessUpdateHandler.bind(this))
210
219
  this.registerEventListeners()
211
220
 
212
221
  if (this.configuration.forceSyncInterval) {
@@ -292,7 +301,9 @@ export class HocuspocusProvider extends EventEmitter {
292
301
  }
293
302
 
294
303
  pageUnload() {
295
- removeAwarenessStates(this.awareness, [this.document.clientID], 'window unload')
304
+ if (this.awareness) {
305
+ removeAwarenessStates(this.awareness, [this.document.clientID], 'window unload')
306
+ }
296
307
  }
297
308
 
298
309
  registerEventListeners() {
@@ -395,7 +406,7 @@ export class HocuspocusProvider extends EventEmitter {
395
406
  this.incrementUnsyncedChanges()
396
407
  this.send(SyncStepOneMessage, { document: this.document, documentName: this.configuration.name })
397
408
 
398
- if (this.awareness.getLocalState() !== null) {
409
+ if (this.awareness && this.awareness.getLocalState() !== null) {
399
410
  this.send(AwarenessMessage, {
400
411
  awareness: this.awareness,
401
412
  clients: [this.document.clientID],
@@ -440,11 +451,13 @@ export class HocuspocusProvider extends EventEmitter {
440
451
  this.synced = false
441
452
 
442
453
  // update awareness (all users except local left)
443
- removeAwarenessStates(
444
- this.awareness,
445
- Array.from(this.awareness.getStates().keys()).filter(client => client !== this.document.clientID),
446
- this,
447
- )
454
+ if (this.awareness) {
455
+ removeAwarenessStates(
456
+ this.awareness,
457
+ Array.from(this.awareness.getStates().keys()).filter(client => client !== this.document.clientID),
458
+ this,
459
+ )
460
+ }
448
461
  }
449
462
 
450
463
  destroy() {
@@ -454,11 +467,13 @@ export class HocuspocusProvider extends EventEmitter {
454
467
  clearInterval(this.intervals.forceSync)
455
468
  }
456
469
 
457
- removeAwarenessStates(this.awareness, [this.document.clientID], 'provider destroy')
470
+ if (this.awareness) {
471
+ removeAwarenessStates(this.awareness, [this.document.clientID], 'provider destroy')
472
+ }
458
473
 
459
474
  this.disconnect()
460
475
 
461
- this.awareness.off('update', this.awarenessUpdateHandler)
476
+ this.awareness?.off('update', this.awarenessUpdateHandler)
462
477
  this.document.off('update', this.documentUpdateHandler)
463
478
 
464
479
  this.removeAllListeners()
@@ -530,18 +545,22 @@ export class HocuspocusProvider extends EventEmitter {
530
545
  this.broadcast(SyncStepOneMessage, { document: this.document })
531
546
  this.broadcast(SyncStepTwoMessage, { document: this.document })
532
547
  this.broadcast(QueryAwarenessMessage, { document: this.document })
533
- this.broadcast(AwarenessMessage, { awareness: this.awareness, clients: [this.document.clientID], document: this.document })
548
+ if (this.awareness) {
549
+ this.broadcast(AwarenessMessage, { awareness: this.awareness, clients: [this.document.clientID], document: this.document })
550
+ }
534
551
  })
535
552
  }
536
553
 
537
554
  disconnectBroadcastChannel() {
538
555
  // broadcast message with local awareness state set to null (indicating disconnect)
539
- this.send(AwarenessMessage, {
540
- awareness: this.awareness,
541
- clients: [this.document.clientID],
542
- states: new Map(),
543
- documentName: this.configuration.name,
544
- }, true)
556
+ if (this.awareness) {
557
+ this.send(AwarenessMessage, {
558
+ awareness: this.awareness,
559
+ clients: [this.document.clientID],
560
+ states: new Map(),
561
+ documentName: this.configuration.name,
562
+ }, true)
563
+ }
545
564
 
546
565
  if (this.subscribedToBroadcastChannel) {
547
566
  bc.unsubscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber)
@@ -562,6 +581,9 @@ export class HocuspocusProvider extends EventEmitter {
562
581
  }
563
582
 
564
583
  setAwarenessField(key: string, value: any) {
584
+ if (!this.awareness) {
585
+ throw new AwarenessError(`Cannot set awareness field "${key}" to ${JSON.stringify(value)}. You have disabled Awareness for this provider by explicitly passing awareness: null in the provider configuration.`)
586
+ }
565
587
  this.awareness.setLocalStateField(key, value)
566
588
  }
567
589
  }
@@ -98,8 +98,6 @@ export class HocuspocusProviderWebsocket extends EventEmitter {
98
98
  url: '',
99
99
  // @ts-ignore
100
100
  document: undefined,
101
- // @ts-ignore
102
- awareness: undefined,
103
101
  WebSocketPolyfill: undefined,
104
102
  parameters: {},
105
103
  connect: true,
@@ -358,7 +356,7 @@ export class HocuspocusProviderWebsocket extends EventEmitter {
358
356
  return
359
357
  }
360
358
 
361
- // Don’t close then connection while waiting for the first message
359
+ // Don’t close the connection while waiting for the first message
362
360
  if (!this.lastMessageReceived) {
363
361
  return
364
362
  }
@@ -369,7 +367,8 @@ export class HocuspocusProviderWebsocket extends EventEmitter {
369
367
  }
370
368
 
371
369
  // No message received in a long time, not even your own
372
- // Awareness updates, which are updated every 15 seconds.
370
+ // Awareness updates, which are updated every 15 seconds
371
+ // if awareness is enabled.
373
372
  this.closeTries += 1
374
373
  // https://bugs.webkit.org/show_bug.cgi?id=247943
375
374
  if (this.closeTries > 2) {
@@ -97,6 +97,8 @@ export class MessageReceiver {
97
97
  }
98
98
 
99
99
  private applyAwarenessMessage(provider: HocuspocusProvider) {
100
+ if (!provider.awareness) return
101
+
100
102
  const { message } = this
101
103
 
102
104
  awarenessProtocol.applyAwarenessUpdate(
@@ -117,6 +119,8 @@ export class MessageReceiver {
117
119
  }
118
120
 
119
121
  private applyQueryAwarenessMessage(provider: HocuspocusProvider) {
122
+ if (!provider.awareness) return
123
+
120
124
  const { message } = this
121
125
 
122
126
  message.writeVarUint(MessageType.Awareness)