@symbo.ls/sdk 3.1.1 → 3.2.3

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.
Files changed (83) hide show
  1. package/README.md +174 -13
  2. package/dist/cjs/config/environment.js +32 -42
  3. package/dist/cjs/index.js +31 -24
  4. package/dist/cjs/services/AIService.js +3 -3
  5. package/dist/cjs/services/AuthService.js +44 -3
  6. package/dist/cjs/services/BasedService.js +530 -24
  7. package/dist/cjs/services/CollabService.js +420 -0
  8. package/dist/cjs/services/CoreService.js +2295 -0
  9. package/dist/cjs/services/SocketService.js +207 -59
  10. package/dist/cjs/services/SymstoryService.js +135 -49
  11. package/dist/cjs/services/index.js +8 -16
  12. package/dist/cjs/state/RootStateManager.js +86 -0
  13. package/dist/cjs/state/rootEventBus.js +65 -0
  14. package/dist/cjs/utils/CollabClient.js +157 -0
  15. package/dist/cjs/utils/TokenManager.js +409 -0
  16. package/dist/cjs/utils/basedQuerys.js +120 -0
  17. package/dist/cjs/utils/jsonDiff.js +103 -0
  18. package/dist/cjs/utils/permission.js +4 -4
  19. package/dist/cjs/utils/services.js +133 -69
  20. package/dist/cjs/utils/symstoryClient.js +33 -2
  21. package/dist/esm/config/environment.js +32 -42
  22. package/dist/esm/index.js +20586 -11525
  23. package/dist/esm/services/AIService.js +3 -3
  24. package/dist/esm/services/AuthService.js +48 -7
  25. package/dist/esm/services/BasedService.js +676 -65
  26. package/dist/esm/services/CollabService.js +18028 -0
  27. package/dist/esm/services/CoreService.js +2827 -0
  28. package/dist/esm/services/SocketService.js +323 -58
  29. package/dist/esm/services/SymstoryService.js +287 -111
  30. package/dist/esm/services/index.js +20456 -11470
  31. package/dist/esm/state/RootStateManager.js +102 -0
  32. package/dist/esm/state/rootEventBus.js +47 -0
  33. package/dist/esm/utils/CollabClient.js +17483 -0
  34. package/dist/esm/utils/TokenManager.js +395 -0
  35. package/dist/esm/utils/basedQuerys.js +120 -0
  36. package/dist/esm/utils/jsonDiff.js +6096 -0
  37. package/dist/esm/utils/permission.js +4 -4
  38. package/dist/esm/utils/services.js +133 -69
  39. package/dist/esm/utils/symstoryClient.js +63 -43
  40. package/dist/esm/utils/validation.js +89 -19
  41. package/dist/node/config/environment.js +32 -42
  42. package/dist/node/index.js +37 -28
  43. package/dist/node/services/AIService.js +3 -3
  44. package/dist/node/services/AuthService.js +44 -3
  45. package/dist/node/services/BasedService.js +531 -25
  46. package/dist/node/services/CollabService.js +401 -0
  47. package/dist/node/services/CoreService.js +2266 -0
  48. package/dist/node/services/SocketService.js +197 -59
  49. package/dist/node/services/SymstoryService.js +135 -49
  50. package/dist/node/services/index.js +8 -16
  51. package/dist/node/state/RootStateManager.js +57 -0
  52. package/dist/node/state/rootEventBus.js +46 -0
  53. package/dist/node/utils/CollabClient.js +128 -0
  54. package/dist/node/utils/TokenManager.js +390 -0
  55. package/dist/node/utils/basedQuerys.js +120 -0
  56. package/dist/node/utils/jsonDiff.js +74 -0
  57. package/dist/node/utils/permission.js +4 -4
  58. package/dist/node/utils/services.js +133 -69
  59. package/dist/node/utils/symstoryClient.js +33 -2
  60. package/package.json +23 -14
  61. package/src/config/environment.js +33 -42
  62. package/src/index.js +45 -28
  63. package/src/services/AIService.js +3 -3
  64. package/src/services/AuthService.js +52 -3
  65. package/src/services/BasedService.js +603 -23
  66. package/src/services/CollabService.js +491 -0
  67. package/src/services/CoreService.js +2548 -0
  68. package/src/services/SocketService.js +227 -59
  69. package/src/services/SymstoryService.js +150 -64
  70. package/src/services/index.js +7 -14
  71. package/src/state/RootStateManager.js +71 -0
  72. package/src/state/rootEventBus.js +48 -0
  73. package/src/utils/CollabClient.js +161 -0
  74. package/src/utils/TokenManager.js +462 -0
  75. package/src/utils/basedQuerys.js +123 -0
  76. package/src/utils/jsonDiff.js +109 -0
  77. package/src/utils/permission.js +4 -4
  78. package/src/utils/services.js +144 -69
  79. package/src/utils/symstoryClient.js +36 -2
  80. package/dist/cjs/services/SocketIOService.js +0 -309
  81. package/dist/esm/services/SocketIOService.js +0 -467
  82. package/dist/node/services/SocketIOService.js +0 -280
  83. package/src/services/SocketIOService.js +0 -356
@@ -1,4 +1,11 @@
1
- import { BaseService } from './BaseService'
1
+ import { connect, send, disconnect } from '@symbo.ls/socket/client.js'
2
+ import { BaseService } from './BaseService.js'
3
+
4
+ import * as utils from '@domql/utils'
5
+ import { router } from '@symbo.ls/router'
6
+ import environment from '../config/environment.js'
7
+
8
+ const { deepStringify, deepDestringify, isString } = utils.default || utils
2
9
 
3
10
  export class SocketService extends BaseService {
4
11
  constructor (config) {
@@ -8,14 +15,31 @@ export class SocketService extends BaseService {
8
15
  this._maxReconnectAttempts = config?.maxReconnectAttempts || 5
9
16
  this._reconnectDelay = config?.reconnectDelay || 1000
10
17
  this._handlers = new Map()
18
+ this._sessionId = Math.random()
19
+
20
+ this._ignoreSync = [
21
+ 'userId',
22
+ 'username',
23
+ 'usersName',
24
+ 'email',
25
+ 'projects',
26
+ 'feedbacks',
27
+ 'userRoles',
28
+ 'loading',
29
+ 'appKey',
30
+ 'projectName',
31
+ 'followingUser',
32
+ 'activeProject',
33
+ 'user',
34
+ 'sessionId',
35
+ 'clients'
36
+ ]
11
37
  }
12
38
 
13
- async init ({ context, options }) {
39
+ init () {
14
40
  try {
15
- this._context = context
16
- this._options = options
17
- const { authToken } = context
18
- const { socketUrl } = context.socket || {}
41
+ const { _context, _options } = this
42
+ const socketUrl = environment.socketUrl || _options.socketUrl
19
43
 
20
44
  if (!socketUrl) {
21
45
  throw new Error('Socket URL is required')
@@ -24,12 +48,11 @@ export class SocketService extends BaseService {
24
48
  this._info = {
25
49
  config: {
26
50
  url: socketUrl,
27
- hasToken: Boolean(authToken),
51
+ hasToken: Boolean(_context.authToken),
28
52
  status: 'initializing'
29
53
  }
30
54
  }
31
55
 
32
- await this.connect()
33
56
  this._setReady()
34
57
  } catch (error) {
35
58
  this._setError(error)
@@ -39,93 +62,233 @@ export class SocketService extends BaseService {
39
62
 
40
63
  connect () {
41
64
  try {
42
- const { socketUrl, authToken } = this._context.socket || {}
43
-
44
- this._socket = new window.WebSocket(socketUrl)
65
+ // Check if already connected or connecting
66
+ if (
67
+ this._socket &&
68
+ ['connected', 'connecting'].includes(this._info?.config?.status)
69
+ ) {
70
+ console.warn(
71
+ 'Socket connection already exists:',
72
+ this._info?.config?.status
73
+ )
74
+ return true
75
+ }
45
76
 
46
- this._socket.onopen = () => {
47
- this._reconnectAttempts = 0
48
- this._updateStatus('connected')
77
+ const { _context } = this
49
78
 
50
- // Authenticate if token available
51
- if (authToken) {
52
- this.send('auth', { token: authToken })
53
- }
79
+ if (!_context.appKey) {
80
+ throw new Error('App key is required')
54
81
  }
55
82
 
56
- this._socket.onclose = () => {
57
- this._updateStatus('disconnected')
58
- this._handleReconnect()
83
+ // Update status to connecting before attempting connection
84
+ this._updateStatus('connecting')
85
+
86
+ const config = {
87
+ source: 'platform',
88
+ userId: _context.user?.id,
89
+ socketUrl: this._info.config.url,
90
+ location: window.location.host,
91
+ // onConnect: () => {
92
+ // console.log('waz')
93
+ // },
94
+ onChange: this._handleMessage.bind(this),
95
+ sessionId: this._sessionId,
96
+ usersName: _context.user?.name,
97
+ route: window.location.pathname,
98
+ onDisconnect: this._handleDisconnect.bind(this)
59
99
  }
60
100
 
61
- this._socket.onerror = error => {
62
- this._updateStatus('error')
63
- this._setError(error)
101
+ // If a previous socket exists but wasn't properly cleaned up, destroy it
102
+ if (this._socket) {
103
+ this.destroy()
64
104
  }
65
105
 
66
- this._socket.onmessage = event => {
67
- this._handleMessage(event.data)
106
+ this._socket = connect(_context.appKey, config)
107
+ this._updateStatus('connected')
108
+
109
+ if (environment.isDevelopment) {
110
+ console.log('Socket connection established:', {
111
+ appKey: _context.appKey,
112
+ userId: _context.user?.id,
113
+ sessionId: this._sessionId,
114
+ url: this._info.config.url
115
+ })
68
116
  }
117
+
118
+ return true
69
119
  } catch (error) {
120
+ this._updateStatus('failed')
121
+ console.error('Socket connection failed:', error)
70
122
  throw new Error(`Socket connection failed: ${error.message}`)
71
123
  }
72
124
  }
73
125
 
74
- // Send message to socket server
75
- send (type, data) {
126
+ send (type, data, opts = {}) {
76
127
  this._requireReady()
77
128
 
78
- if (!this._socket || this._socket.readyState !== window.WebSocket.OPEN) {
129
+ if (!this._socket) {
79
130
  throw new Error('Socket is not connected')
80
131
  }
81
132
 
82
- this._socket.send(JSON.stringify({ type, data }))
83
- }
84
-
85
- // Subscribe to socket events
86
- subscribe (type, handler) {
87
- if (!this._handlers.has(type)) {
88
- this._handlers.set(type, new Set())
133
+ const payload = {
134
+ sessionId: this._sessionId,
135
+ userId: this._context.user?.id,
136
+ usersName: this._context.user?.name,
137
+ ...data
89
138
  }
90
139
 
91
- this._handlers.get(type).add(handler)
140
+ send.call(
141
+ this._socket,
142
+ type,
143
+ opts.useDeepStringify ? deepStringify(payload) : payload
144
+ )
145
+ }
146
+
147
+ _handleMessage (event, data) {
148
+ try {
149
+ const d = isString(data) ? deepDestringify(JSON.parse(data)) : data
150
+ if (this._sessionId === d.sessionId) {
151
+ return
152
+ }
92
153
 
93
- return () => {
94
- const handlers = this._handlers.get(type)
154
+ const handlers = this._handlers.get(event)
95
155
  if (handlers) {
96
- handlers.delete(handler)
97
- if (handlers.size === 0) {
98
- this._handlers.delete(type)
99
- }
156
+ handlers.forEach(handler => handler(d))
100
157
  }
158
+
159
+ // Handle specific events
160
+ switch (event) {
161
+ case 'change':
162
+ this._handleChangeEvent(d)
163
+ break
164
+ case 'clients':
165
+ this._handleClientsEvent(d)
166
+ break
167
+ case 'route':
168
+ this._handleRouteEvent(d)
169
+ break
170
+ default:
171
+ break
172
+ }
173
+ } catch (error) {
174
+ this._setError(new Error(`Failed to handle message: ${error.message}`))
101
175
  }
102
176
  }
103
177
 
104
- subscribeChannel (type, handler) {
105
- return this.subscribe(type, handler)
178
+ _handleChangeEvent (data) {
179
+ const { type, changes, version } = data
180
+ if (version) {
181
+ this._context.state.version = version
182
+ }
183
+ if (changes) {
184
+ window.requestAnimationFrame(async () => {
185
+ await this._context.state.setPathCollection(changes, {
186
+ preventReplace: type === 'canvas',
187
+ preventUpdate: true,
188
+ fromSocket: true,
189
+ userId: data.userId,
190
+ changes
191
+ })
192
+ })
193
+ }
194
+
195
+ // monaco updates
196
+ // if (data.canvas) {
197
+ // const { clients } = data.canvas
198
+ // const [firstClientKey] = Object.keys(clients)
199
+ // const monaco =
200
+ // clients && clients[firstClientKey] && clients[firstClientKey].monaco
201
+ // if (monaco) {
202
+ // const Canvas =
203
+ // this._context.element && this._context.element.getCanvas()
204
+ // if (Canvas) {
205
+ // Canvas.Chosen.EditorPanels.update({}, { forceMonacoUpdate: true })
206
+ // }
207
+ // }
208
+ // return
209
+ // }
106
210
  }
107
211
 
108
- // Private methods
109
- _handleMessage (rawData) {
110
- try {
111
- const { type, data } = JSON.parse(rawData)
112
- const handlers = this._handlers.get(type)
212
+ _handleClientsEvent (data) {
213
+ const { root } = this._context.state
113
214
 
114
- if (handlers) {
115
- handlers.forEach(handler => handler(data))
215
+ root.replace(
216
+ { clients: data },
217
+ {
218
+ fromSocket: true,
219
+ preventUpdate: true
116
220
  }
117
- } catch (error) {
118
- this._setError(new Error(`Failed to handle message: ${error.message}`))
221
+ )
222
+ }
223
+
224
+ _handleRouteEvent (data) {
225
+ const { element } = this._context
226
+ const { state } = this._context
227
+
228
+ if (data.userId && data.type === 'routeChanged') {
229
+ const isModalOpen = this.getWindow('modal')
230
+ const isFollowing = state.followingUser === data.userId
231
+ const isRouteSyncEnabled =
232
+ element.getUserSettings('presentMode') && data.userId === state.userId
233
+
234
+ if ((isFollowing || isRouteSyncEnabled) && !isModalOpen) {
235
+ router(
236
+ data.route,
237
+ element.__ref.root,
238
+ {},
239
+ {
240
+ fromSocket: true,
241
+ updateStateOptions: {
242
+ fromSocket: true,
243
+ preventStateUpdateListener: 1 // !isModalRoute(data.route, element)
244
+ }
245
+ }
246
+ )
247
+ }
248
+ } else if (data.reload) {
249
+ window.location.reload()
250
+ } else if (data.route && data.type === 'routeForced') {
251
+ router(
252
+ data.route,
253
+ element.__ref.root,
254
+ {},
255
+ {
256
+ fromSocket: true,
257
+ updateStateOptions: {
258
+ fromSocket: true
259
+ }
260
+ }
261
+ )
262
+ } else if (data.componentKey) {
263
+ if (!element.getData('components')[data.componentKey]) {
264
+ return
265
+ }
266
+ element.activateSelected(data.componentKey)
119
267
  }
120
268
  }
121
269
 
270
+ _handleDisconnect () {
271
+ this._updateStatus('disconnected')
272
+ this._handleReconnect()
273
+ }
274
+
122
275
  _handleReconnect () {
123
276
  if (this._reconnectAttempts < this._maxReconnectAttempts) {
124
277
  this._reconnectAttempts++
125
278
  this._updateStatus('reconnecting')
126
279
 
127
280
  setTimeout(() => {
128
- this.connect()
281
+ try {
282
+ const connected = this.connect()
283
+ if (connected) {
284
+ this._reconnectAttempts = 0
285
+ } else {
286
+ this._handleReconnect()
287
+ }
288
+ } catch (error) {
289
+ console.error('Reconnection failed:', error)
290
+ this._handleReconnect()
291
+ }
129
292
  }, this._reconnectDelay * this._reconnectAttempts)
130
293
  } else {
131
294
  this._updateStatus('failed')
@@ -143,19 +306,24 @@ export class SocketService extends BaseService {
143
306
  }
144
307
  }
145
308
 
146
- // Cleanup
147
309
  destroy () {
148
310
  if (this._socket) {
149
- this._socket.close()
311
+ disconnect.call(this._socket)
150
312
  this._socket = null
151
313
  }
152
314
  this._handlers.clear()
153
315
  this._setReady(false)
154
316
  }
155
317
 
318
+ reconnect () {
319
+ this.destroy()
320
+ this.connect()
321
+ }
322
+
156
323
  _checkRequiredContext () {
157
- const { socket } = this._context
158
- return Boolean(socket?.socketUrl && this._socket)
324
+ return Boolean(
325
+ this._context?.appKey && this._context?.authToken && this._socket
326
+ )
159
327
  }
160
328
 
161
329
  isReady () {