@cuboapp/crdt 1.0.5 → 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.
@@ -1,11 +1,5 @@
1
- import { WsServer, WsServerRequest } from '@cuboapp/ws'
1
+ export type CuboCrdtKey<K, M> = K extends Extract<keyof M, string> ? M[K] : any
2
2
 
3
- export type CuboCrdtOptions<A> = {
4
- host?: string
5
- port?: number
6
- debug?: boolean
3
+ export type CuboCrdtAction = 'create' | 'update' | 'delete'
7
4
 
8
- authHandler?: (ctx: { server: WsServer<{ auth: A }>; request: WsServerRequest<{ auth: A }> }) => Promise<A> | A
9
-
10
- beforeLoadDocument?: (name: string) => Promise<any> | any
11
- }
5
+ export type CuboCrdtExposeStrategy = 'all' | 'other' | 'subscribe' | 'client'
@@ -1,7 +1,69 @@
1
1
  import { CuboApiEntitiesMap } from '@cuboapp/types'
2
2
 
3
- import { CuboCrdt, CuboCrdtOptions } from '..'
3
+ import { CuboCrdtClient, CuboCrdtClientOptions, CuboCrdtServer, CuboCrdtServerOptions } from '..'
4
4
 
5
- export function createCrdt<T extends CuboApiEntitiesMap<T>, A = {}>(opts: CuboCrdtOptions<A>) {
6
- return new CuboCrdt<T, A>(opts)
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,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
- }