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