@hocuspocus/provider 2.9.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 +152 -2
- package/dist/hocuspocus-provider.cjs.map +1 -1
- package/dist/hocuspocus-provider.esm.js +152 -2
- package/dist/hocuspocus-provider.esm.js.map +1 -1
- package/dist/packages/provider/src/TiptapCollabProvider.d.ts +21 -2
- package/dist/packages/provider/src/TiptapCollabProviderWebsocket.d.ts +5 -1
- package/dist/packages/provider/src/types.d.ts +14 -0
- package/dist/packages/server/src/Hocuspocus.d.ts +1 -1
- package/dist/packages/server/src/Server.d.ts +1 -1
- package/dist/playground/frontend/vite.config.d.ts +1 -1
- package/package.json +3 -2
- package/src/TiptapCollabProvider.ts +177 -3
- package/src/TiptapCollabProviderWebsocket.ts +7 -2
- package/src/types.ts +16 -0
|
@@ -1,13 +1,17 @@
|
|
|
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';
|
|
5
|
-
export type TiptapCollabProviderConfiguration = Required<Pick<HocuspocusProviderConfiguration, 'name'>> & Partial<HocuspocusProviderConfiguration> & (Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'websocketProvider'>> | Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'appId'>>);
|
|
4
|
+
import type { TCollabComment, TCollabThread, THistoryVersion } from './types.js';
|
|
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
|
/**
|
|
8
8
|
* A Hocuspocus Cloud App ID, get one here: https://cloud.tiptap.dev
|
|
9
9
|
*/
|
|
10
10
|
appId?: string;
|
|
11
|
+
/**
|
|
12
|
+
* If you are using the on-premise version of TiptapCollab, put your baseUrl here (e.g. https://collab.yourdomain.com)
|
|
13
|
+
*/
|
|
14
|
+
baseUrl?: string;
|
|
11
15
|
websocketProvider?: TiptapCollabProviderWebsocket;
|
|
12
16
|
}
|
|
13
17
|
export declare class TiptapCollabProvider extends HocuspocusProvider {
|
|
@@ -36,4 +40,19 @@ export declare class TiptapCollabProvider extends HocuspocusProvider {
|
|
|
36
40
|
isAutoVersioning(): boolean;
|
|
37
41
|
enableAutoVersioning(): 1;
|
|
38
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;
|
|
39
58
|
}
|
|
@@ -4,7 +4,11 @@ export interface AdditionalTiptapCollabProviderWebsocketConfiguration {
|
|
|
4
4
|
/**
|
|
5
5
|
* A Hocuspocus Cloud App ID, get one here: https://cloud.tiptap.dev
|
|
6
6
|
*/
|
|
7
|
-
appId
|
|
7
|
+
appId?: string;
|
|
8
|
+
/**
|
|
9
|
+
* If you are using the on-premise version of TiptapCollab, put your baseUrl here (e.g. https://collab.yourdomain.com)
|
|
10
|
+
*/
|
|
11
|
+
baseUrl?: string;
|
|
8
12
|
}
|
|
9
13
|
export declare class TiptapCollabProviderWebsocket extends HocuspocusProviderWebsocket {
|
|
10
14
|
constructor(configuration: TiptapCollabProviderWebsocketConfiguration);
|
|
@@ -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,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { IncomingMessage } from 'http';
|
|
3
3
|
import WebSocket, { AddressInfo } from 'ws';
|
|
4
|
-
import { Server as HocuspocusServer } from './Server';
|
|
4
|
+
import { Server as HocuspocusServer } from './Server.js';
|
|
5
5
|
import { Debugger } from './Debugger.js';
|
|
6
6
|
import { DirectConnection } from './DirectConnection.js';
|
|
7
7
|
import Document from './Document.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { IncomingMessage, Server as HTTPServer, ServerResponse } from 'http';
|
|
3
3
|
import { WebSocketServer } from 'ws';
|
|
4
|
-
import { Hocuspocus } from './Hocuspocus';
|
|
4
|
+
import { Hocuspocus } from './Hocuspocus.js';
|
|
5
5
|
export declare class Server {
|
|
6
6
|
httpServer: HTTPServer;
|
|
7
7
|
webSocketServer: WebSocketServer;
|
|
@@ -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.0",
|
|
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.0",
|
|
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,17 +1,22 @@
|
|
|
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'>> &
|
|
12
16
|
Partial<HocuspocusProviderConfiguration> &
|
|
13
17
|
(Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'websocketProvider'>> |
|
|
14
|
-
Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'appId'
|
|
18
|
+
Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'appId'>>|
|
|
19
|
+
Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'baseUrl'>>)
|
|
15
20
|
|
|
16
21
|
export interface AdditionalTiptapCollabProviderConfiguration {
|
|
17
22
|
/**
|
|
@@ -19,6 +24,11 @@ export interface AdditionalTiptapCollabProviderConfiguration {
|
|
|
19
24
|
*/
|
|
20
25
|
appId?: string,
|
|
21
26
|
|
|
27
|
+
/**
|
|
28
|
+
* If you are using the on-premise version of TiptapCollab, put your baseUrl here (e.g. https://collab.yourdomain.com)
|
|
29
|
+
*/
|
|
30
|
+
baseUrl?: string
|
|
31
|
+
|
|
22
32
|
websocketProvider?: TiptapCollabProviderWebsocket
|
|
23
33
|
}
|
|
24
34
|
|
|
@@ -27,7 +37,7 @@ export class TiptapCollabProvider extends HocuspocusProvider {
|
|
|
27
37
|
|
|
28
38
|
constructor(configuration: TiptapCollabProviderConfiguration) {
|
|
29
39
|
if (!configuration.websocketProvider) {
|
|
30
|
-
configuration.websocketProvider = new TiptapCollabProviderWebsocket({ appId: (configuration as Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'appId'>>).appId })
|
|
40
|
+
configuration.websocketProvider = new TiptapCollabProviderWebsocket({ appId: (configuration as Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'appId'>>).appId, baseUrl: (configuration as Required<Pick<AdditionalTiptapCollabProviderConfiguration, 'baseUrl'>>).baseUrl })
|
|
31
41
|
}
|
|
32
42
|
|
|
33
43
|
if (!configuration.token) {
|
|
@@ -87,4 +97,168 @@ export class TiptapCollabProvider extends HocuspocusProvider {
|
|
|
87
97
|
return this.configuration.document.getMap<number>(`${this.tiptapCollabConfigurationPrefix}config`).set('autoVersioning', 0)
|
|
88
98
|
}
|
|
89
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
|
+
|
|
90
264
|
}
|
|
@@ -11,11 +11,16 @@ export interface AdditionalTiptapCollabProviderWebsocketConfiguration {
|
|
|
11
11
|
/**
|
|
12
12
|
* A Hocuspocus Cloud App ID, get one here: https://cloud.tiptap.dev
|
|
13
13
|
*/
|
|
14
|
-
appId
|
|
14
|
+
appId?: string,
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* If you are using the on-premise version of TiptapCollab, put your baseUrl here (e.g. https://collab.yourdomain.com)
|
|
18
|
+
*/
|
|
19
|
+
baseUrl?: string
|
|
15
20
|
}
|
|
16
21
|
|
|
17
22
|
export class TiptapCollabProviderWebsocket extends HocuspocusProviderWebsocket {
|
|
18
23
|
constructor(configuration: TiptapCollabProviderWebsocketConfiguration) {
|
|
19
|
-
super({ ...configuration as HocuspocusProviderWebsocketConfiguration, url: `wss://${configuration.appId}.collab.tiptap.cloud` })
|
|
24
|
+
super({ ...configuration as HocuspocusProviderWebsocketConfiguration, url: configuration.baseUrl ?? `wss://${configuration.appId}.collab.tiptap.cloud` })
|
|
20
25
|
}
|
|
21
26
|
}
|
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;
|