@hocuspocus/provider 3.4.6-rc.2 → 4.0.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.
package/dist/index.d.ts CHANGED
@@ -1,8 +1,7 @@
1
- import { Event, MessageEvent } from "ws";
2
1
  import * as Y from "yjs";
3
2
  import { CloseEvent } from "@hocuspocus/common";
4
3
 
5
- //#region node_modules/lib0/observable.d.ts
4
+ //#region node_modules/.pnpm/lib0@0.2.117/node_modules/lib0/observable.d.ts
6
5
  /**
7
6
  * Handles named events.
8
7
  *
@@ -43,7 +42,7 @@ declare class Observable<N> {
43
42
  destroy(): void;
44
43
  }
45
44
  //#endregion
46
- //#region node_modules/y-protocols/awareness.d.ts
45
+ //#region node_modules/.pnpm/y-protocols@1.0.7_yjs@13.6.29/node_modules/y-protocols/awareness.d.ts
47
46
  /**
48
47
  * @typedef {Object} MetaClientState
49
48
  * @property {number} MetaClientState.clock
@@ -132,34 +131,35 @@ declare class EventEmitter {
132
131
  removeAllListeners(): void;
133
132
  }
134
133
  //#endregion
135
- //#region node_modules/lib0/encoding.d.ts
134
+ //#region node_modules/.pnpm/lib0@0.2.117/node_modules/lib0/encoding.d.ts
136
135
  /**
137
136
  * A BinaryEncoder handles the encoding to an Uint8Array.
138
137
  */
139
138
  declare class Encoder {
140
139
  cpos: number;
141
- cbuf: Uint8Array;
140
+ cbuf: Uint8Array<ArrayBuffer>;
142
141
  /**
143
142
  * @type {Array<Uint8Array>}
144
143
  */
145
144
  bufs: Array<Uint8Array>;
146
145
  }
147
146
  //#endregion
148
- //#region node_modules/lib0/decoding.d.ts
147
+ //#region node_modules/.pnpm/lib0@0.2.117/node_modules/lib0/decoding.d.ts
149
148
  /**
150
149
  * A Decoder handles the decoding of an Uint8Array.
150
+ * @template {ArrayBufferLike} [Buf=ArrayBufferLike]
151
151
  */
152
- declare class Decoder {
152
+ declare class Decoder<Buf extends ArrayBufferLike = ArrayBufferLike> {
153
153
  /**
154
- * @param {Uint8Array} uint8Array Binary data to decode
154
+ * @param {Uint8Array<Buf>} uint8Array Binary data to decode
155
155
  */
156
- constructor(uint8Array: Uint8Array);
156
+ constructor(uint8Array: Uint8Array<Buf>);
157
157
  /**
158
158
  * Decoding target.
159
159
  *
160
- * @type {Uint8Array}
160
+ * @type {Uint8Array<Buf>}
161
161
  */
162
- arr: Uint8Array;
162
+ arr: Uint8Array<Buf>;
163
163
  /**
164
164
  * Current decoding position.
165
165
  *
@@ -190,7 +190,7 @@ declare class OutgoingMessage implements OutgoingMessageInterface {
190
190
  type?: MessageType;
191
191
  constructor();
192
192
  get(args: Partial<OutgoingMessageArguments>): Encoder | undefined;
193
- toUint8Array(): Uint8Array<ArrayBufferLike>;
193
+ toUint8Array(): Uint8Array<ArrayBuffer>;
194
194
  }
195
195
  //#endregion
196
196
  //#region packages/provider/src/OutgoingMessages/AuthenticationMessage.d.ts
@@ -243,7 +243,9 @@ declare enum MessageType {
243
243
  QueryAwareness = 3,
244
244
  Stateless = 5,
245
245
  CLOSE = 7,
246
- SyncStatus = 8
246
+ SyncStatus = 8,
247
+ Ping = 9,
248
+ Pong = 10
247
249
  }
248
250
  declare enum WebSocketStatus {
249
251
  Connecting = "connecting",
@@ -394,6 +396,7 @@ interface CompleteHocuspocusProviderWebsocketConfiguration {
394
396
  providerMap: Map<string, HocuspocusProvider>;
395
397
  }
396
398
  declare class HocuspocusProviderWebsocket extends EventEmitter {
399
+ private static readonly DEDUPLICATABLE_TYPES;
397
400
  private messageQueue;
398
401
  configuration: CompleteHocuspocusProviderWebsocketConfiguration;
399
402
  webSocket: HocusPocusWebSocket | null;
@@ -421,6 +424,10 @@ declare class HocuspocusProviderWebsocket extends EventEmitter {
421
424
  cleanupWebSocket(): void;
422
425
  createWebSocketConnection(): Promise<unknown>;
423
426
  onMessage(event: MessageEvent): void;
427
+ /**
428
+ * Send application-level Pong response to server Ping
429
+ */
430
+ private sendPong;
424
431
  resolveConnectionAttempt(): void;
425
432
  stopConnectionAttempt(): void;
426
433
  rejectConnectionAttempt(): void;
@@ -429,6 +436,8 @@ declare class HocuspocusProviderWebsocket extends EventEmitter {
429
436
  get serverUrl(): string;
430
437
  get url(): string;
431
438
  disconnect(): void;
439
+ private parseQueuedMessage;
440
+ private addToQueue;
432
441
  send(message: any): void;
433
442
  onClose({
434
443
  event
@@ -464,6 +473,17 @@ interface CompleteHocuspocusProviderConfiguration {
464
473
  * Hocuspocus websocket provider
465
474
  */
466
475
  websocketProvider: HocuspocusProviderWebsocket;
476
+ /**
477
+ * Enable session-aware multiplexing. When true, the provider embeds a unique
478
+ * sessionId in the documentName field of every message, allowing multiple
479
+ * providers with the same document name on a single WebSocket connection.
480
+ *
481
+ * Only set this to `false` when connecting to a v3 server that does not
482
+ * support session awareness.
483
+ *
484
+ * Default: true
485
+ */
486
+ sessionAwareness: boolean;
467
487
  /**
468
488
  * Force syncing the document in the defined interval.
469
489
  */
@@ -495,6 +515,17 @@ declare class HocuspocusProvider extends EventEmitter {
495
515
  authorizedScope: AuthorizedScope | undefined;
496
516
  manageSocket: boolean;
497
517
  private _isAttached;
518
+ /**
519
+ * Unique session identifier for this provider instance.
520
+ * Used for multiplexing multiple providers with the same document name on a single WebSocket.
521
+ */
522
+ sessionId: string;
523
+ /**
524
+ * The effective name used as the first VarString in messages.
525
+ * When `sessionAwareness` is enabled, returns a composite key (documentName\0sessionId).
526
+ * Otherwise, returns the plain document name.
527
+ */
528
+ get effectiveName(): string;
498
529
  intervals: any;
499
530
  constructor(configuration: HocuspocusProviderConfiguration);
500
531
  boundDocumentUpdateHandler: (update: Uint8Array, origin: any) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hocuspocus/provider",
3
- "version": "3.4.6-rc.2",
3
+ "version": "4.0.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": "^3.4.6-rc.2",
32
+ "@hocuspocus/common": "^4.0.0-rc.1",
33
33
  "@lifeomic/attempt": "^3.0.2",
34
34
  "lib0": "^0.2.87",
35
35
  "ws": "^8.17.1"
@@ -38,8 +38,11 @@
38
38
  "y-protocols": "^1.0.6",
39
39
  "yjs": "^13.6.8"
40
40
  },
41
- "gitHead": "cd788b6a315f608ef531524409abdce1e6790726",
41
+ "gitHead": "730ac02724fcc44bbbfcc5849df4b0cafb996450",
42
42
  "repository": {
43
43
  "url": "https://github.com/ueberdosis/hocuspocus"
44
+ },
45
+ "publishConfig": {
46
+ "access": "public"
44
47
  }
45
48
  }
@@ -1,5 +1,4 @@
1
- import { awarenessStatesToArray } from "@hocuspocus/common";
2
- import type { Event, MessageEvent } from "ws";
1
+ import { awarenessStatesToArray, makeRoutingKey, parseRoutingKey } from "@hocuspocus/common";
3
2
  import { Awareness, removeAwarenessStates } from "y-protocols/awareness";
4
3
  import * as Y from "yjs";
5
4
  import EventEmitter from "./EventEmitter.ts";
@@ -13,22 +12,22 @@ import { AwarenessMessage } from "./OutgoingMessages/AwarenessMessage.ts";
13
12
  import { StatelessMessage } from "./OutgoingMessages/StatelessMessage.ts";
14
13
  import { SyncStepOneMessage } from "./OutgoingMessages/SyncStepOneMessage.ts";
15
14
  import { UpdateMessage } from "./OutgoingMessages/UpdateMessage.ts";
16
- import type {
17
- AuthorizedScope,
18
- ConstructableOutgoingMessage,
19
- onAuthenticatedParameters,
20
- onAuthenticationFailedParameters,
21
- onAwarenessChangeParameters,
22
- onAwarenessUpdateParameters,
23
- onCloseParameters,
24
- onDisconnectParameters,
25
- onMessageParameters,
26
- onOpenParameters,
27
- onOutgoingMessageParameters,
28
- onStatelessParameters,
29
- onStatusParameters,
30
- onSyncedParameters,
31
- onUnsyncedChangesParameters,
15
+ import {
16
+ type AuthorizedScope,
17
+ type ConstructableOutgoingMessage,
18
+ type onAuthenticatedParameters,
19
+ type onAuthenticationFailedParameters,
20
+ type onAwarenessChangeParameters,
21
+ type onAwarenessUpdateParameters,
22
+ type onCloseParameters,
23
+ type onDisconnectParameters,
24
+ type onMessageParameters,
25
+ type onOpenParameters,
26
+ type onOutgoingMessageParameters,
27
+ type onStatelessParameters,
28
+ type onStatusParameters,
29
+ type onSyncedParameters,
30
+ type onUnsyncedChangesParameters,
32
31
  } from "./types.ts";
33
32
 
34
33
  export type HocuspocusProviderConfiguration = Required<
@@ -78,6 +77,18 @@ export interface CompleteHocuspocusProviderConfiguration {
78
77
  */
79
78
  websocketProvider: HocuspocusProviderWebsocket;
80
79
 
80
+ /**
81
+ * Enable session-aware multiplexing. When true, the provider embeds a unique
82
+ * sessionId in the documentName field of every message, allowing multiple
83
+ * providers with the same document name on a single WebSocket connection.
84
+ *
85
+ * Only set this to `false` when connecting to a v3 server that does not
86
+ * support session awareness.
87
+ *
88
+ * Default: true
89
+ */
90
+ sessionAwareness: boolean;
91
+
81
92
  /**
82
93
  * Force syncing the document in the defined interval.
83
94
  */
@@ -112,6 +123,7 @@ export class HocuspocusProvider extends EventEmitter {
112
123
  // @ts-ignore
113
124
  awareness: undefined,
114
125
  token: null,
126
+ sessionAwareness: true,
115
127
  forceSyncInterval: false,
116
128
  onAuthenticated: () => null,
117
129
  onAuthenticationFailed: () => null,
@@ -143,6 +155,23 @@ export class HocuspocusProvider extends EventEmitter {
143
155
 
144
156
  private _isAttached = false;
145
157
 
158
+ /**
159
+ * Unique session identifier for this provider instance.
160
+ * Used for multiplexing multiple providers with the same document name on a single WebSocket.
161
+ */
162
+ sessionId: string = Math.random().toString(36).slice(2);
163
+
164
+ /**
165
+ * The effective name used as the first VarString in messages.
166
+ * When `sessionAwareness` is enabled, returns a composite key (documentName\0sessionId).
167
+ * Otherwise, returns the plain document name.
168
+ */
169
+ get effectiveName(): string {
170
+ return this.configuration.sessionAwareness
171
+ ? makeRoutingKey(this.configuration.name, this.sessionId)
172
+ : this.configuration.name;
173
+ }
174
+
146
175
  intervals: any = {
147
176
  forceSync: null,
148
177
  };
@@ -280,7 +309,7 @@ export class HocuspocusProvider extends EventEmitter {
280
309
 
281
310
  this.send(SyncStepOneMessage, {
282
311
  document: this.document,
283
- documentName: this.configuration.name,
312
+ documentName: this.effectiveName,
284
313
  });
285
314
  }
286
315
 
@@ -304,7 +333,7 @@ export class HocuspocusProvider extends EventEmitter {
304
333
 
305
334
  sendStateless(payload: string) {
306
335
  this.send(StatelessMessage, {
307
- documentName: this.configuration.name,
336
+ documentName: this.effectiveName,
308
337
  payload,
309
338
  });
310
339
  }
@@ -322,7 +351,7 @@ export class HocuspocusProvider extends EventEmitter {
322
351
 
323
352
  this.send(AuthenticationMessage, {
324
353
  token: token ?? "",
325
- documentName: this.configuration.name,
354
+ documentName: this.effectiveName,
326
355
  });
327
356
  }
328
357
 
@@ -332,7 +361,7 @@ export class HocuspocusProvider extends EventEmitter {
332
361
  }
333
362
 
334
363
  this.incrementUnsyncedChanges();
335
- this.send(UpdateMessage, { update, documentName: this.configuration.name });
364
+ this.send(UpdateMessage, { update, documentName: this.effectiveName });
336
365
  }
337
366
 
338
367
  awarenessUpdateHandler({ added, updated, removed }: any, origin: any) {
@@ -341,7 +370,7 @@ export class HocuspocusProvider extends EventEmitter {
341
370
  this.send(AwarenessMessage, {
342
371
  awareness: this.awareness,
343
372
  clients: changedClients,
344
- documentName: this.configuration.name,
373
+ documentName: this.effectiveName,
345
374
  });
346
375
  }
347
376
 
@@ -414,14 +443,14 @@ export class HocuspocusProvider extends EventEmitter {
414
443
 
415
444
  this.send(SyncStepOneMessage, {
416
445
  document: this.document,
417
- documentName: this.configuration.name,
446
+ documentName: this.effectiveName,
418
447
  });
419
448
 
420
449
  if (this.awareness && this.awareness.getLocalState() !== null) {
421
450
  this.send(AwarenessMessage, {
422
451
  awareness: this.awareness,
423
452
  clients: [this.document.clientID],
424
- documentName: this.configuration.name,
453
+ documentName: this.effectiveName,
425
454
  });
426
455
  }
427
456
  }
@@ -438,9 +467,11 @@ export class HocuspocusProvider extends EventEmitter {
438
467
  onMessage(event: MessageEvent) {
439
468
  const message = new IncomingMessage(event.data);
440
469
 
441
- const documentName = message.readVarString();
470
+ const rawKey = message.readVarString();
471
+ // Extract actual documentName from potentially composite routing key
472
+ const { documentName } = parseRoutingKey(rawKey);
442
473
 
443
- message.writeVarString(documentName);
474
+ message.writeVarString(this.effectiveName);
444
475
 
445
476
  this.emit("message", { event, message: new IncomingMessage(event.data) });
446
477
 
@@ -1,13 +1,14 @@
1
1
  import { WsReadyStates } from "@hocuspocus/common";
2
2
  import { retry } from "@lifeomic/attempt";
3
+ import { createDecoder, readVarString, readVarUint } from "lib0/decoding";
4
+ import * as encoding from "lib0/encoding";
3
5
  import * as time from "lib0/time";
4
- import type { Event, MessageEvent } from "ws";
5
6
  import EventEmitter from "./EventEmitter.ts";
6
7
  import type { HocuspocusProvider } from "./HocuspocusProvider.ts";
7
8
  import { IncomingMessage } from "./IncomingMessage.ts";
8
9
  import { CloseMessage } from "./OutgoingMessages/CloseMessage.ts";
9
10
  import {
10
- WebSocketStatus,
11
+ MessageType,
11
12
  type onAwarenessChangeParameters,
12
13
  type onAwarenessUpdateParameters,
13
14
  type onCloseParameters,
@@ -16,6 +17,7 @@ import {
16
17
  type onOpenParameters,
17
18
  type onOutgoingMessageParameters,
18
19
  type onStatusParameters,
20
+ WebSocketStatus,
19
21
  } from "./types.ts";
20
22
 
21
23
  export type HocuspocusWebSocket = WebSocket & { identifier: string };
@@ -103,13 +105,18 @@ export interface CompleteHocuspocusProviderWebsocketConfiguration {
103
105
  }
104
106
 
105
107
  export class HocuspocusProviderWebsocket extends EventEmitter {
108
+ private static readonly DEDUPLICATABLE_TYPES = new Set([
109
+ MessageType.Awareness,
110
+ MessageType.QueryAwareness,
111
+ ]);
112
+
106
113
  private messageQueue: any[] = [];
107
114
 
108
115
  public configuration: CompleteHocuspocusProviderWebsocketConfiguration = {
109
116
  url: "",
110
117
  autoConnect: true,
111
118
  preserveTrailingSlash: false,
112
- // @ts-ignore
119
+ // @ts-expect-error
113
120
  document: undefined,
114
121
  WebSocketPolyfill: undefined,
115
122
  // TODO: this should depend on awareness.outdatedTime
@@ -209,7 +216,20 @@ export class HocuspocusProviderWebsocket extends EventEmitter {
209
216
  }
210
217
 
211
218
  attach(provider: HocuspocusProvider) {
212
- this.configuration.providerMap.set(provider.configuration.name, provider);
219
+ const key = provider.effectiveName;
220
+ const existing = this.configuration.providerMap.get(key);
221
+
222
+ if (existing && existing !== provider) {
223
+ // Allow replacing a provider that hasn't authenticated (e.g., after auth failure retry)
224
+ if (existing.isAuthenticated) {
225
+ throw new Error(
226
+ `Cannot attach two providers with the same effective name "${key}". ` +
227
+ "Use sessionAwareness: true to multiplex providers with the same document name.",
228
+ );
229
+ }
230
+ }
231
+
232
+ this.configuration.providerMap.set(key, provider);
213
233
 
214
234
  if (this.status === WebSocketStatus.Disconnected && this.shouldConnect) {
215
235
  this.connect();
@@ -224,11 +244,12 @@ export class HocuspocusProviderWebsocket extends EventEmitter {
224
244
  }
225
245
 
226
246
  detach(provider: HocuspocusProvider) {
227
- if (this.configuration.providerMap.has(provider.configuration.name)) {
247
+ const key = provider.effectiveName;
248
+ if (this.configuration.providerMap.has(key)) {
228
249
  provider.send(CloseMessage, {
229
- documentName: provider.configuration.name,
250
+ documentName: key,
230
251
  });
231
- this.configuration.providerMap.delete(provider.configuration.name);
252
+ this.configuration.providerMap.delete(key);
232
253
  }
233
254
  }
234
255
 
@@ -373,10 +394,31 @@ export class HocuspocusProviderWebsocket extends EventEmitter {
373
394
 
374
395
  this.lastMessageReceived = time.getUnixTime();
375
396
 
376
- const message = new IncomingMessage(event.data);
377
- const documentName = message.peekVarString();
397
+ const data = new Uint8Array(event.data as ArrayBuffer);
398
+
399
+ // Check for connection-level Ping message (no document name prefix)
400
+ // Ping messages are sent as just the message type byte (length 1)
401
+ // We check length to avoid confusing with regular messages that happen to have
402
+ // a document name length of 9 as the first byte
403
+ if (data.length === 1 && data[0] === MessageType.Ping) {
404
+ this.sendPong();
405
+ return;
406
+ }
407
+
408
+ const message = new IncomingMessage(data);
409
+ const rawKey = message.peekVarString();
410
+
411
+ const provider = this.configuration.providerMap.get(rawKey);
412
+ provider?.onMessage(event);
413
+ }
378
414
 
379
- this.configuration.providerMap.get(documentName)?.onMessage(event);
415
+ /**
416
+ * Send application-level Pong response to server Ping
417
+ */
418
+ private sendPong() {
419
+ const encoder = encoding.createEncoder();
420
+ encoding.writeVarUint(encoder, MessageType.Pong);
421
+ this.send(encoding.toUint8Array(encoder));
380
422
  }
381
423
 
382
424
  resolveConnectionAttempt() {
@@ -474,11 +516,45 @@ export class HocuspocusProviderWebsocket extends EventEmitter {
474
516
  }
475
517
  }
476
518
 
519
+ private parseQueuedMessage(
520
+ message: Uint8Array,
521
+ ): { documentName: string; messageType: number } | null {
522
+ try {
523
+ const decoder = createDecoder(message);
524
+ const documentName = readVarString(decoder);
525
+ const messageType = readVarUint(decoder);
526
+ return { documentName, messageType };
527
+ } catch {
528
+ return null;
529
+ }
530
+ }
531
+
532
+ private addToQueue(message: any) {
533
+ if (message instanceof Uint8Array) {
534
+ const parsed = this.parseQueuedMessage(message);
535
+ if (
536
+ parsed &&
537
+ HocuspocusProviderWebsocket.DEDUPLICATABLE_TYPES.has(parsed.messageType)
538
+ ) {
539
+ this.messageQueue = this.messageQueue.filter((queued) => {
540
+ if (!(queued instanceof Uint8Array)) return true;
541
+ const queuedParsed = this.parseQueuedMessage(queued);
542
+ if (!queuedParsed) return true;
543
+ return !(
544
+ queuedParsed.documentName === parsed.documentName &&
545
+ queuedParsed.messageType === parsed.messageType
546
+ );
547
+ });
548
+ }
549
+ }
550
+ this.messageQueue.push(message);
551
+ }
552
+
477
553
  send(message: any) {
478
554
  if (this.webSocket?.readyState === WsReadyStates.Open) {
479
555
  this.webSocket.send(message);
480
556
  } else {
481
- this.messageQueue.push(message);
557
+ this.addToQueue(message);
482
558
  }
483
559
  }
484
560
 
@@ -1,6 +1,5 @@
1
- import { readAuthMessage } from "@hocuspocus/common";
1
+ import { type CloseEvent, readAuthMessage } from "@hocuspocus/common";
2
2
  import { readVarInt, readVarString } from "lib0/decoding";
3
- import type { CloseEvent } from "ws";
4
3
  import * as awarenessProtocol from "y-protocols/awareness";
5
4
  import { messageYjsSyncStep2, readSyncMessage } from "y-protocols/sync";
6
5
  import type { HocuspocusProvider } from "./HocuspocusProvider.ts";
@@ -54,9 +53,6 @@ export class MessageReceiver {
54
53
  const event: CloseEvent = {
55
54
  code: 1000,
56
55
  reason: readVarString(message.decoder),
57
- // @ts-ignore
58
- target: provider.configuration.websocketProvider.webSocket!,
59
- type: "close",
60
56
  };
61
57
  provider.onClose();
62
58
  provider.configuration.onClose({ event });
@@ -64,7 +60,7 @@ export class MessageReceiver {
64
60
  break;
65
61
 
66
62
  default:
67
- throw new Error(`Can’t apply message of unknown type: ${type}`);
63
+ console.error(`Can’t apply message of unknown type: ${type}`);
68
64
  }
69
65
 
70
66
  // Reply
@@ -3,6 +3,7 @@ import { writeAuthentication } from "@hocuspocus/common";
3
3
  import type { OutgoingMessageArguments } from "../types.ts";
4
4
  import { MessageType } from "../types.ts";
5
5
  import { OutgoingMessage } from "../OutgoingMessage.ts";
6
+ import { version } from "../version.ts";
6
7
 
7
8
  export class AuthenticationMessage extends OutgoingMessage {
8
9
  type = MessageType.Auth;
@@ -19,6 +20,7 @@ export class AuthenticationMessage extends OutgoingMessage {
19
20
  writeVarString(this.encoder, args.documentName!);
20
21
  writeVarUint(this.encoder, this.type);
21
22
  writeAuthentication(this.encoder, args.token);
23
+ writeVarString(this.encoder, version);
22
24
 
23
25
  return this.encoder;
24
26
  }
package/src/types.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import type { Encoder } from "lib0/encoding";
2
- import type { Event, MessageEvent } from "ws";
3
2
  import type { Awareness } from "y-protocols/awareness";
4
3
  import type * as Y from "yjs";
5
4
  import type { CloseEvent } from "@hocuspocus/common";
@@ -20,6 +19,8 @@ export enum MessageType {
20
19
  Stateless = 5,
21
20
  CLOSE = 7,
22
21
  SyncStatus = 8,
22
+ Ping = 9,
23
+ Pong = 10,
23
24
  }
24
25
 
25
26
  export enum WebSocketStatus {
package/src/version.ts ADDED
@@ -0,0 +1,5 @@
1
+ // @ts-ignore - __HOCUSPOCUS_VERSION__ is replaced at build time by rolldown
2
+ // eslint-disable-next-line
3
+ export const version: string = typeof __HOCUSPOCUS_VERSION__ !== 'undefined'
4
+ ? __HOCUSPOCUS_VERSION__
5
+ : 'unknown';