@cuboapp/api-backend 1.0.25 → 1.0.27
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/package.json +8 -10
- package/src/index.ts +42 -257
- package/src/old.ts +744 -0
- package/src/types/db.ts +5 -2
- package/src/types/index.ts +11 -2
- package/src/crdt/index.ts +0 -413
- package/src/crdt/types.ts +0 -34
package/src/types/db.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CuboCrdtServerDocumentOrigin } from '@cuboapp/crdt'
|
|
1
2
|
import { type Transaction } from '@cuboapp/database'
|
|
2
3
|
|
|
3
4
|
export type CuboCrudQueryOptions = {
|
|
@@ -11,7 +12,7 @@ export type CuboCrudQueryOptions = {
|
|
|
11
12
|
groupBy?: string
|
|
12
13
|
withDeleted?: boolean
|
|
13
14
|
withCrdt?: boolean
|
|
14
|
-
|
|
15
|
+
|
|
15
16
|
extra?: any
|
|
16
17
|
}
|
|
17
18
|
|
|
@@ -19,6 +20,7 @@ export type CuboCrudMethodOptions<E extends object = {}> = {
|
|
|
19
20
|
transaction?: Transaction
|
|
20
21
|
performer_id?: number
|
|
21
22
|
extra?: any
|
|
23
|
+
debounce?: number
|
|
22
24
|
excludeHooks?: (
|
|
23
25
|
| 'beforeGetMany'
|
|
24
26
|
| 'beforeGetOne'
|
|
@@ -30,11 +32,12 @@ export type CuboCrudMethodOptions<E extends object = {}> = {
|
|
|
30
32
|
| 'beforeUpdate'
|
|
31
33
|
| 'afterCrdtCreate'
|
|
32
34
|
| 'afterCrdtUpdate'
|
|
35
|
+
| 'baseHooks'
|
|
33
36
|
)[]
|
|
34
37
|
|
|
35
38
|
log?: boolean
|
|
36
39
|
replace?: boolean
|
|
37
|
-
crdt?:
|
|
40
|
+
crdt?: CuboCrdtServerDocumentOrigin
|
|
38
41
|
|
|
39
42
|
queryOptions?: CuboCrudQueryOptions
|
|
40
43
|
} & E
|
package/src/types/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { CuboCrdtOptions } from '@cuboapp/crdt'
|
|
2
1
|
import { Database, DatabaseOptions, Options } from '@cuboapp/database'
|
|
3
2
|
import { CuboApiEntitiesMap, CuboAuthTokenType, CuboEntity } from '@cuboapp/types'
|
|
4
3
|
|
|
5
4
|
import { CuboCrudAugmentationsStore } from './augmentation'
|
|
5
|
+
import { CuboCrudMethodOptions } from './db'
|
|
6
6
|
|
|
7
7
|
export * from './augmentation'
|
|
8
8
|
export * from './basic'
|
|
@@ -21,7 +21,16 @@ export type CuboBackendApiOptions<T extends CuboApiEntitiesMap<T>, A> = {
|
|
|
21
21
|
options?: Options & DatabaseOptions
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
hooks?: {
|
|
25
|
+
onAfterCreate?: <A extends Extract<keyof T, string>>(entity: CuboEntity, row: T[A], opts: CuboCrudMethodOptions) => void | Promise<void>
|
|
26
|
+
onAfterUpdate?: <A extends Extract<keyof T, string>>(
|
|
27
|
+
entity: CuboEntity,
|
|
28
|
+
row: T[A],
|
|
29
|
+
oldRow: T[A],
|
|
30
|
+
opts: CuboCrudMethodOptions
|
|
31
|
+
) => void | Promise<void>
|
|
32
|
+
onAfterDelete?: <A extends Extract<keyof T, string>>(entity: CuboEntity, row: T[A], opts: CuboCrudMethodOptions) => void | Promise<void>
|
|
33
|
+
}
|
|
25
34
|
|
|
26
35
|
augmentations?: Partial<CuboCrudAugmentationsStore<T>>
|
|
27
36
|
}
|
package/src/crdt/index.ts
DELETED
|
@@ -1,413 +0,0 @@
|
|
|
1
|
-
import { QueryTypes } from '@cuboapp/database'
|
|
2
|
-
import { CuboApiEntitiesMap, CuboEntity } from '@cuboapp/types'
|
|
3
|
-
import { Database } from '@hocuspocus/extension-database'
|
|
4
|
-
import { Server } from '@hocuspocus/server'
|
|
5
|
-
import { IncomingHttpHeaders } from 'http'
|
|
6
|
-
import * as Y from 'yjs'
|
|
7
|
-
|
|
8
|
-
import { CuboBackendApi } from '..'
|
|
9
|
-
import { CuboDirectConnection } from './types'
|
|
10
|
-
|
|
11
|
-
export * from './types'
|
|
12
|
-
|
|
13
|
-
export * from '@hocuspocus/server'
|
|
14
|
-
|
|
15
|
-
export class CuboCrdt<T extends CuboApiEntitiesMap<T>> {
|
|
16
|
-
public server: Server
|
|
17
|
-
private documentPrefix = 'cubo'
|
|
18
|
-
private defaultCrdtFieldAlias = 'crdt_data'
|
|
19
|
-
|
|
20
|
-
constructor(public api: CuboBackendApi<T>) {
|
|
21
|
-
this.init()
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
private init() {
|
|
25
|
-
const { onAuthenticate, onLoadDocument, onChange, onStoreDocument, afterLoadDocument, connected, ...config } = this.api.options.crdt
|
|
26
|
-
|
|
27
|
-
this.server = new Server({
|
|
28
|
-
port: config.port,
|
|
29
|
-
extensions: [
|
|
30
|
-
new Database({
|
|
31
|
-
fetch: async ({ documentName, context, document, instance, requestHeaders, requestParameters, socketId, connectionConfig }) => {
|
|
32
|
-
try {
|
|
33
|
-
const [prefix] = documentName.split('.')
|
|
34
|
-
if (prefix !== this.documentPrefix) {
|
|
35
|
-
return null
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const { entityAlias, id } = this.parseDocumentName(documentName)
|
|
39
|
-
|
|
40
|
-
// console.log('fetch', entityAlias, id)
|
|
41
|
-
if (id <= 0) {
|
|
42
|
-
return null
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const entity = await this.api.helpers.getEntityByAlias(entityAlias as keyof T)
|
|
46
|
-
if (!entity) {
|
|
47
|
-
throw new Error(`Entity not found: "${entityAlias}"`)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const isSupported = this.isCrdtSupported(entity)
|
|
51
|
-
if (!isSupported) {
|
|
52
|
-
throw new Error(`Entity "${entityAlias}" does not support CRDT`)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const fieldKey = this.getCrdtField(entity)?.alias
|
|
56
|
-
|
|
57
|
-
if (!fieldKey) {
|
|
58
|
-
return null
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const db = await this.api.helpers.getConnection('write')
|
|
62
|
-
|
|
63
|
-
const [data] = await db.connection.query(`SELECT ${fieldKey} from ${entityAlias} where id = :id`, {
|
|
64
|
-
type: QueryTypes.SELECT,
|
|
65
|
-
replacements: {
|
|
66
|
-
id
|
|
67
|
-
}
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
if (!data) {
|
|
71
|
-
throw new Error(`Entity "${entityAlias}" with id=${id} not found`)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const raw = (data as any)[fieldKey]
|
|
75
|
-
|
|
76
|
-
if (!raw) {
|
|
77
|
-
return null
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return raw
|
|
81
|
-
} catch (error) {
|
|
82
|
-
console.log('error', error)
|
|
83
|
-
}
|
|
84
|
-
},
|
|
85
|
-
store: async ({ documentName, document, state, context }) => {
|
|
86
|
-
const [prefix] = documentName.split('.')
|
|
87
|
-
if (prefix !== this.documentPrefix) {
|
|
88
|
-
return null
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const { entityAlias, id } = this.parseDocumentName(documentName)
|
|
92
|
-
|
|
93
|
-
if (id <= 0) {
|
|
94
|
-
return
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const entity = await this.api.helpers.getEntityByAlias(entityAlias as keyof T)
|
|
98
|
-
if (!entity) {
|
|
99
|
-
throw new Error(`Entity not found: "${entityAlias}"`)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const isSupported = this.isCrdtSupported(entity)
|
|
103
|
-
if (!isSupported) {
|
|
104
|
-
throw new Error(`Entity "${entityAlias}" does not support CRDT`)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const entityMap = document.getMap(entityAlias)
|
|
108
|
-
const body: Record<string, any> = {}
|
|
109
|
-
|
|
110
|
-
const fieldKey = this.getCrdtField(entity)?.alias
|
|
111
|
-
|
|
112
|
-
for (const [key, value] of entityMap.entries()) {
|
|
113
|
-
if (key === fieldKey) {
|
|
114
|
-
continue
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
body[key] = value
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// console.log('state', state)
|
|
121
|
-
|
|
122
|
-
body[fieldKey] = state
|
|
123
|
-
|
|
124
|
-
body.modified_at = new Date().toISOString()
|
|
125
|
-
|
|
126
|
-
await this.api
|
|
127
|
-
.updateOne(
|
|
128
|
-
entityAlias as Extract<keyof T, string>,
|
|
129
|
-
{
|
|
130
|
-
query: { id },
|
|
131
|
-
body
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
crdt: false,
|
|
135
|
-
extra: {
|
|
136
|
-
auth: context.auth
|
|
137
|
-
},
|
|
138
|
-
excludeHooks: [],
|
|
139
|
-
queryOptions: { withDeleted: true, withCrdt: true }
|
|
140
|
-
}
|
|
141
|
-
)
|
|
142
|
-
.catch((e) => {
|
|
143
|
-
console.log('crdt on store error', { body })
|
|
144
|
-
})
|
|
145
|
-
}
|
|
146
|
-
})
|
|
147
|
-
],
|
|
148
|
-
onAuthenticate: async (data) => {
|
|
149
|
-
try {
|
|
150
|
-
return await onAuthenticate?.(this.api, data)
|
|
151
|
-
} catch (err) {
|
|
152
|
-
throw new Error('Ошибка авторизации: ' + err)
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
onLoadDocument: async (data) => {
|
|
156
|
-
const { documentName } = data
|
|
157
|
-
|
|
158
|
-
const [prefix] = documentName.split('.')
|
|
159
|
-
if (prefix === this.documentPrefix) {
|
|
160
|
-
const { entityAlias, id } = this.parseDocumentName(documentName)
|
|
161
|
-
|
|
162
|
-
if (entityAlias) {
|
|
163
|
-
const augmentation = this.api.options.augmentations?.[entityAlias]
|
|
164
|
-
|
|
165
|
-
if (augmentation?.onLoadDocument) {
|
|
166
|
-
await augmentation.onLoadDocument(data)
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return onLoadDocument?.(this.api, data)
|
|
172
|
-
},
|
|
173
|
-
afterLoadDocument: async (data) => {
|
|
174
|
-
const { documentName, document, instance } = data
|
|
175
|
-
|
|
176
|
-
return afterLoadDocument?.(this.api, data)
|
|
177
|
-
},
|
|
178
|
-
connected: async (data) => {
|
|
179
|
-
const { documentName, instance } = data
|
|
180
|
-
|
|
181
|
-
const [prefix] = documentName?.split('.')
|
|
182
|
-
if (prefix === this.documentPrefix) {
|
|
183
|
-
const document = instance.documents.get(documentName)
|
|
184
|
-
|
|
185
|
-
const { entityAlias, id } = this.parseDocumentName(documentName)
|
|
186
|
-
|
|
187
|
-
if (entityAlias && document) {
|
|
188
|
-
const entityMap = document.getMap(entityAlias)
|
|
189
|
-
const id = entityMap.get('id')
|
|
190
|
-
|
|
191
|
-
if (id === undefined) {
|
|
192
|
-
document.connections.forEach(({ connection }) => {
|
|
193
|
-
connection.close({
|
|
194
|
-
reason: 'Document not loaded',
|
|
195
|
-
code: 500
|
|
196
|
-
})
|
|
197
|
-
})
|
|
198
|
-
instance.unloadDocument(document)
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return connected?.(this.api, data)
|
|
204
|
-
},
|
|
205
|
-
onChange: async (data) => {
|
|
206
|
-
const { documentName } = data
|
|
207
|
-
|
|
208
|
-
const [prefix] = documentName.split('.')
|
|
209
|
-
if (prefix === this.documentPrefix) {
|
|
210
|
-
const { entityAlias, id } = this.parseDocumentName(documentName)
|
|
211
|
-
|
|
212
|
-
if (entityAlias) {
|
|
213
|
-
const augmentation = this.api.options.augmentations?.[entityAlias]
|
|
214
|
-
|
|
215
|
-
if (augmentation?.onChangeDocument) {
|
|
216
|
-
await augmentation.onChangeDocument(data)
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return onChange?.(this.api, data)
|
|
222
|
-
},
|
|
223
|
-
onStoreDocument: async (data) => {
|
|
224
|
-
const { documentName } = data
|
|
225
|
-
|
|
226
|
-
const [prefix] = documentName.split('.')
|
|
227
|
-
if (prefix === this.documentPrefix) {
|
|
228
|
-
const { entityAlias, id } = this.parseDocumentName(documentName)
|
|
229
|
-
|
|
230
|
-
if (entityAlias) {
|
|
231
|
-
const augmentation = this.api.options.augmentations?.[entityAlias]
|
|
232
|
-
|
|
233
|
-
if (augmentation?.onStoreDocument) {
|
|
234
|
-
await augmentation.onStoreDocument(data)
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
return onStoreDocument?.(this.api, data)
|
|
240
|
-
},
|
|
241
|
-
|
|
242
|
-
...config
|
|
243
|
-
})
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
public async listen() {
|
|
247
|
-
await this.server.listen()
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
private parseDocumentName(documentName: string) {
|
|
251
|
-
const parts = documentName.split('.')
|
|
252
|
-
|
|
253
|
-
const [prefix, entityAlias, idRaw] = parts
|
|
254
|
-
|
|
255
|
-
if (prefix !== this.documentPrefix) {
|
|
256
|
-
throw new Error(`Invalid prefix: "${prefix}", expected "${this.documentPrefix}"`)
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
if (!entityAlias) {
|
|
260
|
-
throw new Error(`Missing entity alias in documentName: "${documentName}"`)
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
const id = Number(idRaw)
|
|
264
|
-
if (Number.isNaN(id)) {
|
|
265
|
-
throw new Error(`Invalid id in documentName: "${documentName}"`)
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
return { entityAlias: entityAlias as Extract<keyof T, string>, id }
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
public createDocumentName(entityAlias: string, id: number | string, prefix?: string) {
|
|
272
|
-
const parts = [prefix || this.documentPrefix, entityAlias, id]
|
|
273
|
-
|
|
274
|
-
return parts.join('.')
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
public isCrdtSupported(entity: CuboEntity) {
|
|
278
|
-
const hasCrdtField = entity.fields.some((f) => f.alias === (this.api.options.crdt?.fieldAlias || this.defaultCrdtFieldAlias))
|
|
279
|
-
|
|
280
|
-
return hasCrdtField
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
public getCrdtField(entity: CuboEntity) {
|
|
284
|
-
const crdtField = entity.fields.find((f) => f.alias === (this.api.options.crdt?.fieldAlias || this.defaultCrdtFieldAlias))
|
|
285
|
-
|
|
286
|
-
return crdtField
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
public getDocumentByEntity(entityAlias: string, id: number, requestHeaders: IncomingHttpHeaders) {
|
|
290
|
-
const documentName = this.createDocumentName(entityAlias, id)
|
|
291
|
-
const fakeSocketId = 'api-' + crypto.randomUUID()
|
|
292
|
-
|
|
293
|
-
return this.server.hocuspocus.createDocument(documentName, { headers: requestHeaders, url: '/collaboration' }, fakeSocketId, {
|
|
294
|
-
readOnly: false,
|
|
295
|
-
isAuthenticated: false
|
|
296
|
-
})
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
public async openDirectConnection(entityAlias: string, id: number, context?: any) {
|
|
300
|
-
const documentName = this.createDocumentName(entityAlias, id)
|
|
301
|
-
if (!documentName) {
|
|
302
|
-
return
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
return this.server.hocuspocus.openDirectConnection(documentName, context)
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
public async connectionDisconnect(connection: CuboDirectConnection) {
|
|
309
|
-
const { document, instance, context } = connection
|
|
310
|
-
|
|
311
|
-
if (document) {
|
|
312
|
-
document.removeDirectConnection()
|
|
313
|
-
|
|
314
|
-
await instance.storeDocumentHooks(document, {
|
|
315
|
-
clientsCount: document.getConnectionsCount(),
|
|
316
|
-
context: context,
|
|
317
|
-
document: document,
|
|
318
|
-
documentName: document.name,
|
|
319
|
-
instance: instance,
|
|
320
|
-
requestHeaders: {},
|
|
321
|
-
requestParameters: new URLSearchParams(),
|
|
322
|
-
socketId: 'server'
|
|
323
|
-
})
|
|
324
|
-
|
|
325
|
-
// // If the direct connection was the only connection to the document
|
|
326
|
-
// // then we should trigger the onDisconnect hook for
|
|
327
|
-
// // this doc and unload the document
|
|
328
|
-
// if (document.getConnectionsCount() === 0) {
|
|
329
|
-
// await instance.hooks('onDisconnect', {
|
|
330
|
-
// instance: instance,
|
|
331
|
-
// clientsCount: document.getConnectionsCount(),
|
|
332
|
-
// context: context,
|
|
333
|
-
// document: document,
|
|
334
|
-
// socketId: 'server',
|
|
335
|
-
// documentName: document.name,
|
|
336
|
-
// requestHeaders: {},
|
|
337
|
-
// requestParameters: new URLSearchParams()
|
|
338
|
-
// })
|
|
339
|
-
|
|
340
|
-
// await instance.unloadDocument(document)
|
|
341
|
-
// }
|
|
342
|
-
|
|
343
|
-
connection.document = null
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
public async updateDocument(params: { entityAlias: string; id: number; entity: CuboEntity }, dto: Record<string, any>, context?: any) {
|
|
348
|
-
const { entityAlias, id, entity } = params
|
|
349
|
-
|
|
350
|
-
const connection = await this.openDirectConnection(entityAlias, id, context)
|
|
351
|
-
if (!connection) {
|
|
352
|
-
return
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
const { document } = connection
|
|
356
|
-
if (!document) {
|
|
357
|
-
return
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
const entityMap = document.getMap(entityAlias)
|
|
361
|
-
|
|
362
|
-
const fieldKey = this.getCrdtField(entity)?.alias
|
|
363
|
-
|
|
364
|
-
document.transact(() => {
|
|
365
|
-
for (const [key, value] of Object.entries(dto)) {
|
|
366
|
-
if (key === fieldKey) {
|
|
367
|
-
continue
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
let preparedValue = value
|
|
371
|
-
|
|
372
|
-
if (value instanceof Date) {
|
|
373
|
-
preparedValue = value.toISOString()
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
entityMap.set(key, preparedValue)
|
|
377
|
-
}
|
|
378
|
-
})
|
|
379
|
-
|
|
380
|
-
return this.connectionDisconnect(connection)
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
public async createState(params: { entityAlias: string; id: number; entity: CuboEntity }, dto: Record<string, any>) {
|
|
384
|
-
const { entityAlias, id, entity } = params
|
|
385
|
-
|
|
386
|
-
const document = new Y.Doc()
|
|
387
|
-
if (!document) {
|
|
388
|
-
return
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
const entityMap = document.getMap(entityAlias)
|
|
392
|
-
|
|
393
|
-
const fieldKey = this.getCrdtField(entity)?.alias
|
|
394
|
-
|
|
395
|
-
document.transact(() => {
|
|
396
|
-
for (const [key, value] of Object.entries(dto)) {
|
|
397
|
-
if (key === fieldKey) {
|
|
398
|
-
continue
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
let preparedValue = value
|
|
402
|
-
|
|
403
|
-
if (value instanceof Date) {
|
|
404
|
-
preparedValue = value.toISOString()
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
entityMap.set(key, preparedValue)
|
|
408
|
-
}
|
|
409
|
-
})
|
|
410
|
-
|
|
411
|
-
return Buffer.from(Y.encodeStateAsUpdate(document))
|
|
412
|
-
}
|
|
413
|
-
}
|
package/src/crdt/types.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { CuboApiEntitiesMap } from '@cuboapp/types'
|
|
2
|
-
import {
|
|
3
|
-
DirectConnection as DirectConnectionInterface,
|
|
4
|
-
Document,
|
|
5
|
-
Hocuspocus,
|
|
6
|
-
ServerConfiguration,
|
|
7
|
-
afterLoadDocumentPayload,
|
|
8
|
-
connectedPayload,
|
|
9
|
-
onAuthenticatePayload,
|
|
10
|
-
onChangePayload,
|
|
11
|
-
onLoadDocumentPayload,
|
|
12
|
-
onStoreDocumentPayload
|
|
13
|
-
} from '@hocuspocus/server'
|
|
14
|
-
|
|
15
|
-
import { CuboBackendApi } from '..'
|
|
16
|
-
|
|
17
|
-
export type CuboCrdtConfiguration<T extends CuboApiEntitiesMap<T>> = Omit<
|
|
18
|
-
Partial<ServerConfiguration>,
|
|
19
|
-
'onAuthenticate' | 'onLoadDocument' | 'onChange' | 'onStoreDocument' | 'afterLoadDocument' | 'connected'
|
|
20
|
-
> & {
|
|
21
|
-
onAuthenticate?: (api: CuboBackendApi<T>, data: onAuthenticatePayload) => Promise<any>
|
|
22
|
-
onLoadDocument?: (api: CuboBackendApi<T>, data: onLoadDocumentPayload) => Promise<any>
|
|
23
|
-
onChange?: (api: CuboBackendApi<T>, data: onChangePayload) => Promise<any>
|
|
24
|
-
onStoreDocument?: (api: CuboBackendApi<T>, data: onStoreDocumentPayload) => Promise<any>
|
|
25
|
-
afterLoadDocument?: (api: CuboBackendApi<T>, data: afterLoadDocumentPayload) => Promise<any>
|
|
26
|
-
connected?: (api: CuboBackendApi<T>, data: connectedPayload) => Promise<any>
|
|
27
|
-
fieldAlias?: string
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export type CuboDirectConnection = {
|
|
31
|
-
document: Document | null
|
|
32
|
-
instance: Hocuspocus
|
|
33
|
-
context: any
|
|
34
|
-
} & DirectConnectionInterface
|