@hocuspocus/extension-redis 3.0.0-rc.0 → 3.0.6-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 (54) hide show
  1. package/dist/hocuspocus-redis.cjs +41 -33137
  2. package/dist/hocuspocus-redis.cjs.map +1 -1
  3. package/dist/hocuspocus-redis.esm.js +35 -33131
  4. package/dist/hocuspocus-redis.esm.js.map +1 -1
  5. package/dist/packages/common/src/index.d.ts +4 -4
  6. package/dist/packages/extension-database/src/index.d.ts +1 -1
  7. package/dist/packages/extension-logger/src/index.d.ts +1 -1
  8. package/dist/packages/extension-redis/src/Redis.d.ts +6 -2
  9. package/dist/packages/extension-redis/src/index.d.ts +1 -1
  10. package/dist/packages/extension-sqlite/src/index.d.ts +1 -1
  11. package/dist/packages/provider/src/HocuspocusProvider.d.ts +14 -36
  12. package/dist/packages/provider/src/HocuspocusProviderWebsocket.d.ts +4 -8
  13. package/dist/packages/provider/src/IncomingMessage.d.ts +2 -2
  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 +3 -3
  18. package/dist/packages/provider/src/OutgoingMessages/AwarenessMessage.d.ts +3 -3
  19. package/dist/packages/provider/src/OutgoingMessages/CloseMessage.d.ts +3 -3
  20. package/dist/packages/provider/src/OutgoingMessages/QueryAwarenessMessage.d.ts +3 -3
  21. package/dist/packages/provider/src/OutgoingMessages/StatelessMessage.d.ts +3 -3
  22. package/dist/packages/provider/src/OutgoingMessages/SyncStepOneMessage.d.ts +3 -3
  23. package/dist/packages/provider/src/OutgoingMessages/SyncStepTwoMessage.d.ts +3 -3
  24. package/dist/packages/provider/src/OutgoingMessages/UpdateMessage.d.ts +3 -3
  25. package/dist/packages/provider/src/index.d.ts +3 -5
  26. package/dist/packages/provider/src/types.d.ts +50 -10
  27. package/dist/packages/server/src/ClientConnection.d.ts +16 -8
  28. package/dist/packages/server/src/Connection.d.ts +14 -20
  29. package/dist/packages/server/src/DirectConnection.d.ts +4 -4
  30. package/dist/packages/server/src/Document.d.ts +2 -6
  31. package/dist/packages/server/src/Hocuspocus.d.ts +6 -15
  32. package/dist/packages/server/src/IncomingMessage.d.ts +4 -3
  33. package/dist/packages/server/src/MessageReceiver.d.ts +6 -8
  34. package/dist/packages/server/src/OutgoingMessage.d.ts +2 -1
  35. package/dist/packages/server/src/Server.d.ts +3 -3
  36. package/dist/packages/server/src/index.d.ts +9 -10
  37. package/dist/packages/server/src/types.d.ts +41 -13
  38. package/dist/packages/transformer/src/Prosemirror.d.ts +1 -1
  39. package/dist/packages/transformer/src/Tiptap.d.ts +1 -1
  40. package/dist/packages/transformer/src/index.d.ts +3 -3
  41. package/dist/playground/frontend/app/SocketContext.d.ts +2 -0
  42. package/dist/playground/frontend/next.config.d.ts +3 -0
  43. package/dist/tests/utils/index.d.ts +9 -9
  44. package/dist/tests/utils/newHocuspocusProvider.d.ts +2 -2
  45. package/package.json +4 -4
  46. package/src/Redis.ts +39 -13
  47. package/src/index.ts +1 -1
  48. package/dist/packages/provider/src/TiptapCollabProvider.d.ts +0 -64
  49. package/dist/packages/provider/src/TiptapCollabProviderWebsocket.d.ts +0 -20
  50. package/dist/packages/server/src/Debugger.d.ts +0 -14
  51. package/dist/playground/frontend/vite.config.d.ts +0 -2
  52. package/dist/tests/server/getMessageLogs.d.ts +0 -1
  53. package/dist/tests/server/requiresAuthentication.d.ts +0 -1
  54. /package/dist/{playground/frontend/src/main.d.ts → tests/server/beforeSync.d.ts} +0 -0
@@ -1,10 +1,9 @@
1
1
  import type { IncomingMessage } from 'http';
2
2
  import type WebSocket from 'ws';
3
- import type { Server } from './Server.js';
4
- import { Debugger } from './Debugger.js';
5
- import { DirectConnection } from './DirectConnection.js';
6
- import Document from './Document.js';
7
- import type { Configuration, ConnectionConfiguration, HookName, HookPayloadByName, onStoreDocumentPayload } from './types.js';
3
+ import { DirectConnection } from './DirectConnection.ts';
4
+ import Document from './Document.ts';
5
+ import type { Server } from './Server.ts';
6
+ import type { Configuration, ConnectionConfiguration, HookName, HookPayloadByName, onStoreDocumentPayload } from './types.ts';
8
7
  export declare const defaultConfiguration: {
9
8
  name: null;
10
9
  timeout: number;
@@ -22,7 +21,6 @@ export declare class Hocuspocus {
22
21
  loadingDocuments: Map<string, Promise<Document>>;
23
22
  documents: Map<string, Document>;
24
23
  server?: Server;
25
- debugger: Debugger;
26
24
  debouncer: {
27
25
  debounce: (id: string, func: Function, debounce: number, maxDebounce: number) => any;
28
26
  isDebounced: (id: string) => boolean;
@@ -33,7 +31,6 @@ export declare class Hocuspocus {
33
31
  * Configure Hocuspocus
34
32
  */
35
33
  configure(configuration: Partial<Configuration>): Hocuspocus;
36
- get requiresAuthentication(): boolean;
37
34
  /**
38
35
  * Get the total number of active documents
39
36
  */
@@ -68,19 +65,13 @@ export declare class Hocuspocus {
68
65
  * Create a new document by the given request
69
66
  */
70
67
  createDocument(documentName: string, request: Partial<Pick<IncomingMessage, 'headers' | 'url'>>, socketId: string, connection: ConnectionConfiguration, context?: any): Promise<Document>;
71
- loadDocument(documentName: string, request: Partial<Pick<IncomingMessage, 'headers' | 'url'>>, socketId: string, connection: ConnectionConfiguration, context?: any): Promise<Document>;
68
+ loadDocument(documentName: string, request: Partial<Pick<IncomingMessage, 'headers' | 'url'>>, socketId: string, connectionConfig: ConnectionConfiguration, context?: any): Promise<Document>;
72
69
  storeDocumentHooks(document: Document, hookPayload: onStoreDocumentPayload, immediately?: boolean): any;
73
70
  /**
74
71
  * Run the given hook on all configured extensions.
75
72
  * Runs the given callback after each hook.
76
73
  */
77
74
  hooks<T extends HookName>(name: T, payload: HookPayloadByName[T], callback?: Function | null): Promise<any>;
78
- unloadDocument(document: Document): void;
79
- enableDebugging(): void;
80
- enableMessageLogging(): void;
81
- disableLogging(): void;
82
- disableDebugging(): void;
83
- flushMessageLogs(): this;
84
- getMessageLogs(): any[];
75
+ unloadDocument(document: Document): Promise<any>;
85
76
  openDirectConnection(documentName: string, context?: any): Promise<DirectConnection>;
86
77
  }
@@ -1,6 +1,6 @@
1
1
  import type { Decoder } from 'lib0/decoding';
2
2
  import type { Encoder } from 'lib0/encoding';
3
- import type { MessageType } from './types.js';
3
+ import type { MessageType } from './types.ts';
4
4
  export declare class IncomingMessage {
5
5
  /**
6
6
  * Access to the received message.
@@ -14,10 +14,11 @@ export declare class IncomingMessage {
14
14
  private encoderInternal?;
15
15
  constructor(input: any);
16
16
  get encoder(): Encoder;
17
- readVarUint8Array(): Uint8Array;
17
+ readVarUint8Array(): Uint8Array<ArrayBufferLike>;
18
+ peekVarUint8Array(): Uint8Array<ArrayBufferLike>;
18
19
  readVarUint(): number;
19
20
  readVarString(): string;
20
- toUint8Array(): Uint8Array;
21
+ toUint8Array(): Uint8Array<ArrayBufferLike>;
21
22
  writeVarUint(type: MessageType): void;
22
23
  writeVarString(string: string): void;
23
24
  get length(): number;
@@ -1,13 +1,11 @@
1
- import type Connection from './Connection.js';
2
- import type { Debugger } from './Debugger.js';
3
- import type Document from './Document.js';
4
- import type { IncomingMessage } from './IncomingMessage.js';
1
+ import type Connection from './Connection.ts';
2
+ import type Document from './Document.ts';
3
+ import type { IncomingMessage } from './IncomingMessage.ts';
5
4
  export declare class MessageReceiver {
6
5
  message: IncomingMessage;
7
- logger: Debugger;
8
6
  defaultTransactionOrigin?: string;
9
- constructor(message: IncomingMessage, logger: Debugger, defaultTransactionOrigin?: string);
10
- apply(document: Document, connection?: Connection, reply?: (message: Uint8Array) => void): void;
11
- readSyncMessage(message: IncomingMessage, document: Document, connection?: Connection, reply?: (message: Uint8Array) => void, requestFirstSync?: boolean): 0 | 1 | 2;
7
+ constructor(message: IncomingMessage, defaultTransactionOrigin?: string);
8
+ apply(document: Document, connection?: Connection, reply?: (message: Uint8Array) => void): Promise<void>;
9
+ readSyncMessage(message: IncomingMessage, document: Document, connection?: Connection, reply?: (message: Uint8Array) => void, requestFirstSync?: boolean): Promise<0 | 1 | 2>;
12
10
  applyQueryAwarenessMessage(document: Document, reply?: (message: Uint8Array) => void): void;
13
11
  }
@@ -1,6 +1,6 @@
1
1
  import type { Encoder } from 'lib0/encoding';
2
2
  import type { Awareness } from 'y-protocols/awareness';
3
- import type Document from './Document.js';
3
+ import type Document from './Document.ts';
4
4
  export declare class OutgoingMessage {
5
5
  encoder: Encoder;
6
6
  type?: number;
@@ -17,5 +17,6 @@ export declare class OutgoingMessage {
17
17
  writeStateless(payload: string): OutgoingMessage;
18
18
  writeBroadcastStateless(payload: string): OutgoingMessage;
19
19
  writeSyncStatus(updateSaved: boolean): OutgoingMessage;
20
+ writeCloseMessage(reason: string): OutgoingMessage;
20
21
  toUint8Array(): Uint8Array;
21
22
  }
@@ -1,7 +1,7 @@
1
1
  import type { IncomingMessage, Server as HTTPServer, ServerResponse } from 'http';
2
- import type { AddressInfo } from 'ws';
3
2
  import { WebSocketServer } from 'ws';
4
- import { Hocuspocus } from './Hocuspocus.js';
3
+ import type { AddressInfo, ServerOptions } from 'ws';
4
+ import { Hocuspocus } from './Hocuspocus.ts';
5
5
  import type { Configuration } from './types';
6
6
  export interface ServerConfiguration extends Configuration {
7
7
  port?: number;
@@ -18,7 +18,7 @@ export declare class Server {
18
18
  webSocketServer: WebSocketServer;
19
19
  hocuspocus: Hocuspocus;
20
20
  configuration: ServerConfiguration;
21
- constructor(configuration?: Partial<ServerConfiguration>);
21
+ constructor(configuration?: Partial<ServerConfiguration>, websocketOptions?: ServerOptions);
22
22
  setupWebsocketConnection: () => void;
23
23
  setupHttpUpgrade: () => void;
24
24
  requestHandler: (request: IncomingMessage, response: ServerResponse) => Promise<void>;
@@ -1,10 +1,9 @@
1
- export * from './Connection.js';
2
- export * from './Debugger.js';
3
- export * from './Document.js';
4
- export * from './Hocuspocus.js';
5
- export * from './IncomingMessage.js';
6
- export * from './MessageReceiver.js';
7
- export * from './OutgoingMessage.js';
8
- export * from './Server.js';
9
- export * from './types.js';
10
- export * from './util/debounce.js';
1
+ export * from './Connection.ts';
2
+ export * from './Document.ts';
3
+ export * from './Hocuspocus.ts';
4
+ export * from './IncomingMessage.ts';
5
+ export * from './MessageReceiver.ts';
6
+ export * from './OutgoingMessage.ts';
7
+ export * from './Server.ts';
8
+ export * from './types.ts';
9
+ export * from './util/debounce.ts';
@@ -1,9 +1,9 @@
1
1
  import type { IncomingHttpHeaders, IncomingMessage, ServerResponse } from 'http';
2
2
  import type { URLSearchParams } from 'url';
3
3
  import type { Awareness } from 'y-protocols/awareness';
4
- import type Connection from './Connection.js';
5
- import type Document from './Document.js';
6
- import type { Hocuspocus } from './Hocuspocus.js';
4
+ import type Connection from './Connection.ts';
5
+ import type Document from './Document.ts';
6
+ import type { Hocuspocus } from './Hocuspocus.ts';
7
7
  export declare enum MessageType {
8
8
  Unknown = -1,
9
9
  Sync = 0,
@@ -23,7 +23,6 @@ export interface AwarenessUpdate {
23
23
  }
24
24
  export interface ConnectionConfiguration {
25
25
  readOnly: boolean;
26
- requiresAuthentication: boolean;
27
26
  isAuthenticated: boolean;
28
27
  }
29
28
  export interface Extension {
@@ -39,6 +38,7 @@ export interface Extension {
39
38
  onLoadDocument?(data: onLoadDocumentPayload): Promise<any>;
40
39
  afterLoadDocument?(data: afterLoadDocumentPayload): Promise<any>;
41
40
  beforeHandleMessage?(data: beforeHandleMessagePayload): Promise<any>;
41
+ beforeSync?(data: beforeSyncPayload): Promise<any>;
42
42
  beforeBroadcastStateless?(data: beforeBroadcastStatelessPayload): Promise<any>;
43
43
  onStateless?(payload: onStatelessPayload): Promise<any>;
44
44
  onChange?(data: onChangePayload): Promise<any>;
@@ -47,10 +47,11 @@ export interface Extension {
47
47
  onAwarenessUpdate?(data: onAwarenessUpdatePayload): Promise<any>;
48
48
  onRequest?(data: onRequestPayload): Promise<any>;
49
49
  onDisconnect?(data: onDisconnectPayload): Promise<any>;
50
+ beforeUnloadDocument?(data: beforeUnloadDocumentPayload): Promise<any>;
50
51
  afterUnloadDocument?(data: afterUnloadDocumentPayload): Promise<any>;
51
52
  onDestroy?(data: onDestroyPayload): Promise<any>;
52
53
  }
53
- export type HookName = 'onConfigure' | 'onListen' | 'onUpgrade' | 'onConnect' | 'connected' | 'onAuthenticate' | 'onCreateDocument' | 'onLoadDocument' | 'afterLoadDocument' | 'beforeHandleMessage' | 'beforeBroadcastStateless' | 'onStateless' | 'onChange' | 'onStoreDocument' | 'afterStoreDocument' | 'onAwarenessUpdate' | 'onRequest' | 'onDisconnect' | 'afterUnloadDocument' | 'onDestroy';
54
+ export type HookName = 'onConfigure' | 'onListen' | 'onUpgrade' | 'onConnect' | 'connected' | 'onAuthenticate' | 'onCreateDocument' | 'onLoadDocument' | 'afterLoadDocument' | 'beforeHandleMessage' | 'beforeBroadcastStateless' | 'beforeSync' | 'onStateless' | 'onChange' | 'onStoreDocument' | 'afterStoreDocument' | 'onAwarenessUpdate' | 'onRequest' | 'onDisconnect' | 'beforeUnloadDocument' | 'afterUnloadDocument' | 'onDestroy';
54
55
  export type HookPayloadByName = {
55
56
  onConfigure: onConfigurePayload;
56
57
  onListen: onListenPayload;
@@ -63,6 +64,7 @@ export type HookPayloadByName = {
63
64
  afterLoadDocument: afterLoadDocumentPayload;
64
65
  beforeHandleMessage: beforeHandleMessagePayload;
65
66
  beforeBroadcastStateless: beforeBroadcastStatelessPayload;
67
+ beforeSync: beforeSyncPayload;
66
68
  onStateless: onStatelessPayload;
67
69
  onChange: onChangePayload;
68
70
  onStoreDocument: onStoreDocumentPayload;
@@ -71,6 +73,7 @@ export type HookPayloadByName = {
71
73
  onRequest: onRequestPayload;
72
74
  onDisconnect: onDisconnectPayload;
73
75
  afterUnloadDocument: afterUnloadDocumentPayload;
76
+ beforeUnloadDocument: beforeUnloadDocumentPayload;
74
77
  onDestroy: onDestroyPayload;
75
78
  };
76
79
  export interface Configuration extends Extension {
@@ -130,7 +133,7 @@ export interface onAuthenticatePayload {
130
133
  request: IncomingMessage;
131
134
  socketId: string;
132
135
  token: string;
133
- connection: ConnectionConfiguration;
136
+ connectionConfig: ConnectionConfiguration;
134
137
  }
135
138
  export interface onCreateDocumentPayload {
136
139
  context: any;
@@ -139,7 +142,7 @@ export interface onCreateDocumentPayload {
139
142
  requestHeaders: IncomingHttpHeaders;
140
143
  requestParameters: URLSearchParams;
141
144
  socketId: string;
142
- connection: ConnectionConfiguration;
145
+ connectionConfig: ConnectionConfiguration;
143
146
  }
144
147
  export interface onConnectPayload {
145
148
  context: any;
@@ -149,7 +152,7 @@ export interface onConnectPayload {
149
152
  requestHeaders: IncomingHttpHeaders;
150
153
  requestParameters: URLSearchParams;
151
154
  socketId: string;
152
- connection: ConnectionConfiguration;
155
+ connectionConfig: ConnectionConfiguration;
153
156
  }
154
157
  export interface connectedPayload {
155
158
  context: any;
@@ -159,8 +162,8 @@ export interface connectedPayload {
159
162
  requestHeaders: IncomingHttpHeaders;
160
163
  requestParameters: URLSearchParams;
161
164
  socketId: string;
162
- connection: ConnectionConfiguration;
163
- connectionInstance: Connection;
165
+ connectionConfig: ConnectionConfiguration;
166
+ connection: Connection;
164
167
  }
165
168
  export interface onLoadDocumentPayload {
166
169
  context: any;
@@ -170,7 +173,7 @@ export interface onLoadDocumentPayload {
170
173
  requestHeaders: IncomingHttpHeaders;
171
174
  requestParameters: URLSearchParams;
172
175
  socketId: string;
173
- connection: ConnectionConfiguration;
176
+ connectionConfig: ConnectionConfiguration;
174
177
  }
175
178
  export interface afterLoadDocumentPayload {
176
179
  context: any;
@@ -180,7 +183,7 @@ export interface afterLoadDocumentPayload {
180
183
  requestHeaders: IncomingHttpHeaders;
181
184
  requestParameters: URLSearchParams;
182
185
  socketId: string;
183
- connection: ConnectionConfiguration;
186
+ connectionConfig: ConnectionConfiguration;
184
187
  }
185
188
  export interface onChangePayload {
186
189
  clientsCount: number;
@@ -206,6 +209,27 @@ export interface beforeHandleMessagePayload {
206
209
  socketId: string;
207
210
  connection: Connection;
208
211
  }
212
+ export interface beforeSyncPayload {
213
+ clientsCount: number;
214
+ context: any;
215
+ document: Document;
216
+ documentName: string;
217
+ connection: Connection;
218
+ /**
219
+ * The y-protocols/sync message type
220
+ * @example
221
+ * 0: SyncStep1
222
+ * 1: SyncStep2
223
+ * 2: YjsUpdate
224
+ *
225
+ * @see https://github.com/yjs/y-protocols/blob/master/sync.js#L13-L40
226
+ */
227
+ type: number;
228
+ /**
229
+ * The payload of the y-sync message.
230
+ */
231
+ payload: Uint8Array;
232
+ }
209
233
  export interface beforeBroadcastStatelessPayload {
210
234
  document: Document;
211
235
  documentName: string;
@@ -250,7 +274,7 @@ export interface fetchPayload {
250
274
  requestHeaders: IncomingHttpHeaders;
251
275
  requestParameters: URLSearchParams;
252
276
  socketId: string;
253
- connection: ConnectionConfiguration;
277
+ connectionConfig: ConnectionConfiguration;
254
278
  }
255
279
  export interface storePayload extends onStoreDocumentPayload {
256
280
  state: Buffer;
@@ -293,6 +317,10 @@ export interface afterUnloadDocumentPayload {
293
317
  instance: Hocuspocus;
294
318
  documentName: string;
295
319
  }
320
+ export interface beforeUnloadDocumentPayload {
321
+ instance: Hocuspocus;
322
+ documentName: string;
323
+ }
296
324
  export interface DirectConnection {
297
325
  transact(transaction: (document: Document) => void): Promise<void>;
298
326
  disconnect(): void;
@@ -1,6 +1,6 @@
1
1
  import { Doc } from 'yjs';
2
2
  import { Schema } from '@tiptap/pm/model';
3
- import type { Transformer } from './types.js';
3
+ import type { Transformer } from './types.ts';
4
4
  declare class Prosemirror implements Transformer {
5
5
  defaultSchema: Schema;
6
6
  schema(schema: Schema): Prosemirror;
@@ -1,6 +1,6 @@
1
1
  import type { Doc } from 'yjs';
2
2
  import type { Extensions } from '@tiptap/core';
3
- import type { Transformer } from './types.js';
3
+ import type { Transformer } from './types.ts';
4
4
  export declare class Tiptap implements Transformer {
5
5
  defaultExtensions: Extensions;
6
6
  extensions(extensions: Extensions): Tiptap;
@@ -1,3 +1,3 @@
1
- export * from './Prosemirror.js';
2
- export * from './Tiptap.js';
3
- export * from './types.js';
1
+ export * from './Prosemirror.ts';
2
+ export * from './Tiptap.ts';
3
+ export * from './types.ts';
@@ -0,0 +1,2 @@
1
+ import type { HocuspocusProviderWebsocket } from "@hocuspocus/provider";
2
+ export declare const SocketContext: import("react").Context<HocuspocusProviderWebsocket | null>;
@@ -0,0 +1,3 @@
1
+ import type { NextConfig } from "next";
2
+ declare const nextConfig: NextConfig;
3
+ export default nextConfig;
@@ -1,9 +1,9 @@
1
- export * from './createDirectory.js';
2
- export * from './flushRedis.js';
3
- export * from './newHocuspocus.js';
4
- export * from './newHocuspocusProvider.js';
5
- export * from './newHocuspocusProviderWebsocket.js';
6
- export * from './randomInteger.js';
7
- export * from './redisConnectionSettings.js';
8
- export * from './removeDirectory.js';
9
- export * from './sleep.js';
1
+ export * from './createDirectory.ts';
2
+ export * from './flushRedis.ts';
3
+ export * from './newHocuspocus.ts';
4
+ export * from './newHocuspocusProvider.ts';
5
+ export * from './newHocuspocusProviderWebsocket.ts';
6
+ export * from './randomInteger.ts';
7
+ export * from './redisConnectionSettings.ts';
8
+ export * from './removeDirectory.ts';
9
+ export * from './sleep.ts';
@@ -1,3 +1,3 @@
1
- import { HocuspocusProvider, type HocuspocusProviderConfiguration, type HocuspocusProviderWebsocketConfiguration } from '@hocuspocus/provider';
1
+ import { HocuspocusProvider, type HocuspocusProviderConfiguration, type HocuspocusProviderWebsocket, type HocuspocusProviderWebsocketConfiguration } from '@hocuspocus/provider';
2
2
  import type { Hocuspocus } from '@hocuspocus/server';
3
- export declare const newHocuspocusProvider: (server: Hocuspocus, options?: Partial<HocuspocusProviderConfiguration>, websocketOptions?: Partial<HocuspocusProviderWebsocketConfiguration>) => HocuspocusProvider;
3
+ export declare const newHocuspocusProvider: (server: Hocuspocus, options?: Partial<HocuspocusProviderConfiguration>, websocketOptions?: Partial<HocuspocusProviderWebsocketConfiguration>, websocketProvider?: HocuspocusProviderWebsocket) => HocuspocusProvider;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hocuspocus/extension-redis",
3
- "version": "3.0.0-rc.0",
3
+ "version": "3.0.6-rc.0",
4
4
  "description": "Scale Hocuspocus horizontally with Redis",
5
5
  "homepage": "https://hocuspocus.dev",
6
6
  "keywords": [
@@ -15,7 +15,7 @@
15
15
  "types": "dist/packages/extension-redis/src/index.d.ts",
16
16
  "exports": {
17
17
  "source": {
18
- "import": "./src"
18
+ "import": "./src/index.ts"
19
19
  },
20
20
  "default": {
21
21
  "import": "./dist/hocuspocus-redis.esm.js",
@@ -33,12 +33,12 @@
33
33
  "@types/redlock": "^4.0.3"
34
34
  },
35
35
  "dependencies": {
36
- "@hocuspocus/server": "^3.0.0-rc.0",
36
+ "@hocuspocus/server": "^3.0.6-rc.0",
37
37
  "ioredis": "^4.28.2",
38
38
  "kleur": "^4.1.4",
39
39
  "lodash.debounce": "^4.0.8",
40
40
  "redlock": "^4.2.0",
41
- "uuid": "^10.0.0"
41
+ "uuid": "^11.0.3"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "y-protocols": "^1.0.6",
package/src/Redis.ts CHANGED
@@ -17,7 +17,6 @@ import {
17
17
  IncomingMessage,
18
18
  OutgoingMessage,
19
19
  MessageReceiver,
20
- Debugger,
21
20
  } from '@hocuspocus/server'
22
21
 
23
22
  export type RedisInstance = RedisClient.Cluster | RedisClient.Redis
@@ -98,19 +97,22 @@ export class Redis implements Extension {
98
97
 
99
98
  locks = new Map<string, Redlock.Lock>()
100
99
 
101
- logger: Debugger
102
-
103
100
  messagePrefix: Buffer
104
101
 
102
+ /**
103
+ * When we have a high frequency of updates to a document we don't need tons of setTimeouts
104
+ * piling up, so we'll track them to keep it to the most recent per document.
105
+ */
106
+ private pendingDisconnects = new Map<string, NodeJS.Timeout>()
107
+
108
+ private pendingAfterStoreDocumentResolves = new Map<string, { timeout: NodeJS.Timeout; resolve:() => void }>()
109
+
105
110
  public constructor(configuration: Partial<Configuration>) {
106
111
  this.configuration = {
107
112
  ...this.configuration,
108
113
  ...configuration,
109
114
  }
110
115
 
111
- // We’ll replace that in the onConfigure hook with the global instance.
112
- this.logger = new Debugger()
113
-
114
116
  // Create Redis instance
115
117
  const {
116
118
  port,
@@ -145,7 +147,6 @@ export class Redis implements Extension {
145
147
  }
146
148
 
147
149
  async onConfigure({ instance }: onConfigurePayload) {
148
- this.logger = instance.debugger
149
150
  this.instance = instance
150
151
  }
151
152
 
@@ -262,9 +263,27 @@ export class Redis implements Extension {
262
263
  // if the change was initiated by a directConnection, we need to delay this hook to make sure sync can finish first.
263
264
  // for provider connections, this usually happens in the onDisconnect hook
264
265
  if (socketId === 'server') {
265
- await new Promise(resolve => {
266
- setTimeout(() => resolve(''), this.configuration.disconnectDelay)
266
+ const pending = this.pendingAfterStoreDocumentResolves.get(documentName)
267
+
268
+ if (pending) {
269
+ clearTimeout(pending.timeout)
270
+ pending.resolve()
271
+ this.pendingAfterStoreDocumentResolves.delete(documentName)
272
+ }
273
+
274
+ let resolveFunction: () => void = () => {}
275
+ const delayedPromise = new Promise<void>(resolve => {
276
+ resolveFunction = resolve
267
277
  })
278
+
279
+ const timeout = setTimeout(() => {
280
+ this.pendingAfterStoreDocumentResolves.delete(documentName)
281
+ resolveFunction()
282
+ }, this.configuration.disconnectDelay)
283
+
284
+ this.pendingAfterStoreDocumentResolves.set(documentName, { timeout, resolve: resolveFunction })
285
+
286
+ await delayedPromise
268
287
  }
269
288
  }
270
289
 
@@ -303,14 +322,11 @@ export class Redis implements Extension {
303
322
  const document = this.instance.documents.get(documentName)
304
323
 
305
324
  if (!document) {
306
- // What does this mean? Why are we subscribed to this document?
307
- this.logger.log(`Received message for unknown document ${documentName}`)
308
325
  return
309
326
  }
310
327
 
311
328
  new MessageReceiver(
312
329
  message,
313
- this.logger,
314
330
  this.redisTransactionOrigin,
315
331
  ).apply(document, undefined, reply => {
316
332
  return this.pub.publishBuffer(
@@ -334,9 +350,18 @@ export class Redis implements Extension {
334
350
  * no one connected anymore.
335
351
  */
336
352
  public onDisconnect = async ({ documentName }: onDisconnectPayload) => {
353
+ const pending = this.pendingDisconnects.get(documentName)
354
+
355
+ if (pending) {
356
+ clearTimeout(pending)
357
+ this.pendingDisconnects.delete(documentName)
358
+ }
359
+
337
360
  const disconnect = () => {
338
361
  const document = this.instance.documents.get(documentName)
339
362
 
363
+ this.pendingDisconnects.delete(documentName)
364
+
340
365
  // Do nothing, when other users are still connected to the document.
341
366
  if (!document || document.getConnectionsCount() > 0) {
342
367
  return
@@ -352,7 +377,8 @@ export class Redis implements Extension {
352
377
  this.instance.unloadDocument(document)
353
378
  }
354
379
  // Delay the disconnect procedure to allow last minute syncs to happen
355
- setTimeout(disconnect, this.configuration.disconnectDelay)
380
+ const timeout = setTimeout(disconnect, this.configuration.disconnectDelay)
381
+ this.pendingDisconnects.set(documentName, timeout)
356
382
  }
357
383
 
358
384
  async beforeBroadcastStateless(data: beforeBroadcastStatelessPayload) {
package/src/index.ts CHANGED
@@ -1 +1 @@
1
- export * from './Redis.js'
1
+ export * from './Redis.ts'
@@ -1,64 +0,0 @@
1
- import type { AbstractType, YArrayEvent } from 'yjs';
2
- import * as Y from 'yjs';
3
- import type { HocuspocusProviderConfiguration } from './HocuspocusProvider.js';
4
- import { HocuspocusProvider } from './HocuspocusProvider.js';
5
- import { TiptapCollabProviderWebsocket } from './TiptapCollabProviderWebsocket.js';
6
- import type { TCollabComment, TCollabThread, THistoryVersion } from './types.js';
7
- export type TiptapCollabProviderConfiguration = Required<Pick<HocuspocusProviderConfiguration, 'name'>> & Partial<HocuspocusProviderConfiguration> & (Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'websocketProvider'>> | Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'appId'>> | Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'baseUrl'>>) & Pick<AdditionalTiptapCollabProviderConfiguration, 'user'>;
8
- export interface AdditionalTiptapCollabProviderConfiguration {
9
- /**
10
- * A Hocuspocus Cloud App ID, get one here: https://cloud.tiptap.dev
11
- */
12
- appId?: string;
13
- /**
14
- * If you are using the on-premise version of TiptapCollab, put your baseUrl here (e.g. https://collab.yourdomain.com)
15
- */
16
- baseUrl?: string;
17
- websocketProvider?: TiptapCollabProviderWebsocket;
18
- user?: string;
19
- }
20
- export declare class TiptapCollabProvider extends HocuspocusProvider {
21
- tiptapCollabConfigurationPrefix: string;
22
- userData?: Y.PermanentUserData;
23
- constructor(configuration: TiptapCollabProviderConfiguration);
24
- /**
25
- * note: this will only work if your server loaded @hocuspocus-pro/extension-history, or if you are on a Tiptap business plan.
26
- */
27
- createVersion(name?: string): void;
28
- /**
29
- * note: this will only work if your server loaded @hocuspocus-pro/extension-history, or if you are on a Tiptap business plan.
30
- */
31
- revertToVersion(targetVersion: number): void;
32
- /**
33
- * note: this will only work if your server loaded @hocuspocus-pro/extension-history, or if you are on a Tiptap business plan.
34
- *
35
- * The server will reply with a stateless message (THistoryVersionPreviewEvent)
36
- */
37
- previewVersion(targetVersion: number): void;
38
- /**
39
- * note: this will only work if your server loaded @hocuspocus-pro/extension-history, or if you are on a Tiptap business plan.
40
- */
41
- getVersions(): THistoryVersion[];
42
- watchVersions(callback: Parameters<AbstractType<YArrayEvent<THistoryVersion>>['observe']>[0]): void;
43
- unwatchVersions(callback: Parameters<AbstractType<YArrayEvent<THistoryVersion>>['unobserve']>[0]): void;
44
- isAutoVersioning(): boolean;
45
- enableAutoVersioning(): 1;
46
- disableAutoVersioning(): 0;
47
- private getYThreads;
48
- getThreads<Data, CommentData>(): TCollabThread<Data, CommentData>[];
49
- private getThreadIndex;
50
- getThread<Data, CommentData>(id: string): TCollabThread<Data, CommentData> | null;
51
- private getYThread;
52
- createThread(data: Omit<TCollabThread, 'id' | 'createdAt' | 'updatedAt' | 'comments'>): TCollabThread;
53
- updateThread(id: TCollabThread['id'], data: Partial<Pick<TCollabThread, 'data'> & {
54
- resolvedAt: TCollabThread['resolvedAt'] | null;
55
- }>): TCollabThread;
56
- deleteThread(id: TCollabThread['id']): void;
57
- getThreadComments(threadId: TCollabThread['id']): TCollabComment[] | null;
58
- getThreadComment(threadId: TCollabThread['id'], commentId: TCollabComment['id']): TCollabComment | null;
59
- addComment(threadId: TCollabThread['id'], data: Omit<TCollabComment, 'id' | 'updatedAt' | 'createdAt'>): TCollabThread;
60
- updateComment(threadId: TCollabThread['id'], commentId: TCollabComment['id'], data: Partial<Pick<TCollabComment, 'data' | 'content'>>): TCollabThread;
61
- deleteComment(threadId: TCollabThread['id'], commentId: TCollabComment['id']): TCollabThread | null | undefined;
62
- watchThreads(callback: () => void): void;
63
- unwatchThreads(callback: () => void): void;
64
- }
@@ -1,20 +0,0 @@
1
- import type { CompleteHocuspocusProviderWebsocketConfiguration } from './HocuspocusProviderWebsocket.js';
2
- import { HocuspocusProviderWebsocket } from './HocuspocusProviderWebsocket.js';
3
- export type TiptapCollabProviderWebsocketConfiguration = Partial<CompleteHocuspocusProviderWebsocketConfiguration> & AdditionalTiptapCollabProviderWebsocketConfiguration;
4
- export interface AdditionalTiptapCollabProviderWebsocketConfiguration {
5
- /**
6
- * A Hocuspocus Cloud App ID, get one here: https://cloud.tiptap.dev
7
- */
8
- appId?: string;
9
- /**
10
- * If you are using the on-premise version of TiptapCollab, put your baseUrl here (e.g. https://collab.yourdomain.com)
11
- */
12
- baseUrl?: string;
13
- /**
14
- * Only fill this if you are using Tiptap Collab HA.
15
- */
16
- shardKey?: string;
17
- }
18
- export declare class TiptapCollabProviderWebsocket extends HocuspocusProviderWebsocket {
19
- constructor(configuration: TiptapCollabProviderWebsocketConfiguration);
20
- }
@@ -1,14 +0,0 @@
1
- export declare class Debugger {
2
- logs: any[];
3
- listen: boolean;
4
- output: boolean;
5
- enable(): void;
6
- disable(): void;
7
- verbose(): void;
8
- quiet(): void;
9
- log(message: any): this;
10
- flush(): this;
11
- get(): {
12
- logs: any[];
13
- };
14
- }
@@ -1,2 +0,0 @@
1
- declare const _default: import("vite").UserConfig;
2
- export default _default;
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};