@hocuspocus/provider 2.9.1-rc.0 → 2.9.2-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.
- package/dist/hocuspocus-provider.cjs +149 -0
- package/dist/hocuspocus-provider.cjs.map +1 -1
- package/dist/hocuspocus-provider.esm.js +149 -0
- package/dist/hocuspocus-provider.esm.js.map +1 -1
- package/dist/packages/provider/src/TiptapCollabProvider.d.ts +16 -1
- package/dist/packages/provider/src/types.d.ts +14 -0
- package/dist/playground/frontend/vite.config.d.ts +1 -1
- package/package.json +3 -2
- package/src/TiptapCollabProvider.ts +169 -1
- package/src/types.ts +16 -0
|
@@ -1,7 +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.js';
|
|
4
|
+
import type { TCollabComment, TCollabThread, THistoryVersion } from './types.js';
|
|
5
5
|
export type TiptapCollabProviderConfiguration = Required<Pick<HocuspocusProviderConfiguration, 'name'>> & Partial<HocuspocusProviderConfiguration> & (Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'websocketProvider'>> | Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'appId'>> | Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'baseUrl'>>);
|
|
6
6
|
export interface AdditionalTiptapCollabProviderConfiguration {
|
|
7
7
|
/**
|
|
@@ -40,4 +40,19 @@ export declare class TiptapCollabProvider extends HocuspocusProvider {
|
|
|
40
40
|
isAutoVersioning(): boolean;
|
|
41
41
|
enableAutoVersioning(): 1;
|
|
42
42
|
disableAutoVersioning(): 0;
|
|
43
|
+
private getYThreads;
|
|
44
|
+
getThreads<Data, CommentData>(): TCollabThread<Data, CommentData>[];
|
|
45
|
+
private getThreadIndex;
|
|
46
|
+
getThread<Data, CommentData>(id: string): TCollabThread<Data, CommentData> | null;
|
|
47
|
+
private getYThread;
|
|
48
|
+
createThread(data: TCollabThread): TCollabThread | null;
|
|
49
|
+
updateThread(id: TCollabThread['id'], data: Pick<TCollabThread, 'data'>): TCollabThread | null;
|
|
50
|
+
deleteThread(id: TCollabThread['id']): void;
|
|
51
|
+
getThreadComments(threadId: TCollabThread['id']): TCollabComment[] | null;
|
|
52
|
+
getThreadComment(threadId: TCollabThread['id'], commentId: TCollabComment['id']): TCollabComment | null;
|
|
53
|
+
addComment(threadId: TCollabThread['id'], data: TCollabComment): TCollabThread | null;
|
|
54
|
+
updateComment(threadId: TCollabThread['id'], commentId: TCollabComment['id'], data: TCollabComment): TCollabThread | null;
|
|
55
|
+
deleteComment(threadId: TCollabThread['id'], commentId: TCollabComment['id']): TCollabThread | null;
|
|
56
|
+
watchThreads(callback: () => void): void;
|
|
57
|
+
unwatchThreads(callback: () => void): void;
|
|
43
58
|
}
|
|
@@ -84,6 +84,20 @@ export type StatesArray = {
|
|
|
84
84
|
clientId: number;
|
|
85
85
|
[key: string | number]: any;
|
|
86
86
|
}[];
|
|
87
|
+
export type TCollabThread<Data = any, CommentData = any> = {
|
|
88
|
+
id: string;
|
|
89
|
+
createdAt: number;
|
|
90
|
+
updatedAt: number;
|
|
91
|
+
comments: TCollabComment<CommentData>[];
|
|
92
|
+
data: Data;
|
|
93
|
+
};
|
|
94
|
+
export type TCollabComment<Data = any> = {
|
|
95
|
+
id: string;
|
|
96
|
+
createdAt: number;
|
|
97
|
+
updatedAt: number;
|
|
98
|
+
data: Data;
|
|
99
|
+
content: any;
|
|
100
|
+
};
|
|
87
101
|
export type THistoryVersion = {
|
|
88
102
|
name?: string;
|
|
89
103
|
version: number;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("vite").
|
|
1
|
+
declare const _default: import("vite").UserConfig;
|
|
2
2
|
export default _default;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hocuspocus/provider",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.2-rc.0",
|
|
4
4
|
"description": "hocuspocus provider",
|
|
5
5
|
"homepage": "https://hocuspocus.dev",
|
|
6
6
|
"keywords": [
|
|
@@ -29,9 +29,10 @@
|
|
|
29
29
|
"dist"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@hocuspocus/common": "^2.9.
|
|
32
|
+
"@hocuspocus/common": "^2.9.2-rc.0",
|
|
33
33
|
"@lifeomic/attempt": "^3.0.2",
|
|
34
34
|
"lib0": "^0.2.87",
|
|
35
|
+
"uuid": "^9.0.0",
|
|
35
36
|
"ws": "^8.14.2"
|
|
36
37
|
},
|
|
37
38
|
"peerDependencies": {
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { AbstractType, YArrayEvent } from 'yjs'
|
|
2
|
+
import * as Y from 'yjs'
|
|
3
|
+
import { uuidv4 } from 'lib0/random'
|
|
2
4
|
import {
|
|
3
5
|
HocuspocusProvider,
|
|
4
6
|
HocuspocusProviderConfiguration,
|
|
5
7
|
} from './HocuspocusProvider.js'
|
|
6
8
|
|
|
7
9
|
import { TiptapCollabProviderWebsocket } from './TiptapCollabProviderWebsocket.js'
|
|
8
|
-
import type {
|
|
10
|
+
import type {
|
|
11
|
+
TCollabComment, TCollabThread, THistoryVersion,
|
|
12
|
+
} from './types.js'
|
|
9
13
|
|
|
10
14
|
export type TiptapCollabProviderConfiguration =
|
|
11
15
|
Required<Pick<HocuspocusProviderConfiguration, 'name'>> &
|
|
@@ -93,4 +97,168 @@ export class TiptapCollabProvider extends HocuspocusProvider {
|
|
|
93
97
|
return this.configuration.document.getMap<number>(`${this.tiptapCollabConfigurationPrefix}config`).set('autoVersioning', 0)
|
|
94
98
|
}
|
|
95
99
|
|
|
100
|
+
private getYThreads() {
|
|
101
|
+
return this.configuration.document.getArray<Y.Map<any>>(`${this.tiptapCollabConfigurationPrefix}threads`)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
getThreads<Data, CommentData>(): TCollabThread<Data, CommentData>[] {
|
|
105
|
+
return this.getYThreads().toJSON() as TCollabThread<Data, CommentData>[]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private getThreadIndex(id: string): number | null {
|
|
109
|
+
let index = null
|
|
110
|
+
|
|
111
|
+
let i = 0
|
|
112
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
113
|
+
for (const thread of this.getThreads()) {
|
|
114
|
+
if (thread.id === id) {
|
|
115
|
+
index = i
|
|
116
|
+
break
|
|
117
|
+
}
|
|
118
|
+
i += 1
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return index
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
getThread<Data, CommentData>(id: string): TCollabThread<Data, CommentData> | null {
|
|
125
|
+
const index = this.getThreadIndex(id)
|
|
126
|
+
|
|
127
|
+
if (index === null) {
|
|
128
|
+
return null
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return this.getYThreads().get(index).toJSON() as TCollabThread<Data, CommentData>
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private getYThread(id: string) {
|
|
135
|
+
const index = this.getThreadIndex(id)
|
|
136
|
+
|
|
137
|
+
if (index === null) {
|
|
138
|
+
return null
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return this.getYThreads().get(index)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
createThread(data: TCollabThread) {
|
|
145
|
+
const thread = new Y.Map()
|
|
146
|
+
thread.set('id', uuidv4())
|
|
147
|
+
thread.set('createdAt', (new Date()).toISOString())
|
|
148
|
+
thread.set('comments', new Y.Array())
|
|
149
|
+
|
|
150
|
+
this.getYThreads().push([thread])
|
|
151
|
+
return this.updateThread(String(thread.get('id')), data)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
updateThread(id: TCollabThread['id'], data: Pick<TCollabThread, 'data'>) {
|
|
155
|
+
const thread = this.getYThread(id)
|
|
156
|
+
|
|
157
|
+
if (thread === null) {
|
|
158
|
+
return null
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
thread.set('updatedAt', (new Date()).toISOString())
|
|
162
|
+
thread.set('data', data.data)
|
|
163
|
+
|
|
164
|
+
return thread.toJSON() as TCollabThread
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
deleteThread(id: TCollabThread['id']) {
|
|
168
|
+
const index = this.getThreadIndex(id)
|
|
169
|
+
|
|
170
|
+
if (index === null) {
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
this.getYThreads().delete(index, 1)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
getThreadComments(threadId: TCollabThread['id']): TCollabComment[] | null {
|
|
178
|
+
const index = this.getThreadIndex(threadId)
|
|
179
|
+
|
|
180
|
+
if (index === null) {
|
|
181
|
+
return null
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return this.getThread(threadId)?.comments ?? []
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
getThreadComment(threadId: TCollabThread['id'], commentId: TCollabComment['id']): TCollabComment | null {
|
|
188
|
+
const index = this.getThreadIndex(threadId)
|
|
189
|
+
|
|
190
|
+
if (index === null) {
|
|
191
|
+
return null
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return this.getThread(threadId)?.comments.find(comment => comment.id === commentId) ?? null
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
addComment(threadId: TCollabThread['id'], data: TCollabComment) {
|
|
198
|
+
const thread = this.getYThread(threadId)
|
|
199
|
+
|
|
200
|
+
if (thread === null) return null
|
|
201
|
+
|
|
202
|
+
const commentMap = new Y.Map()
|
|
203
|
+
commentMap.set('id', uuidv4())
|
|
204
|
+
commentMap.set('createdAt', (new Date()).toISOString())
|
|
205
|
+
thread.get('comments').push([commentMap])
|
|
206
|
+
|
|
207
|
+
this.updateComment(threadId, String(commentMap.get('id')), data)
|
|
208
|
+
|
|
209
|
+
return thread.toJSON() as TCollabThread
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
updateComment(threadId: TCollabThread['id'], commentId: TCollabComment['id'], data: TCollabComment) {
|
|
213
|
+
const thread = this.getYThread(threadId)
|
|
214
|
+
|
|
215
|
+
if (thread === null) return null
|
|
216
|
+
|
|
217
|
+
let comment = null
|
|
218
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
219
|
+
for (const c of thread.get('comments')) {
|
|
220
|
+
if (c.get('id') === commentId) {
|
|
221
|
+
comment = c
|
|
222
|
+
break
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (comment === null) return null
|
|
227
|
+
|
|
228
|
+
comment.set('updatedAt', (new Date()).toISOString())
|
|
229
|
+
comment.set('data', data.data)
|
|
230
|
+
comment.set('content', data.content)
|
|
231
|
+
|
|
232
|
+
return thread.toJSON() as TCollabThread
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
deleteComment(threadId: TCollabThread['id'], commentId: TCollabComment['id']) {
|
|
236
|
+
const thread = this.getYThread(threadId)
|
|
237
|
+
|
|
238
|
+
if (thread === null) return null
|
|
239
|
+
|
|
240
|
+
let commentIndex = 0
|
|
241
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
242
|
+
for (const c of thread.get('comments')) {
|
|
243
|
+
if (c.get('id') === commentId) {
|
|
244
|
+
break
|
|
245
|
+
}
|
|
246
|
+
commentIndex += 1
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (commentIndex >= 0) {
|
|
250
|
+
thread.get('comments').delete(commentIndex)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return thread.toJSON() as TCollabThread
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
watchThreads(callback: () => void) {
|
|
257
|
+
this.getYThreads().observeDeep(callback)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
unwatchThreads(callback: () => void) {
|
|
261
|
+
this.getYThreads().unobserveDeep(callback)
|
|
262
|
+
}
|
|
263
|
+
|
|
96
264
|
}
|
package/src/types.ts
CHANGED
|
@@ -106,6 +106,22 @@ export type StatesArray = { clientId: number, [key: string | number]: any }[]
|
|
|
106
106
|
|
|
107
107
|
// hocuspocus-pro types
|
|
108
108
|
|
|
109
|
+
export type TCollabThread<Data = any, CommentData = any> = {
|
|
110
|
+
id: string;
|
|
111
|
+
createdAt: number;
|
|
112
|
+
updatedAt: number;
|
|
113
|
+
comments: TCollabComment<CommentData>[];
|
|
114
|
+
data: Data
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export type TCollabComment<Data = any> = {
|
|
118
|
+
id: string;
|
|
119
|
+
createdAt: number;
|
|
120
|
+
updatedAt: number;
|
|
121
|
+
data: Data
|
|
122
|
+
content: any
|
|
123
|
+
}
|
|
124
|
+
|
|
109
125
|
export type THistoryVersion = {
|
|
110
126
|
name?: string;
|
|
111
127
|
version: number;
|