@cuboapp/crdt 1.0.5 → 1.0.7
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 -4
- package/src/client/index.ts +381 -72
- package/src/client/types/document.ts +22 -0
- package/src/client/types/index.ts +53 -0
- package/src/client/types/store.ts +15 -0
- package/src/client/types/utils.ts +35 -0
- package/src/constants/index.ts +6 -0
- package/src/index.ts +1 -129
- package/src/server/document/index.ts +84 -0
- package/src/server/index.ts +582 -0
- package/src/server/types/document.ts +56 -0
- package/src/server/types/index.ts +25 -0
- package/src/server/types/subscribe.ts +15 -0
- package/src/types/index.ts +3 -9
- package/src/utils/index.ts +95 -3
- package/src/yjs/index.ts +0 -118
package/src/utils/index.ts
CHANGED
|
@@ -1,7 +1,99 @@
|
|
|
1
1
|
import { CuboApiEntitiesMap } from '@cuboapp/types'
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
CuboCrdtClient,
|
|
5
|
+
CuboCrdtClientOptions,
|
|
6
|
+
CuboCrdtServer,
|
|
7
|
+
CuboCrdtServerDocumentOrigin,
|
|
8
|
+
CuboCrdtServerOptions,
|
|
9
|
+
CuboCrdtServerSubscribe
|
|
10
|
+
} from '..'
|
|
4
11
|
|
|
5
|
-
export function
|
|
6
|
-
|
|
12
|
+
export function createCrdtServer<M extends CuboApiEntitiesMap<M>, A = {}, E extends Extract<keyof M, string> = Extract<keyof M, string>>(
|
|
13
|
+
opts: CuboCrdtServerOptions<M, A, E>
|
|
14
|
+
) {
|
|
15
|
+
return new CuboCrdtServer<M, A, E>(opts)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function createCrdtClient<M extends CuboApiEntitiesMap<M>>(opts: CuboCrdtClientOptions<M>) {
|
|
19
|
+
return new CuboCrdtClient<M>(opts)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function cleanObject<F>(object: F): any {
|
|
23
|
+
if (Array.isArray(object)) {
|
|
24
|
+
return object.map(cleanObject).filter(Boolean)
|
|
25
|
+
} else if (typeof object === 'object' && object !== null) {
|
|
26
|
+
const newObj: any = {}
|
|
27
|
+
|
|
28
|
+
for (const key in object) {
|
|
29
|
+
const value = cleanObject(object[key])
|
|
30
|
+
|
|
31
|
+
if (value !== undefined && value !== null && value !== '' && !(typeof value === 'object' && Object.keys(value).length === 0)) {
|
|
32
|
+
newObj[key] = value
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return newObj
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return object
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function checkRowIsSutable(
|
|
43
|
+
row: any,
|
|
44
|
+
filters?: object,
|
|
45
|
+
customKeys?: Record<string, (key: string, row: any, filters?: any) => boolean>
|
|
46
|
+
) {
|
|
47
|
+
let sutable = true
|
|
48
|
+
|
|
49
|
+
if (Object.keys(filters || {}).length) {
|
|
50
|
+
Object.entries(filters || {}).forEach(([key, value]) => {
|
|
51
|
+
if (!['limit', 'with'].includes(key)) {
|
|
52
|
+
if (customKeys?.[key]) {
|
|
53
|
+
sutable = customKeys[key](key, row, filters)
|
|
54
|
+
} else {
|
|
55
|
+
const [formula, str] = `${value}`.split(':')
|
|
56
|
+
|
|
57
|
+
// console.log({ formula, str, value: row[key] })
|
|
58
|
+
|
|
59
|
+
if (!str) {
|
|
60
|
+
if (row[key as keyof typeof row] !== value) {
|
|
61
|
+
sutable = false
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
switch (formula) {
|
|
65
|
+
case 'in':
|
|
66
|
+
if (
|
|
67
|
+
!str
|
|
68
|
+
.split(',')
|
|
69
|
+
.map(Number)
|
|
70
|
+
.includes(row[key as keyof typeof row] as any)
|
|
71
|
+
) {
|
|
72
|
+
sutable = false
|
|
73
|
+
}
|
|
74
|
+
break
|
|
75
|
+
default:
|
|
76
|
+
sutable = false
|
|
77
|
+
break
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return sutable
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function checkSubscribeIsSutable(origin: CuboCrdtServerDocumentOrigin, subscribe?: CuboCrdtServerSubscribe) {
|
|
89
|
+
if (!subscribe) {
|
|
90
|
+
return false
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const noStrategyResolved = !origin?.expose || origin?.expose === 'all'
|
|
94
|
+
const strategyOtherResolved = (origin?.expose === 'other' && origin.subscribe_id !== subscribe?.id) || false
|
|
95
|
+
const strategyClientResolved = origin?.expose === 'client' && subscribe?.client_id === origin.client_id
|
|
96
|
+
const strategySubscribeResolved = origin?.expose === 'subscribe' && subscribe?.id === origin.subscribe_id
|
|
97
|
+
|
|
98
|
+
return noStrategyResolved || strategyOtherResolved || strategyClientResolved || strategySubscribeResolved
|
|
7
99
|
}
|
package/src/yjs/index.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { type WsServerSocket } from '@cuboapp/ws'
|
|
2
|
-
import { Doc, encodeStateAsUpdate } from 'yjs'
|
|
3
|
-
|
|
4
|
-
export type CuboCrdtDocumentHooks = {
|
|
5
|
-
onBeforeDestroy?: () => Promise<void> | void
|
|
6
|
-
onAfterDestroy?: () => Promise<void> | void
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export type CuboCrdtDocumentOptions = CuboCrdtDocumentHooks & {
|
|
10
|
-
name: string
|
|
11
|
-
autoRemove?: boolean
|
|
12
|
-
debug?: boolean
|
|
13
|
-
initial?: any
|
|
14
|
-
|
|
15
|
-
initialState?: () => Promise<any>
|
|
16
|
-
onUpdate?: (ctx: { data: Uint8Array<ArrayBufferLike>; document: CuboCrdtDocument }) => void
|
|
17
|
-
|
|
18
|
-
yjsOptions?: {
|
|
19
|
-
guid?: string
|
|
20
|
-
collectionid?: string
|
|
21
|
-
gc?: boolean
|
|
22
|
-
gcFilter?: () => true
|
|
23
|
-
meta?: any
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export class CuboCrdtDocument {
|
|
28
|
-
private ydoc: Doc
|
|
29
|
-
public clients = new Set<WsServerSocket>()
|
|
30
|
-
|
|
31
|
-
constructor(public opts: CuboCrdtDocumentOptions) {
|
|
32
|
-
opts.autoRemove = opts?.autoRemove ?? true
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
get stat() {
|
|
36
|
-
return {
|
|
37
|
-
clients: this.clients.size
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
get stateAsUpdate() {
|
|
42
|
-
return encodeStateAsUpdate(this.ydoc)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async init() {
|
|
46
|
-
if (this.opts.debug) {
|
|
47
|
-
console.log('init doc', this.opts.name)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
this.ydoc = new Doc({
|
|
51
|
-
...(this.opts?.yjsOptions || {}),
|
|
52
|
-
autoLoad: false,
|
|
53
|
-
shouldLoad: false
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
const state = this.opts?.initialState ? (await this.opts?.initialState()) || {} : {}
|
|
57
|
-
|
|
58
|
-
// console.log('initial state', state)
|
|
59
|
-
|
|
60
|
-
return new Promise<void>((resolve) => {
|
|
61
|
-
this.ydoc.once('update', () => {
|
|
62
|
-
this.ydoc.on('update', (data) => {
|
|
63
|
-
// console.log('document updated', this.opts.name, this.getMap().toJSON())
|
|
64
|
-
|
|
65
|
-
this.opts?.onUpdate?.({ data, document: this })
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
resolve()
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
const map = this.getMap()
|
|
72
|
-
|
|
73
|
-
this.ydoc.transact(() => {
|
|
74
|
-
if (state) {
|
|
75
|
-
Object.entries(state).forEach(([key, value]) => {
|
|
76
|
-
map.set(key, value)
|
|
77
|
-
})
|
|
78
|
-
}
|
|
79
|
-
})
|
|
80
|
-
})
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
getMap() {
|
|
84
|
-
return this.ydoc.getMap()
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async hasClient(client: WsServerSocket) {
|
|
88
|
-
return this.clients.has(client)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async addClient(client: WsServerSocket) {
|
|
92
|
-
this.clients.add(client)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async removeClient(client: WsServerSocket) {
|
|
96
|
-
this.clients.delete(client)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async write(dto: object) {
|
|
100
|
-
if (this.opts.debug) {
|
|
101
|
-
console.log('CRDT write document', this.opts.name, dto)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return new Promise<void>(async (resolve) => {
|
|
105
|
-
const map = this.getMap()
|
|
106
|
-
|
|
107
|
-
this.ydoc.transact(() => {
|
|
108
|
-
Object.entries(dto).forEach(([key, value]) => {
|
|
109
|
-
map.set(key, value)
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
// Внимание! Резолв промиса не означает раскатку по всем подключениям,
|
|
113
|
-
// только лишь запись в Yjs-документ
|
|
114
|
-
resolve()
|
|
115
|
-
})
|
|
116
|
-
})
|
|
117
|
-
}
|
|
118
|
-
}
|