@hocuspocus/provider 2.14.0 → 2.15.1-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.
@@ -2,7 +2,7 @@ import type { AbstractType, YArrayEvent } from 'yjs';
2
2
  import * as Y from 'yjs';
3
3
  import { HocuspocusProvider, HocuspocusProviderConfiguration } from './HocuspocusProvider.js';
4
4
  import { TiptapCollabProviderWebsocket } from './TiptapCollabProviderWebsocket.js';
5
- import type { DeleteCommentOptions, TCollabComment, TCollabThread, THistoryVersion } from './types.js';
5
+ import { type DeleteCommentOptions, type DeleteThreadOptions, type GetThreadsOptions, type TCollabComment, type TCollabThread, type THistoryVersion } from './types.js';
6
6
  export type TiptapCollabProviderConfiguration = Required<Pick<HocuspocusProviderConfiguration, 'name'>> & Partial<HocuspocusProviderConfiguration> & (Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'websocketProvider'>> | Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'appId'>> | Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'baseUrl'>>) & Pick<AdditionalTiptapCollabProviderConfiguration, 'user'> & {
7
7
  /**
8
8
  * Pass `true` if you want to delete a thread when the first comment is deleted.
@@ -55,9 +55,10 @@ export declare class TiptapCollabProvider extends HocuspocusProvider {
55
55
  private getYThreads;
56
56
  /**
57
57
  * Finds all threads in the document and returns them as JSON objects
58
+ * @options Options to control the output of the threads (e.g. include deleted threads)
58
59
  * @returns An array of threads as JSON objects
59
60
  */
60
- getThreads<Data, CommentData>(): TCollabThread<Data, CommentData>[];
61
+ getThreads<Data, CommentData>(options?: GetThreadsOptions): TCollabThread<Data, CommentData>[];
61
62
  /**
62
63
  * Find the index of a thread by its id
63
64
  * @param id The thread id
@@ -81,7 +82,7 @@ export declare class TiptapCollabProvider extends HocuspocusProvider {
81
82
  * @param data The thread data
82
83
  * @returns The created thread
83
84
  */
84
- createThread(data: Omit<TCollabThread, 'id' | 'createdAt' | 'updatedAt' | 'comments' | 'deletedComments'>): TCollabThread;
85
+ createThread(data: Omit<TCollabThread, 'id' | 'createdAt' | 'updatedAt' | 'deletedAt' | 'comments' | 'deletedComments'>): TCollabThread;
85
86
  /**
86
87
  * Update a specific thread
87
88
  * @param id The thread id
@@ -92,11 +93,21 @@ export declare class TiptapCollabProvider extends HocuspocusProvider {
92
93
  resolvedAt: TCollabThread['resolvedAt'] | null;
93
94
  }>): TCollabThread;
94
95
  /**
95
- * Delete a specific thread and all its comments
96
+ * Handle the deletion of a thread. By default, the thread and it's comments are not deleted, but marked as deleted
97
+ * via the `deletedAt` property. Forceful deletion can be enabled by setting the `force` option to `true`.
98
+ *
99
+ * If you only want to delete the comments of a thread, you can set the `deleteComments` option to `true`.
100
+ * @param id The thread id
101
+ * @param options A set of options that control how the thread is deleted
102
+ * @returns The deleted thread or null if the thread is not found
103
+ */
104
+ deleteThread(id: TCollabThread['id'], options?: DeleteThreadOptions): TCollabThread | null | undefined;
105
+ /**
106
+ * Tries to restore a deleted thread
96
107
  * @param id The thread id
97
- * @returns void
108
+ * @returns The restored thread or null if the thread is not found
98
109
  */
99
- deleteThread(id: TCollabThread['id']): void;
110
+ restoreThread(id: TCollabThread['id']): TCollabThread | null;
100
111
  /**
101
112
  * Returns comments from a thread, either deleted or not
102
113
  * @param threadId The thread id
@@ -88,6 +88,7 @@ export type TCollabThread<Data = any, CommentData = any> = {
88
88
  id: string;
89
89
  createdAt: number;
90
90
  updatedAt: number;
91
+ deletedAt: number | null;
91
92
  resolvedAt?: string;
92
93
  comments: TCollabComment<CommentData>[];
93
94
  deletedComments: TCollabComment<CommentData>[];
@@ -156,3 +157,30 @@ export type DeleteCommentOptions = {
156
157
  */
157
158
  deleteContent?: boolean;
158
159
  };
160
+ export type DeleteThreadOptions = {
161
+ /**
162
+ * If `true`, will remove the comments on the thread,
163
+ * otherwise will only mark the thread as deleted
164
+ * and keep the comments
165
+ * @default false
166
+ */
167
+ deleteComments?: boolean;
168
+ /**
169
+ * If `true`, will forcefully remove the thread and all comments,
170
+ * otherwise will only mark the thread as deleted
171
+ * and keep the comments
172
+ * @default false
173
+ */
174
+ force?: boolean;
175
+ };
176
+ /**
177
+ * The type of thread
178
+ */
179
+ export type ThreadType = 'archived' | 'unarchived';
180
+ export type GetThreadsOptions = {
181
+ /**
182
+ * The types of threads to get
183
+ * @default ['unarchived']
184
+ */
185
+ types?: Array<ThreadType>;
186
+ };
@@ -95,7 +95,7 @@ export declare class Hocuspocus {
95
95
  * Runs the given callback after each hook.
96
96
  */
97
97
  hooks<T extends HookName>(name: T, payload: HookPayloadByName[T], callback?: Function | null): Promise<any>;
98
- unloadDocument(document: Document): void;
98
+ unloadDocument(document: Document): Promise<any>;
99
99
  enableDebugging(): void;
100
100
  enableMessageLogging(): void;
101
101
  disableLogging(): void;
@@ -1,3 +1,3 @@
1
- import { HocuspocusProvider, HocuspocusProviderConfiguration, HocuspocusProviderWebsocketConfiguration } from '@hocuspocus/provider';
1
+ import { HocuspocusProvider, HocuspocusProviderConfiguration, HocuspocusProviderWebsocket, HocuspocusProviderWebsocketConfiguration } from '@hocuspocus/provider';
2
2
  import { 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/provider",
3
- "version": "2.14.0",
3
+ "version": "2.15.1-rc.0",
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": "^2.14.0",
32
+ "@hocuspocus/common": "^2.15.1-rc.0",
33
33
  "@lifeomic/attempt": "^3.0.2",
34
34
  "lib0": "^0.2.87",
35
35
  "ws": "^8.17.1"
@@ -7,9 +7,11 @@ import {
7
7
  } from './HocuspocusProvider.js'
8
8
 
9
9
  import { TiptapCollabProviderWebsocket } from './TiptapCollabProviderWebsocket.js'
10
- import type {
11
- DeleteCommentOptions,
12
- TCollabComment, TCollabThread, THistoryVersion,
10
+ import {
11
+ type DeleteCommentOptions,
12
+ type DeleteThreadOptions,
13
+ type GetThreadsOptions,
14
+ type TCollabComment, type TCollabThread, type THistoryVersion,
13
15
  } from './types.js'
14
16
 
15
17
  const defaultDeleteCommentOptions: DeleteCommentOptions = {
@@ -17,6 +19,15 @@ const defaultDeleteCommentOptions: DeleteCommentOptions = {
17
19
  deleteThread: false,
18
20
  }
19
21
 
22
+ const defaultGetThreadsOptions: GetThreadsOptions = {
23
+ types: ['unarchived'],
24
+ }
25
+
26
+ const defaultDeleteThreadOptions: DeleteThreadOptions = {
27
+ deleteComments: false,
28
+ force: false,
29
+ }
30
+
20
31
  export type TiptapCollabProviderConfiguration =
21
32
  Required<Pick<HocuspocusProviderConfiguration, 'name'>> &
22
33
  Partial<HocuspocusProviderConfiguration> &
@@ -128,10 +139,29 @@ export class TiptapCollabProvider extends HocuspocusProvider {
128
139
 
129
140
  /**
130
141
  * Finds all threads in the document and returns them as JSON objects
142
+ * @options Options to control the output of the threads (e.g. include deleted threads)
131
143
  * @returns An array of threads as JSON objects
132
144
  */
133
- getThreads<Data, CommentData>(): TCollabThread<Data, CommentData>[] {
134
- return this.getYThreads().toJSON() as TCollabThread<Data, CommentData>[]
145
+ getThreads<Data, CommentData>(options?: GetThreadsOptions): TCollabThread<Data, CommentData>[] {
146
+ const { types } = { ...defaultGetThreadsOptions, ...options } as GetThreadsOptions
147
+
148
+ const threads = this.getYThreads().toJSON() as TCollabThread<Data, CommentData>[]
149
+
150
+ if (types?.includes('archived') && types?.includes('unarchived')) {
151
+ return threads
152
+ }
153
+
154
+ return threads.filter(currentThead => {
155
+ if (types?.includes('archived') && currentThead.deletedAt) {
156
+ return true
157
+ }
158
+
159
+ if (types?.includes('unarchived') && !currentThead.deletedAt) {
160
+ return true
161
+ }
162
+
163
+ return false
164
+ })
135
165
  }
136
166
 
137
167
  /**
@@ -144,7 +174,7 @@ export class TiptapCollabProvider extends HocuspocusProvider {
144
174
 
145
175
  let i = 0
146
176
  // eslint-disable-next-line no-restricted-syntax
147
- for (const thread of this.getThreads()) {
177
+ for (const thread of this.getThreads({ types: ['archived', 'unarchived'] })) {
148
178
  if (thread.id === id) {
149
179
  index = i
150
180
  break
@@ -190,7 +220,7 @@ export class TiptapCollabProvider extends HocuspocusProvider {
190
220
  * @param data The thread data
191
221
  * @returns The created thread
192
222
  */
193
- createThread(data: Omit<TCollabThread, 'id' | 'createdAt' | 'updatedAt' | 'comments' | 'deletedComments'>) {
223
+ createThread(data: Omit<TCollabThread, 'id' | 'createdAt' | 'updatedAt' | 'deletedAt' | 'comments' | 'deletedComments'>) {
194
224
  let createdThread: TCollabThread = {} as TCollabThread
195
225
 
196
226
  this.document.transact(() => {
@@ -199,6 +229,7 @@ export class TiptapCollabProvider extends HocuspocusProvider {
199
229
  thread.set('createdAt', (new Date()).toISOString())
200
230
  thread.set('comments', new Y.Array())
201
231
  thread.set('deletedComments', new Y.Array())
232
+ thread.set('deletedAt', null)
202
233
 
203
234
  this.getYThreads().push([thread])
204
235
  createdThread = this.updateThread(String(thread.get('id')), data)
@@ -242,18 +273,57 @@ export class TiptapCollabProvider extends HocuspocusProvider {
242
273
  }
243
274
 
244
275
  /**
245
- * Delete a specific thread and all its comments
276
+ * Handle the deletion of a thread. By default, the thread and it's comments are not deleted, but marked as deleted
277
+ * via the `deletedAt` property. Forceful deletion can be enabled by setting the `force` option to `true`.
278
+ *
279
+ * If you only want to delete the comments of a thread, you can set the `deleteComments` option to `true`.
246
280
  * @param id The thread id
247
- * @returns void
281
+ * @param options A set of options that control how the thread is deleted
282
+ * @returns The deleted thread or null if the thread is not found
248
283
  */
249
- deleteThread(id: TCollabThread['id']) {
284
+ deleteThread(id: TCollabThread['id'], options?: DeleteThreadOptions) {
285
+ const { deleteComments, force } = { ...defaultDeleteThreadOptions, ...options }
286
+
250
287
  const index = this.getThreadIndex(id)
251
288
 
252
289
  if (index === null) {
290
+ return null
291
+ }
292
+
293
+ if (force) {
294
+ this.getYThreads().delete(index, 1)
253
295
  return
254
296
  }
255
297
 
256
- this.getYThreads().delete(index, 1)
298
+ const thread = this.getYThreads().get(index)
299
+
300
+ thread.set('deletedAt', (new Date()).toISOString())
301
+
302
+ if (deleteComments) {
303
+ thread.set('comments', new Y.Array())
304
+ thread.set('deletedComments', new Y.Array())
305
+ }
306
+
307
+ return thread.toJSON() as TCollabThread
308
+ }
309
+
310
+ /**
311
+ * Tries to restore a deleted thread
312
+ * @param id The thread id
313
+ * @returns The restored thread or null if the thread is not found
314
+ */
315
+ restoreThread(id: TCollabThread['id']) {
316
+ const index = this.getThreadIndex(id)
317
+
318
+ if (index === null) {
319
+ return null
320
+ }
321
+
322
+ const thread = this.getYThreads().get(index)
323
+
324
+ thread.set('deletedAt', null)
325
+
326
+ return thread.toJSON() as TCollabThread
257
327
  }
258
328
 
259
329
  /**
@@ -406,7 +476,11 @@ export class TiptapCollabProvider extends HocuspocusProvider {
406
476
  newComment.set('data', comment.get('data'))
407
477
  newComment.set('content', deleteContent ? null : comment.get('content'))
408
478
 
479
+ if (!thread.get('deletedComments')) {
480
+ thread.set('deletedComments', new Y.Array())
481
+ }
409
482
  thread.get('deletedComments').push([newComment])
483
+
410
484
  thread.get('comments').delete(commentIndex)
411
485
 
412
486
  return thread.toJSON() as TCollabThread
package/src/types.ts CHANGED
@@ -110,6 +110,7 @@ export type TCollabThread<Data = any, CommentData = any> = {
110
110
  id: string;
111
111
  createdAt: number;
112
112
  updatedAt: number;
113
+ deletedAt: number | null;
113
114
  resolvedAt?: string; // (new Date()).toISOString()
114
115
  comments: TCollabComment<CommentData>[];
115
116
  deletedComments: TCollabComment<CommentData>[];
@@ -197,3 +198,34 @@ export type DeleteCommentOptions = {
197
198
  */
198
199
  deleteContent?: boolean
199
200
  }
201
+
202
+ export type DeleteThreadOptions = {
203
+ /**
204
+ * If `true`, will remove the comments on the thread,
205
+ * otherwise will only mark the thread as deleted
206
+ * and keep the comments
207
+ * @default false
208
+ */
209
+ deleteComments?: boolean
210
+
211
+ /**
212
+ * If `true`, will forcefully remove the thread and all comments,
213
+ * otherwise will only mark the thread as deleted
214
+ * and keep the comments
215
+ * @default false
216
+ */
217
+ force?: boolean,
218
+ }
219
+
220
+ /**
221
+ * The type of thread
222
+ */
223
+ export type ThreadType = 'archived' | 'unarchived'
224
+
225
+ export type GetThreadsOptions = {
226
+ /**
227
+ * The types of threads to get
228
+ * @default ['unarchived']
229
+ */
230
+ types?: Array<ThreadType>
231
+ }