@hocuspocus/provider 2.15.2 → 3.0.4-rc.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.
Files changed (70) hide show
  1. package/dist/hocuspocus-provider.cjs +931 -1532
  2. package/dist/hocuspocus-provider.cjs.map +1 -1
  3. package/dist/hocuspocus-provider.esm.js +931 -1527
  4. package/dist/hocuspocus-provider.esm.js.map +1 -1
  5. package/dist/packages/extension-database/src/Database.d.ts +1 -1
  6. package/dist/packages/extension-logger/src/Logger.d.ts +1 -1
  7. package/dist/packages/extension-redis/src/Redis.d.ts +4 -3
  8. package/dist/packages/extension-sqlite/src/SQLite.d.ts +2 -1
  9. package/dist/packages/extension-throttle/src/index.d.ts +2 -2
  10. package/dist/packages/extension-webhook/src/index.d.ts +3 -3
  11. package/dist/packages/provider/src/HocuspocusProvider.d.ts +12 -45
  12. package/dist/packages/provider/src/HocuspocusProviderWebsocket.d.ts +5 -9
  13. package/dist/packages/provider/src/IncomingMessage.d.ts +3 -3
  14. package/dist/packages/provider/src/MessageReceiver.d.ts +2 -4
  15. package/dist/packages/provider/src/MessageSender.d.ts +2 -2
  16. package/dist/packages/provider/src/OutgoingMessage.d.ts +2 -2
  17. package/dist/packages/provider/src/OutgoingMessages/AuthenticationMessage.d.ts +2 -1
  18. package/dist/packages/provider/src/OutgoingMessages/AwarenessMessage.d.ts +2 -1
  19. package/dist/packages/provider/src/OutgoingMessages/CloseMessage.d.ts +2 -1
  20. package/dist/packages/provider/src/OutgoingMessages/QueryAwarenessMessage.d.ts +2 -1
  21. package/dist/packages/provider/src/OutgoingMessages/StatelessMessage.d.ts +2 -1
  22. package/dist/packages/provider/src/OutgoingMessages/SyncStepOneMessage.d.ts +2 -1
  23. package/dist/packages/provider/src/OutgoingMessages/SyncStepTwoMessage.d.ts +2 -1
  24. package/dist/packages/provider/src/OutgoingMessages/UpdateMessage.d.ts +2 -1
  25. package/dist/packages/provider/src/index.d.ts +0 -2
  26. package/dist/packages/provider/src/types.d.ts +12 -12
  27. package/dist/packages/server/src/ClientConnection.d.ts +19 -10
  28. package/dist/packages/server/src/Connection.d.ts +7 -23
  29. package/dist/packages/server/src/DirectConnection.d.ts +2 -2
  30. package/dist/packages/server/src/Document.d.ts +3 -7
  31. package/dist/packages/server/src/Hocuspocus.d.ts +7 -36
  32. package/dist/packages/server/src/IncomingMessage.d.ts +3 -3
  33. package/dist/packages/server/src/MessageReceiver.d.ts +4 -6
  34. package/dist/packages/server/src/OutgoingMessage.d.ts +4 -3
  35. package/dist/packages/server/src/Server.d.ts +23 -3
  36. package/dist/packages/server/src/index.d.ts +1 -1
  37. package/dist/packages/server/src/types.d.ts +15 -29
  38. package/dist/packages/server/src/util/getParameters.d.ts +1 -1
  39. package/dist/packages/transformer/src/Prosemirror.d.ts +1 -1
  40. package/dist/packages/transformer/src/Tiptap.d.ts +3 -3
  41. package/dist/packages/transformer/src/types.d.ts +1 -1
  42. package/dist/tests/utils/newHocuspocus.d.ts +2 -2
  43. package/dist/tests/utils/newHocuspocusProvider.d.ts +2 -2
  44. package/dist/tests/utils/newHocuspocusProviderWebsocket.d.ts +4 -3
  45. package/dist/tests/utils/retryableAssertion.d.ts +1 -1
  46. package/package.json +2 -2
  47. package/src/EventEmitter.ts +3 -1
  48. package/src/HocuspocusProvider.ts +74 -200
  49. package/src/HocuspocusProviderWebsocket.ts +24 -75
  50. package/src/IncomingMessage.ts +5 -3
  51. package/src/MessageReceiver.ts +20 -19
  52. package/src/MessageSender.ts +3 -2
  53. package/src/OutgoingMessage.ts +3 -2
  54. package/src/OutgoingMessages/AuthenticationMessage.ts +2 -1
  55. package/src/OutgoingMessages/AwarenessMessage.ts +2 -1
  56. package/src/OutgoingMessages/CloseMessage.ts +2 -1
  57. package/src/OutgoingMessages/QueryAwarenessMessage.ts +2 -1
  58. package/src/OutgoingMessages/StatelessMessage.ts +2 -1
  59. package/src/OutgoingMessages/SyncStepOneMessage.ts +2 -1
  60. package/src/OutgoingMessages/SyncStepTwoMessage.ts +2 -1
  61. package/src/OutgoingMessages/UpdateMessage.ts +2 -1
  62. package/src/index.ts +0 -2
  63. package/src/types.ts +12 -12
  64. package/dist/packages/provider/src/TiptapCollabProvider.d.ts +0 -161
  65. package/dist/packages/provider/src/TiptapCollabProviderWebsocket.d.ts +0 -19
  66. package/dist/packages/server/src/Debugger.d.ts +0 -14
  67. package/dist/tests/server/getMessageLogs.d.ts +0 -1
  68. package/dist/tests/server/requiresAuthentication.d.ts +0 -1
  69. package/src/TiptapCollabProvider.ts +0 -505
  70. package/src/TiptapCollabProviderWebsocket.ts +0 -38
@@ -1,12 +1,11 @@
1
1
  import { awarenessStatesToArray } from '@hocuspocus/common'
2
- import * as bc from 'lib0/broadcastchannel'
3
- import * as mutex from 'lib0/mutex'
4
- import type { CloseEvent, Event, MessageEvent } from 'ws'
2
+ import type { Event, MessageEvent } from 'ws'
5
3
  import { Awareness, removeAwarenessStates } from 'y-protocols/awareness'
6
4
  import * as Y from 'yjs'
7
5
  import EventEmitter from './EventEmitter.js'
6
+ import type {
7
+ CompleteHocuspocusProviderWebsocketConfiguration} from './HocuspocusProviderWebsocket.js'
8
8
  import {
9
- CompleteHocuspocusProviderWebsocketConfiguration,
10
9
  HocuspocusProviderWebsocket,
11
10
  } from './HocuspocusProviderWebsocket.js'
12
11
  import { IncomingMessage } from './IncomingMessage.js'
@@ -14,15 +13,11 @@ import { MessageReceiver } from './MessageReceiver.js'
14
13
  import { MessageSender } from './MessageSender.js'
15
14
  import { AuthenticationMessage } from './OutgoingMessages/AuthenticationMessage.js'
16
15
  import { AwarenessMessage } from './OutgoingMessages/AwarenessMessage.js'
17
- import { CloseMessage } from './OutgoingMessages/CloseMessage.js'
18
- import { QueryAwarenessMessage } from './OutgoingMessages/QueryAwarenessMessage.js'
19
16
  import { StatelessMessage } from './OutgoingMessages/StatelessMessage.js'
20
17
  import { SyncStepOneMessage } from './OutgoingMessages/SyncStepOneMessage.js'
21
- import { SyncStepTwoMessage } from './OutgoingMessages/SyncStepTwoMessage.js'
22
18
  import { UpdateMessage } from './OutgoingMessages/UpdateMessage.js'
23
- import {
19
+ import type {
24
20
  ConstructableOutgoingMessage,
25
- WebSocketStatus,
26
21
  onAuthenticationFailedParameters,
27
22
  onAwarenessChangeParameters,
28
23
  onAwarenessUpdateParameters,
@@ -31,7 +26,6 @@ import {
31
26
  onMessageParameters,
32
27
  onOpenParameters,
33
28
  onOutgoingMessageParameters, onStatelessParameters,
34
- onStatusParameters,
35
29
  onSyncedParameters,
36
30
  } from './types.js'
37
31
 
@@ -52,10 +46,6 @@ export interface CompleteHocuspocusProviderConfiguration {
52
46
  */
53
47
  document: Y.Doc,
54
48
 
55
- /**
56
- * Pass false to disable broadcasting between browser tabs.
57
- */
58
- broadcast: boolean,
59
49
  /**
60
50
  * An Awareness instance to keep the presence state of all clients.
61
51
  *
@@ -65,18 +55,17 @@ export interface CompleteHocuspocusProviderConfiguration {
65
55
  * socket connection, or ensure that the Provider receives messages before running into `HocuspocusProviderWebsocket.messageReconnectTimeout`.
66
56
  */
67
57
  awareness: Awareness | null,
58
+
68
59
  /**
69
60
  * A token that’s sent to the backend for authentication purposes.
70
61
  */
71
62
  token: string | (() => string) | (() => Promise<string>) | null,
72
- /**
73
- * URL parameters that should be added.
74
- */
75
- parameters: { [key: string]: any },
63
+
76
64
  /**
77
65
  * Hocuspocus websocket provider
78
66
  */
79
67
  websocketProvider: HocuspocusProviderWebsocket,
68
+
80
69
  /**
81
70
  * Force syncing the document in the defined interval.
82
71
  */
@@ -88,7 +77,6 @@ export interface CompleteHocuspocusProviderConfiguration {
88
77
  onConnect: () => void,
89
78
  onMessage: (data: onMessageParameters) => void,
90
79
  onOutgoingMessage: (data: onOutgoingMessageParameters) => void,
91
- onStatus: (data: onStatusParameters) => void,
92
80
  onSynced: (data: onSyncedParameters) => void,
93
81
  onDisconnect: (data: onDisconnectParameters) => void,
94
82
  onClose: (data: onCloseParameters) => void,
@@ -96,21 +84,6 @@ export interface CompleteHocuspocusProviderConfiguration {
96
84
  onAwarenessUpdate: (data: onAwarenessUpdateParameters) => void,
97
85
  onAwarenessChange: (data: onAwarenessChangeParameters) => void,
98
86
  onStateless: (data: onStatelessParameters) => void
99
-
100
- /**
101
- * Don’t output any warnings.
102
- */
103
- quiet: boolean,
104
-
105
- /**
106
- * Pass `false` to start the connection manually.
107
- */
108
- connect: boolean,
109
-
110
- /**
111
- * Pass `false` to close the connection manually.
112
- */
113
- preserveConnection: boolean,
114
87
  }
115
88
 
116
89
  export class AwarenessError extends Error {
@@ -125,8 +98,6 @@ export class HocuspocusProvider extends EventEmitter {
125
98
  // @ts-ignore
126
99
  awareness: undefined,
127
100
  token: null,
128
- parameters: {},
129
- broadcast: true,
130
101
  forceSyncInterval: false,
131
102
  onAuthenticated: () => null,
132
103
  onAuthenticationFailed: () => null,
@@ -134,7 +105,6 @@ export class HocuspocusProvider extends EventEmitter {
134
105
  onConnect: () => null,
135
106
  onMessage: () => null,
136
107
  onOutgoingMessage: () => null,
137
- onStatus: () => null,
138
108
  onSynced: () => null,
139
109
  onDisconnect: () => null,
140
110
  onClose: () => null,
@@ -142,31 +112,25 @@ export class HocuspocusProvider extends EventEmitter {
142
112
  onAwarenessUpdate: () => null,
143
113
  onAwarenessChange: () => null,
144
114
  onStateless: () => null,
145
- quiet: false,
146
- connect: true,
147
- preserveConnection: true,
148
115
  }
149
116
 
150
- subscribedToBroadcastChannel = false
151
-
152
117
  isSynced = false
153
118
 
154
119
  unsyncedChanges = 0
155
120
 
156
- status = WebSocketStatus.Disconnected
157
-
158
121
  isAuthenticated = false
159
122
 
160
123
  authorizedScope: string | undefined = undefined
161
124
 
162
- mux = mutex.createMutex()
125
+ // @internal
126
+ manageSocket = false
127
+
128
+ private isAttached = false
163
129
 
164
130
  intervals: any = {
165
131
  forceSync: null,
166
132
  }
167
133
 
168
- isConnected = true
169
-
170
134
  constructor(configuration: HocuspocusProviderConfiguration) {
171
135
  super()
172
136
  this.setConfiguration(configuration)
@@ -186,24 +150,6 @@ export class HocuspocusProvider extends EventEmitter {
186
150
  this.on('authenticated', this.configuration.onAuthenticated)
187
151
  this.on('authenticationFailed', this.configuration.onAuthenticationFailed)
188
152
 
189
- this.configuration.websocketProvider.on('connect', this.configuration.onConnect)
190
- this.configuration.websocketProvider.on('connect', this.forwardConnect)
191
-
192
- this.configuration.websocketProvider.on('open', this.boundOnOpen)
193
- this.configuration.websocketProvider.on('open', this.forwardOpen)
194
-
195
- this.configuration.websocketProvider.on('close', this.boundOnClose)
196
- this.configuration.websocketProvider.on('close', this.configuration.onClose)
197
- this.configuration.websocketProvider.on('close', this.forwardClose)
198
-
199
- this.configuration.websocketProvider.on('status', this.boundOnStatus)
200
-
201
- this.configuration.websocketProvider.on('disconnect', this.configuration.onDisconnect)
202
- this.configuration.websocketProvider.on('disconnect', this.forwardDisconnect)
203
-
204
- this.configuration.websocketProvider.on('destroy', this.configuration.onDestroy)
205
- this.configuration.websocketProvider.on('destroy', this.forwardDestroy)
206
-
207
153
  this.awareness?.on('update', () => {
208
154
  this.emit('awarenessUpdate', { states: awarenessStatesToArray(this.awareness!.getStates()) })
209
155
  })
@@ -214,6 +160,7 @@ export class HocuspocusProvider extends EventEmitter {
214
160
 
215
161
  this.document.on('update', this.boundDocumentUpdateHandler)
216
162
  this.awareness?.on('update', this.boundAwarenessUpdateHandler)
163
+
217
164
  this.registerEventListeners()
218
165
 
219
166
  if (
@@ -226,26 +173,24 @@ export class HocuspocusProvider extends EventEmitter {
226
173
  )
227
174
  }
228
175
 
229
- this.configuration.websocketProvider.attach(this)
176
+ if( this.manageSocket ) {
177
+ this.attach()
178
+ }
230
179
  }
231
180
 
232
181
  boundDocumentUpdateHandler = this.documentUpdateHandler.bind(this)
233
182
 
234
183
  boundAwarenessUpdateHandler = this.awarenessUpdateHandler.bind(this)
235
184
 
236
- boundBroadcastChannelSubscriber = this.broadcastChannelSubscriber.bind(this)
237
-
238
185
  boundPageHide = this.pageHide.bind(this)
239
186
 
240
187
  boundOnOpen = this.onOpen.bind(this)
241
188
 
242
189
  boundOnClose = this.onClose.bind(this)
243
190
 
244
- boundOnStatus = this.onStatus.bind(this)
245
-
246
191
  forwardConnect = (e: any) => this.emit('connect', e)
247
192
 
248
- forwardOpen = (e: any) => this.emit('open', e)
193
+ // forwardOpen = (e: any) => this.emit('open', e)
249
194
 
250
195
  forwardClose = (e: any) => this.emit('close', e)
251
196
 
@@ -253,21 +198,12 @@ export class HocuspocusProvider extends EventEmitter {
253
198
 
254
199
  forwardDestroy = (e: any) => this.emit('destroy', e)
255
200
 
256
- public onStatus({ status } : onStatusParameters) {
257
- this.status = status
258
-
259
- this.configuration.onStatus({ status })
260
- this.emit('status', { status })
261
- }
262
-
263
201
  public setConfiguration(configuration: Partial<HocuspocusProviderConfiguration> = {}): void {
264
- if (!configuration.websocketProvider && (configuration as CompleteHocuspocusProviderWebsocketConfiguration).url) {
202
+ if (!configuration.websocketProvider) {
265
203
  const websocketProviderConfig = configuration as CompleteHocuspocusProviderWebsocketConfiguration
266
-
204
+ this.manageSocket = true
267
205
  this.configuration.websocketProvider = new HocuspocusProviderWebsocket({
268
206
  url: websocketProviderConfig.url,
269
- connect: websocketProviderConfig.connect,
270
- parameters: websocketProviderConfig.parameters,
271
207
  })
272
208
  }
273
209
 
@@ -297,10 +233,14 @@ export class HocuspocusProvider extends EventEmitter {
297
233
  }
298
234
 
299
235
  decrementUnsyncedChanges() {
300
- this.unsyncedChanges -= 1
236
+ if( this.unsyncedChanges > 0 ) {
237
+ this.unsyncedChanges -= 1
238
+ }
239
+
301
240
  if (this.unsyncedChanges === 0) {
302
241
  this.synced = true
303
242
  }
243
+
304
244
  this.emit('unsyncedChanges', this.unsyncedChanges)
305
245
  }
306
246
 
@@ -334,7 +274,7 @@ export class HocuspocusProvider extends EventEmitter {
334
274
  }
335
275
 
336
276
  this.incrementUnsyncedChanges()
337
- this.send(UpdateMessage, { update, documentName: this.configuration.name }, true)
277
+ this.send(UpdateMessage, { update, documentName: this.configuration.name })
338
278
  }
339
279
 
340
280
  awarenessUpdateHandler({ added, updated, removed }: any, origin: any) {
@@ -344,7 +284,7 @@ export class HocuspocusProvider extends EventEmitter {
344
284
  awareness: this.awareness,
345
285
  clients: changedClients,
346
286
  documentName: this.configuration.name,
347
- }, true)
287
+ })
348
288
  }
349
289
 
350
290
  /**
@@ -363,43 +303,27 @@ export class HocuspocusProvider extends EventEmitter {
363
303
  }
364
304
 
365
305
  this.isSynced = state
366
- this.emit('synced', { state })
367
- this.emit('sync', { state })
306
+
307
+ if( state ) {
308
+ this.emit('synced', { state })
309
+ }
368
310
  }
369
311
 
370
312
  receiveStateless(payload: string) {
371
313
  this.emit('stateless', { payload })
372
314
  }
373
315
 
374
- get isAuthenticationRequired(): boolean {
375
- return !!this.configuration.token && !this.isAuthenticated
376
- }
377
-
378
316
  // not needed, but provides backward compatibility with e.g. lexical/yjs
379
317
  async connect() {
380
- if (this.configuration.broadcast) {
381
- this.subscribeToBroadcastChannel()
382
- }
383
-
384
- this.configuration.websocketProvider.shouldConnect = true
385
-
386
- return this.configuration.websocketProvider.attach(this)
318
+ console.warn('HocuspocusProvider::connect() is deprecated and does not do anything. Please connect/disconnect on the websocketProvider, or attach/deattach providers.')
387
319
  }
388
320
 
389
321
  disconnect() {
390
- this.disconnectBroadcastChannel()
391
- this.configuration.websocketProvider.detach(this)
392
- this.isConnected = false
393
-
394
- if (!this.configuration.preserveConnection) {
395
- this.configuration.websocketProvider.disconnect()
396
- }
397
-
322
+ console.warn('HocuspocusProvider::disconnect() is deprecated and does not do anything. Please connect/disconnect on the websocketProvider, or attach/deattach providers.')
398
323
  }
399
324
 
400
325
  async onOpen(event: Event) {
401
326
  this.isAuthenticated = false
402
- this.isConnected = true
403
327
 
404
328
  this.emit('open', { event })
405
329
 
@@ -411,12 +335,10 @@ export class HocuspocusProvider extends EventEmitter {
411
335
  return
412
336
  }
413
337
 
414
- if (this.isAuthenticationRequired) {
415
- this.send(AuthenticationMessage, {
416
- token,
417
- documentName: this.configuration.name,
418
- })
419
- }
338
+ this.send(AuthenticationMessage, {
339
+ token: token ?? '',
340
+ documentName: this.configuration.name,
341
+ })
420
342
 
421
343
  this.startSync()
422
344
  }
@@ -444,15 +366,7 @@ export class HocuspocusProvider extends EventEmitter {
444
366
  }
445
367
  }
446
368
 
447
- send(message: ConstructableOutgoingMessage, args: any, broadcast = false) {
448
- if (!this.isConnected) {
449
- return
450
- }
451
-
452
- if (broadcast) {
453
- this.mux(() => { this.broadcast(message, args) })
454
- }
455
-
369
+ send(message: ConstructableOutgoingMessage, args: any) {
456
370
  const messageSender = new MessageSender(message, args)
457
371
 
458
372
  this.emit('outgoingMessage', { message: messageSender.message })
@@ -471,7 +385,7 @@ export class HocuspocusProvider extends EventEmitter {
471
385
  new MessageReceiver(message).apply(this, true)
472
386
  }
473
387
 
474
- onClose(event: CloseEvent) {
388
+ onClose() {
475
389
  this.isAuthenticated = false
476
390
  this.synced = false
477
391
 
@@ -502,109 +416,69 @@ export class HocuspocusProvider extends EventEmitter {
502
416
 
503
417
  this.removeAllListeners()
504
418
 
419
+ this.detach()
420
+
421
+ if( this.manageSocket ) {
422
+ this.configuration.websocketProvider.destroy()
423
+ }
424
+
425
+ if (typeof window === 'undefined' || !('removeEventListener' in window)) {
426
+ return
427
+ }
428
+
429
+ window.removeEventListener('pagehide', this.boundPageHide)
430
+ }
431
+
432
+ detach() {
505
433
  this.configuration.websocketProvider.off('connect', this.configuration.onConnect)
506
434
  this.configuration.websocketProvider.off('connect', this.forwardConnect)
507
435
  this.configuration.websocketProvider.off('open', this.boundOnOpen)
508
- this.configuration.websocketProvider.off('open', this.forwardOpen)
509
436
  this.configuration.websocketProvider.off('close', this.boundOnClose)
510
437
  this.configuration.websocketProvider.off('close', this.configuration.onClose)
511
438
  this.configuration.websocketProvider.off('close', this.forwardClose)
512
- this.configuration.websocketProvider.off('status', this.boundOnStatus)
513
439
  this.configuration.websocketProvider.off('disconnect', this.configuration.onDisconnect)
514
440
  this.configuration.websocketProvider.off('disconnect', this.forwardDisconnect)
515
441
  this.configuration.websocketProvider.off('destroy', this.configuration.onDestroy)
516
442
  this.configuration.websocketProvider.off('destroy', this.forwardDestroy)
517
443
 
518
- this.send(CloseMessage, { documentName: this.configuration.name })
519
- this.disconnect()
520
-
521
- if (typeof window === 'undefined' || !('removeEventListener' in window)) {
522
- return
523
- }
524
-
525
- window.removeEventListener('pagehide', this.boundPageHide)
526
- }
444
+ this.configuration.websocketProvider.detach(this)
527
445
 
528
- permissionDeniedHandler(reason: string) {
529
- this.emit('authenticationFailed', { reason })
530
- this.isAuthenticated = false
531
- this.disconnect()
532
- this.status = WebSocketStatus.Disconnected
446
+ this.isAttached = false
533
447
  }
534
448
 
535
- authenticatedHandler(scope: string) {
536
- this.isAuthenticated = true
537
- this.authorizedScope = scope
538
-
539
- this.emit('authenticated')
540
- }
449
+ attach() {
450
+ if( this.isAttached ) return
541
451
 
542
- get broadcastChannel() {
543
- return `${this.configuration.name}`
544
- }
452
+ this.configuration.websocketProvider.on('connect', this.configuration.onConnect)
453
+ this.configuration.websocketProvider.on('connect', this.forwardConnect)
545
454
 
546
- broadcastChannelSubscriber(data: ArrayBuffer) {
547
- this.mux(() => {
548
- const message = new IncomingMessage(data)
455
+ this.configuration.websocketProvider.on('open', this.boundOnOpen)
549
456
 
550
- const documentName = message.readVarString()
457
+ this.configuration.websocketProvider.on('close', this.boundOnClose)
458
+ this.configuration.websocketProvider.on('close', this.configuration.onClose)
459
+ this.configuration.websocketProvider.on('close', this.forwardClose)
551
460
 
552
- message.writeVarString(documentName)
461
+ this.configuration.websocketProvider.on('disconnect', this.configuration.onDisconnect)
462
+ this.configuration.websocketProvider.on('disconnect', this.forwardDisconnect)
553
463
 
554
- new MessageReceiver(message)
555
- .setBroadcasted(true)
556
- .apply(this, false)
557
- })
558
- }
464
+ this.configuration.websocketProvider.on('destroy', this.configuration.onDestroy)
465
+ this.configuration.websocketProvider.on('destroy', this.forwardDestroy)
559
466
 
560
- subscribeToBroadcastChannel() {
561
- if (!this.subscribedToBroadcastChannel) {
562
- bc.subscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber)
563
- this.subscribedToBroadcastChannel = true
564
- }
467
+ this.configuration.websocketProvider.attach(this)
565
468
 
566
- this.mux(() => {
567
- this.broadcast(SyncStepOneMessage, { document: this.document, documentName: this.configuration.name })
568
- this.broadcast(SyncStepTwoMessage, { document: this.document, documentName: this.configuration.name })
569
- this.broadcast(QueryAwarenessMessage, { document: this.document, documentName: this.configuration.name })
570
- if (this.awareness) {
571
- this.broadcast(AwarenessMessage, {
572
- awareness: this.awareness,
573
- clients: [this.document.clientID],
574
- document: this.document,
575
- documentName: this.configuration.name,
576
- })
577
- }
578
- })
469
+ this.isAttached = true
579
470
  }
580
471
 
581
- disconnectBroadcastChannel() {
582
- // broadcast message with local awareness state set to null (indicating disconnect)
583
- if (this.awareness) {
584
- this.send(AwarenessMessage, {
585
- awareness: this.awareness,
586
- clients: [this.document.clientID],
587
- states: new Map(),
588
- documentName: this.configuration.name,
589
- }, true)
590
- }
591
-
592
- if (this.subscribedToBroadcastChannel) {
593
- bc.unsubscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber)
594
- this.subscribedToBroadcastChannel = false
595
- }
472
+ permissionDeniedHandler(reason: string) {
473
+ this.emit('authenticationFailed', { reason })
474
+ this.isAuthenticated = false
596
475
  }
597
476
 
598
- broadcast(Message: ConstructableOutgoingMessage, args?: any) {
599
- if (!this.configuration.broadcast) {
600
- return
601
- }
602
-
603
- if (!this.subscribedToBroadcastChannel) {
604
- return
605
- }
477
+ authenticatedHandler(scope: string) {
478
+ this.isAuthenticated = true
479
+ this.authorizedScope = scope
606
480
 
607
- new MessageSender(Message, args).broadcast(this.broadcastChannel)
481
+ this.emit('authenticated')
608
482
  }
609
483
 
610
484
  setAwarenessField(key: string, value: any) {
@@ -1,19 +1,20 @@
1
1
  import {
2
- Forbidden, MessageTooBig, Unauthorized, WsReadyStates,
2
+ WsReadyStates,
3
3
  } from '@hocuspocus/common'
4
4
  import { retry } from '@lifeomic/attempt'
5
5
  import * as time from 'lib0/time'
6
6
  import * as url from 'lib0/url'
7
- import type { MessageEvent } from 'ws'
8
- import { Event } from 'ws'
7
+ import type { MessageEvent , Event } from 'ws'
9
8
  import EventEmitter from './EventEmitter.js'
10
- import { HocuspocusProvider } from './HocuspocusProvider.js'
9
+ import type { HocuspocusProvider } from './HocuspocusProvider.js'
10
+ import type {
11
+ onAwarenessChangeParameters, onAwarenessUpdateParameters,
12
+ onCloseParameters, onDisconnectParameters, onMessageParameters, onOpenParameters, onOutgoingMessageParameters, onStatusParameters} from './types.js'
11
13
  import {
12
14
  WebSocketStatus,
13
- onAwarenessChangeParameters, onAwarenessUpdateParameters,
14
- onCloseParameters, onDisconnectParameters, onMessageParameters, onOpenParameters, onOutgoingMessageParameters, onStatusParameters,
15
15
  } from './types.js'
16
16
  import { IncomingMessage } from './IncomingMessage.js'
17
+ import {CloseMessage} from "./OutgoingMessages/CloseMessage.js"
17
18
 
18
19
  export type HocusPocusWebSocket = WebSocket & { identifier: string };
19
20
 
@@ -87,10 +88,6 @@ export interface CompleteHocuspocusProviderWebsocketConfiguration {
87
88
  onDestroy: () => void,
88
89
  onAwarenessUpdate: (data: onAwarenessUpdateParameters) => void,
89
90
  onAwarenessChange: (data: onAwarenessChangeParameters) => void,
90
- /**
91
- * Don’t output any warnings.
92
- */
93
- quiet: boolean,
94
91
 
95
92
  /**
96
93
  * Map of attached providers keyed by documentName.
@@ -138,7 +135,6 @@ export class HocuspocusProviderWebsocket extends EventEmitter {
138
135
  onDestroy: () => null,
139
136
  onAwarenessUpdate: () => null,
140
137
  onAwarenessChange: () => null,
141
- quiet: false,
142
138
  providerMap: new Map(),
143
139
  }
144
140
 
@@ -155,7 +151,6 @@ export class HocuspocusProviderWebsocket extends EventEmitter {
155
151
  identifier = 0
156
152
 
157
153
  intervals: any = {
158
- forceSync: null,
159
154
  connectionChecker: null,
160
155
  }
161
156
 
@@ -209,6 +204,7 @@ export class HocuspocusProviderWebsocket extends EventEmitter {
209
204
  receivedOnStatusPayload?: onStatusParameters | undefined = undefined
210
205
 
211
206
  async onOpen(event: Event) {
207
+ this.cancelWebsocketRetry = undefined
212
208
  this.receivedOnOpenPayload = event
213
209
  }
214
210
 
@@ -227,16 +223,13 @@ export class HocuspocusProviderWebsocket extends EventEmitter {
227
223
  if (this.receivedOnOpenPayload) {
228
224
  provider.onOpen(this.receivedOnOpenPayload)
229
225
  }
230
-
231
- if (this.receivedOnStatusPayload) {
232
- provider.onStatus(this.receivedOnStatusPayload)
233
- }
234
-
235
- return connectPromise
236
226
  }
237
227
 
238
228
  detach(provider: HocuspocusProvider) {
239
- this.configuration.providerMap.delete(provider.configuration.name)
229
+ if( this.configuration.providerMap.has(provider.configuration.name )) {
230
+ provider.send(CloseMessage, { documentName: provider.configuration.name })
231
+ this.configuration.providerMap.delete(provider.configuration.name)
232
+ }
240
233
  }
241
234
 
242
235
  public setConfiguration(
@@ -301,6 +294,7 @@ export class HocuspocusProviderWebsocket extends EventEmitter {
301
294
  return retryPromise
302
295
  }
303
296
 
297
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
304
298
  attachWebSocketListeners(ws: HocusPocusWebSocket, reject: Function) {
305
299
  const { identifier } = ws
306
300
  const onMessageHandler = (payload: any) => this.emit('message', payload)
@@ -442,7 +436,7 @@ export class HocuspocusProviderWebsocket extends EventEmitter {
442
436
  }
443
437
  }
444
438
 
445
- // Ensure that the URL always ends with /
439
+ // Ensure that the URL never ends with /
446
440
  get serverUrl() {
447
441
  while (this.configuration.url[this.configuration.url.length - 1] === '/') {
448
442
  return this.configuration.url.slice(0, this.configuration.url.length - 1)
@@ -467,8 +461,8 @@ export class HocuspocusProviderWebsocket extends EventEmitter {
467
461
  try {
468
462
  this.webSocket.close()
469
463
  this.messageQueue = []
470
- } catch {
471
- //
464
+ } catch(e) {
465
+ console.error(e)
472
466
  }
473
467
  }
474
468
 
@@ -484,73 +478,28 @@ export class HocuspocusProviderWebsocket extends EventEmitter {
484
478
  this.closeTries = 0
485
479
  this.cleanupWebSocket()
486
480
 
487
- if (this.status === WebSocketStatus.Connected) {
488
- this.status = WebSocketStatus.Disconnected
489
- this.emit('status', { status: WebSocketStatus.Disconnected })
490
- this.emit('disconnect', { event })
491
- }
492
-
493
- if (event.code === Unauthorized.code) {
494
- if (event.reason === Unauthorized.reason) {
495
- console.warn(
496
- '[HocuspocusProvider] An authentication token is required, but you didn’t send one. Try adding a `token` to your HocuspocusProvider configuration. Won’t try again.',
497
- )
498
- } else {
499
- console.warn(
500
- `[HocuspocusProvider] Connection closed with status Unauthorized: ${event.reason}`,
501
- )
502
- }
503
-
504
- this.shouldConnect = false
505
- }
506
-
507
- if (event.code === Forbidden.code) {
508
- if (!this.configuration.quiet) {
509
- console.warn(
510
- '[HocuspocusProvider] The provided authentication token isn’t allowed to connect to this server. Will try again.',
511
- )
512
- return // TODO REMOVE ME
513
- }
514
- }
515
-
516
- if (event.code === MessageTooBig.code) {
517
- console.warn(
518
- `[HocuspocusProvider] Connection closed with status MessageTooBig: ${event.reason}`,
519
- )
520
- this.shouldConnect = false
521
- }
522
-
523
481
  if (this.connectionAttempt) {
524
482
  // That connection attempt failed.
525
483
  this.rejectConnectionAttempt()
526
- } else if (this.shouldConnect) {
527
- // The connection was closed by the server. Let’s just try again.
528
- this.connect()
529
- }
530
-
531
- // If we’ll reconnect, we’re done for now.
532
- if (this.shouldConnect) {
533
- return
534
- }
535
-
536
- // The status is set correctly already.
537
- if (this.status === WebSocketStatus.Disconnected) {
538
- return
539
484
  }
540
485
 
541
486
  // Let’s update the connection status.
542
487
  this.status = WebSocketStatus.Disconnected
543
488
  this.emit('status', { status: WebSocketStatus.Disconnected })
544
489
  this.emit('disconnect', { event })
490
+
491
+ // trigger connect if no retry is running and we want to have a connection
492
+ if( !this.cancelWebsocketRetry && this.shouldConnect ) {
493
+
494
+ setTimeout(() => {
495
+ this.connect()
496
+ }, this.configuration.delay)
497
+ }
545
498
  }
546
499
 
547
500
  destroy() {
548
501
  this.emit('destroy')
549
502
 
550
- if (this.intervals.forceSync) {
551
- clearInterval(this.intervals.forceSync)
552
- }
553
-
554
503
  clearInterval(this.intervals.connectionChecker)
555
504
 
556
505
  // If there is still a connection attempt outstanding then we should stop