@hocuspocus/extension-redis 3.0.0-rc.0 → 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 (33) 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/auth.d.ts +1 -1
  6. package/dist/packages/extension-redis/src/Redis.d.ts +8 -2
  7. package/dist/packages/extension-throttle/src/index.d.ts +1 -0
  8. package/dist/packages/extension-webhook/src/index.d.ts +1 -0
  9. package/dist/packages/provider/src/HocuspocusProvider.d.ts +11 -33
  10. package/dist/packages/provider/src/HocuspocusProviderWebsocket.d.ts +0 -4
  11. package/dist/packages/provider/src/MessageReceiver.d.ts +0 -2
  12. package/dist/packages/provider/src/index.d.ts +0 -2
  13. package/dist/packages/provider/src/types.d.ts +42 -2
  14. package/dist/packages/server/src/ClientConnection.d.ts +15 -5
  15. package/dist/packages/server/src/Connection.d.ts +3 -17
  16. package/dist/packages/server/src/DirectConnection.d.ts +1 -1
  17. package/dist/packages/server/src/Document.d.ts +1 -5
  18. package/dist/packages/server/src/Hocuspocus.d.ts +3 -11
  19. package/dist/packages/server/src/MessageReceiver.d.ts +1 -3
  20. package/dist/packages/server/src/OutgoingMessage.d.ts +1 -0
  21. package/dist/packages/server/src/Server.d.ts +3 -2
  22. package/dist/packages/server/src/index.d.ts +0 -1
  23. package/dist/packages/server/src/types.d.ts +20 -11
  24. package/dist/packages/server/src/util/getParameters.d.ts +2 -0
  25. package/dist/tests/utils/newHocuspocusProvider.d.ts +2 -2
  26. package/dist/tests/utils/newHocuspocusProviderWebsocket.d.ts +1 -1
  27. package/package.json +3 -3
  28. package/src/Redis.ts +39 -13
  29. package/dist/packages/provider/src/TiptapCollabProvider.d.ts +0 -64
  30. package/dist/packages/provider/src/TiptapCollabProviderWebsocket.d.ts +0 -20
  31. package/dist/packages/server/src/Debugger.d.ts +0 -14
  32. package/dist/tests/server/getMessageLogs.d.ts +0 -1
  33. package/dist/tests/server/requiresAuthentication.d.ts +0 -1
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) {
@@ -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 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};