@hocuspocus/extension-database 2.5.0-rc.0 → 2.6.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.
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import RedisClient, { ClusterNode, ClusterOptions, RedisOptions } from 'ioredis';
2
3
  import Redlock from 'redlock';
3
4
  import { Extension, afterLoadDocumentPayload, afterStoreDocumentPayload, onDisconnectPayload, onStoreDocumentPayload, onAwarenessUpdatePayload, onChangePayload, Debugger, onConfigurePayload, beforeBroadcastStatelessPayload, Hocuspocus } from '@hocuspocus/server';
@@ -56,18 +57,22 @@ export declare class Redis implements Extension {
56
57
  */
57
58
  priority: number;
58
59
  configuration: Configuration;
60
+ redisTransactionOrigin: string;
59
61
  pub: RedisInstance;
60
62
  sub: RedisInstance;
61
63
  instance: Hocuspocus;
62
64
  redlock: Redlock;
63
65
  locks: Map<string, Redlock.Lock>;
64
66
  logger: Debugger;
67
+ messagePrefix: Buffer;
65
68
  constructor(configuration: Partial<Configuration>);
66
69
  onConfigure({ instance }: onConfigurePayload): Promise<void>;
67
70
  private getKey;
68
71
  private pubKey;
69
72
  private subKey;
70
73
  private lockKey;
74
+ private encodeMessage;
75
+ private decodeMessage;
71
76
  /**
72
77
  * Once a document is loaded, subscribe to the channel in Redis.
73
78
  */
@@ -94,7 +99,7 @@ export declare class Redis implements Extension {
94
99
  */
95
100
  onAwarenessUpdate({ documentName, awareness, added, updated, removed, }: onAwarenessUpdatePayload): Promise<number>;
96
101
  /**
97
- * Handle incoming messages published on all subscribed document channels.
102
+ * Handle incoming messages published on subscribed document channels.
98
103
  * Note that this will also include messages from ourselves as it is not possible
99
104
  * in Redis to filter these.
100
105
  */
@@ -4,6 +4,9 @@ import { Event } from 'ws';
4
4
  import EventEmitter from './EventEmitter.js';
5
5
  import { HocuspocusProvider } from './HocuspocusProvider.js';
6
6
  import { WebSocketStatus, onAwarenessChangeParameters, onAwarenessUpdateParameters, onCloseParameters, onDisconnectParameters, onMessageParameters, onOpenParameters, onOutgoingMessageParameters, onStatusParameters } from './types.js';
7
+ export type HocusPocusWebSocket = WebSocket & {
8
+ identifier: string;
9
+ };
7
10
  export type HocuspocusProviderWebsocketConfiguration = Required<Pick<CompleteHocuspocusProviderWebsocketConfiguration, 'url'>> & Partial<CompleteHocuspocusProviderWebsocketConfiguration>;
8
11
  export interface CompleteHocuspocusProviderWebsocketConfiguration {
9
12
  /**
@@ -79,10 +82,14 @@ export declare class HocuspocusProviderWebsocket extends EventEmitter {
79
82
  private messageQueue;
80
83
  configuration: CompleteHocuspocusProviderWebsocketConfiguration;
81
84
  subscribedToBroadcastChannel: boolean;
82
- webSocket: WebSocket | null;
85
+ webSocket: HocusPocusWebSocket | null;
86
+ webSocketHandlers: {
87
+ [key: string]: any;
88
+ };
83
89
  shouldConnect: boolean;
84
90
  status: WebSocketStatus;
85
91
  lastMessageReceived: number;
92
+ identifier: number;
86
93
  mux: mutex.mutex;
87
94
  intervals: any;
88
95
  connectionAttempt: {
@@ -100,6 +107,8 @@ export declare class HocuspocusProviderWebsocket extends EventEmitter {
100
107
  boundConnect: () => Promise<unknown>;
101
108
  cancelWebsocketRetry?: () => void;
102
109
  connect(): Promise<unknown>;
110
+ attachWebSocketListeners(ws: HocusPocusWebSocket, reject: Function): void;
111
+ cleanupWebSocket(): void;
103
112
  createWebSocketConnection(): Promise<unknown>;
104
113
  onMessage(event: MessageEvent): void;
105
114
  resolveConnectionAttempt(): void;
@@ -107,7 +116,6 @@ export declare class HocuspocusProviderWebsocket extends EventEmitter {
107
116
  rejectConnectionAttempt(): void;
108
117
  closeTries: number;
109
118
  checkConnection(): void;
110
- registerEventListeners(): void;
111
119
  get serverUrl(): string;
112
120
  get url(): string;
113
121
  disconnect(): void;
@@ -1,6 +1,7 @@
1
1
  import type { AbstractType, YArrayEvent } from 'yjs';
2
2
  import { HocuspocusProvider, HocuspocusProviderConfiguration } from './HocuspocusProvider.js';
3
3
  import { TiptapCollabProviderWebsocket } from './TiptapCollabProviderWebsocket.js';
4
+ import type { THistoryVersion } from './types';
4
5
  export type TiptapCollabProviderConfiguration = Required<Pick<HocuspocusProviderConfiguration, 'name'>> & Partial<HocuspocusProviderConfiguration> & (Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'websocketProvider'>> | Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'appId'>>);
5
6
  export interface AdditionalTiptapCollabProviderConfiguration {
6
7
  /**
@@ -9,19 +10,29 @@ export interface AdditionalTiptapCollabProviderConfiguration {
9
10
  appId?: string;
10
11
  websocketProvider?: TiptapCollabProviderWebsocket;
11
12
  }
12
- export type AuditHistoryVersion = {
13
- name?: string;
14
- version: number;
15
- date: number;
16
- };
17
13
  export declare class TiptapCollabProvider extends HocuspocusProvider {
18
14
  tiptapCollabConfigurationPrefix: string;
19
15
  constructor(configuration: TiptapCollabProviderConfiguration);
16
+ /**
17
+ * note: this will only work if your server loaded @hocuspocus-pro/extension-history, or if you are on a Tiptap business plan.
18
+ */
20
19
  createVersion(name?: string): void;
20
+ /**
21
+ * note: this will only work if your server loaded @hocuspocus-pro/extension-history, or if you are on a Tiptap business plan.
22
+ */
21
23
  revertToVersion(targetVersion: number): void;
22
- getVersions(): AuditHistoryVersion[];
23
- watchVersions(callback: Parameters<AbstractType<YArrayEvent<AuditHistoryVersion>>['observe']>[0]): void;
24
- unwatchVersions(callback: Parameters<AbstractType<YArrayEvent<AuditHistoryVersion>>['unobserve']>[0]): void;
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
+ * The server will reply with a stateless message (THistoryVersionPreviewEvent)
28
+ */
29
+ previewVersion(targetVersion: number): void;
30
+ /**
31
+ * note: this will only work if your server loaded @hocuspocus-pro/extension-history, or if you are on a Tiptap business plan.
32
+ */
33
+ getVersions(): THistoryVersion[];
34
+ watchVersions(callback: Parameters<AbstractType<YArrayEvent<THistoryVersion>>['observe']>[0]): void;
35
+ unwatchVersions(callback: Parameters<AbstractType<YArrayEvent<THistoryVersion>>['unobserve']>[0]): void;
25
36
  isAutoVersioning(): boolean;
26
37
  enableAutoVersioning(): 1;
27
38
  disableAutoVersioning(): 0;
@@ -84,3 +84,48 @@ export type StatesArray = {
84
84
  clientId: number;
85
85
  [key: string | number]: any;
86
86
  }[];
87
+ export type THistoryVersion = {
88
+ name?: string;
89
+ version: number;
90
+ date: number;
91
+ };
92
+ export type THistoryConfiguration = {
93
+ autoVersioning: boolean;
94
+ currentVersion: number;
95
+ stateCaptured: number;
96
+ };
97
+ export type THistoryAction = THistoryDocumentRevertAction | THistoryVersionCreateAction | THistoryVersionPreviewAction;
98
+ export type THistoryDocumentRevertAction = {
99
+ action: 'document.revert';
100
+ /**
101
+ * if changes havent been persisted to a version yet, we'll create one with the specified name,
102
+ * expect when `false` is passed.
103
+ */
104
+ currentVersionName?: string | false;
105
+ /**
106
+ * Name of the version that is created after the revert. Pass `false` to avoid generating a new version.
107
+ */
108
+ newVersionName?: string | false;
109
+ };
110
+ export type THistoryVersionCreateAction = {
111
+ action: 'version.create';
112
+ name?: string;
113
+ };
114
+ export type THistoryVersionPreviewAction = {
115
+ action: 'version.preview';
116
+ version: number;
117
+ };
118
+ export type THistoryEvent = THistoryVersionPreviewEvent | THistoryVersionCreatedEvent | THistoryDocumentRevertedEvent;
119
+ export type THistoryVersionCreatedEvent = {
120
+ event: 'version.created';
121
+ version: number;
122
+ };
123
+ export type THistoryVersionPreviewEvent = {
124
+ event: 'version.preview';
125
+ version: number;
126
+ ydoc: string;
127
+ };
128
+ export type THistoryDocumentRevertedEvent = {
129
+ event: 'document.reverted';
130
+ version: number;
131
+ };
@@ -1,5 +1,4 @@
1
1
  /// <reference types="node" />
2
- /// <reference types="node" />
3
2
  import { IncomingMessage } from 'http';
4
3
  import WebSocket, { AddressInfo } from 'ws';
5
4
  import { Server as HocuspocusServer } from './Server';
@@ -29,6 +28,7 @@ export declare class Hocuspocus {
29
28
  documents: Map<string, Document>;
30
29
  server?: HocuspocusServer;
31
30
  debugger: Debugger;
31
+ debounce: (id: string, func: Function, debounce: number, maxDebounce: number) => void;
32
32
  constructor(configuration?: Partial<Configuration>);
33
33
  /**
34
34
  * Configure the server
@@ -78,14 +78,6 @@ export declare class Hocuspocus {
78
78
  * the update is incoming from the provider, but can be anything if the updates is originated from an extension.
79
79
  */
80
80
  private handleDocumentUpdate;
81
- timers: Map<string, {
82
- timeout: NodeJS.Timeout;
83
- start: number;
84
- }>;
85
- /**
86
- * debounce the given function, using the given identifier
87
- */
88
- debounce(id: string, func: Function, immediately?: boolean): void;
89
81
  /**
90
82
  * Create a new document by the given request
91
83
  */
@@ -5,7 +5,8 @@ import { IncomingMessage } from './IncomingMessage.js';
5
5
  export declare class MessageReceiver {
6
6
  message: IncomingMessage;
7
7
  logger: Debugger;
8
- constructor(message: IncomingMessage, logger: Debugger);
8
+ defaultTransactionOrigin?: string;
9
+ constructor(message: IncomingMessage, logger: Debugger, defaultTransactionOrigin?: string);
9
10
  apply(document: Document, connection?: Connection, reply?: (message: Uint8Array) => void): void;
10
11
  readSyncMessage(message: IncomingMessage, document: Document, connection?: Connection, reply?: (message: Uint8Array) => void, requestFirstSync?: boolean): 0 | 1 | 2;
11
12
  applyQueryAwarenessMessage(document: Document, reply?: (message: Uint8Array) => void): void;
@@ -6,3 +6,4 @@ export * from './IncomingMessage.js';
6
6
  export * from './MessageReceiver.js';
7
7
  export * from './OutgoingMessage.js';
8
8
  export * from './types.js';
9
+ export * from './util/debounce.js';
@@ -39,7 +39,7 @@ export interface Extension {
39
39
  connected?(data: connectedPayload): Promise<any>;
40
40
  onAuthenticate?(data: onAuthenticatePayload): Promise<any>;
41
41
  onLoadDocument?(data: onLoadDocumentPayload): Promise<any>;
42
- afterLoadDocument?(data: onLoadDocumentPayload): Promise<any>;
42
+ afterLoadDocument?(data: afterLoadDocumentPayload): Promise<any>;
43
43
  beforeHandleMessage?(data: beforeHandleMessagePayload): Promise<any>;
44
44
  beforeBroadcastStateless?(data: beforeBroadcastStatelessPayload): Promise<any>;
45
45
  onStateless?(payload: onStatelessPayload): Promise<any>;
@@ -49,7 +49,7 @@ export interface Extension {
49
49
  onAwarenessUpdate?(data: onAwarenessUpdatePayload): Promise<any>;
50
50
  onRequest?(data: onRequestPayload): Promise<any>;
51
51
  onDisconnect?(data: onDisconnectPayload): Promise<any>;
52
- afterUnloadDocument?(data: onLoadDocumentPayload): Promise<any>;
52
+ afterUnloadDocument?(data: afterUnloadDocumentPayload): Promise<any>;
53
53
  onDestroy?(data: onDestroyPayload): Promise<any>;
54
54
  }
55
55
  export type HookName = 'onConfigure' | 'onListen' | 'onUpgrade' | 'onConnect' | 'connected' | 'onAuthenticate' | 'onLoadDocument' | 'afterLoadDocument' | 'beforeHandleMessage' | 'beforeBroadcastStateless' | 'onStateless' | 'onChange' | 'onStoreDocument' | 'afterStoreDocument' | 'onAwarenessUpdate' | 'onRequest' | 'onDisconnect' | 'afterUnloadDocument' | 'onDestroy';
@@ -61,7 +61,7 @@ export type HookPayloadByName = {
61
61
  connected: connectedPayload;
62
62
  onAuthenticate: onAuthenticatePayload;
63
63
  onLoadDocument: onLoadDocumentPayload;
64
- afterLoadDocument: onLoadDocumentPayload;
64
+ afterLoadDocument: afterLoadDocumentPayload;
65
65
  beforeHandleMessage: beforeHandleMessagePayload;
66
66
  beforeBroadcastStateless: beforeBroadcastStatelessPayload;
67
67
  onStateless: onStatelessPayload;
@@ -123,15 +123,6 @@ export interface Configuration extends Extension {
123
123
  gc: boolean;
124
124
  gcFilter: () => boolean;
125
125
  };
126
- /**
127
- * Function which returns the (customized) document name based on the request
128
- */
129
- getDocumentName?(data: getDocumentNamePayload): string | Promise<string>;
130
- }
131
- export interface getDocumentNamePayload {
132
- documentName: string;
133
- request: IncomingMessage;
134
- requestParameters: URLSearchParams;
135
126
  }
136
127
  export interface onStatelessPayload {
137
128
  connection: Connection;
@@ -149,6 +140,7 @@ export interface onAuthenticatePayload {
149
140
  connection: ConnectionConfiguration;
150
141
  }
151
142
  export interface onConnectPayload {
143
+ context: any;
152
144
  documentName: string;
153
145
  instance: Hocuspocus;
154
146
  request: IncomingMessage;
@@ -0,0 +1 @@
1
+ export declare const useDebounce: () => (id: string, func: Function, debounce: number, maxDebounce: number) => void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hocuspocus/extension-database",
3
3
  "description": "a generic Hocuspocus persistence driver for the database",
4
- "version": "2.5.0-rc.0",
4
+ "version": "2.6.0",
5
5
  "homepage": "https://hocuspocus.dev",
6
6
  "keywords": [
7
7
  "hocuspocus",
@@ -27,7 +27,7 @@
27
27
  "dist"
28
28
  ],
29
29
  "dependencies": {
30
- "@hocuspocus/server": "^2.5.0-rc.0"
30
+ "@hocuspocus/server": "^2.6.0"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "yjs": "^13.6.4"
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};