@tldraw/sync-core 4.2.0-canary.ff738678e7e0 → 4.2.0-internal.d43dfb4f2e76
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/dist-cjs/index.d.ts +275 -5
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/index.js.map +1 -1
- package/dist-cjs/lib/ClientWebSocketAdapter.js.map +2 -2
- package/dist-cjs/lib/TLSyncClient.js +14 -2
- package/dist-cjs/lib/TLSyncClient.js.map +2 -2
- package/dist-esm/index.d.mts +275 -5
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/index.mjs.map +1 -1
- package/dist-esm/lib/ClientWebSocketAdapter.mjs.map +2 -2
- package/dist-esm/lib/TLSyncClient.mjs +14 -2
- package/dist-esm/lib/TLSyncClient.mjs.map +2 -2
- package/package.json +6 -6
- package/src/index.ts +1 -1
- package/src/lib/ClientWebSocketAdapter.ts +4 -1
- package/src/lib/TLSyncClient.test.ts +17 -6
- package/src/lib/TLSyncClient.ts +44 -19
- package/src/test/TestSocketPair.ts +5 -2
package/src/lib/TLSyncClient.ts
CHANGED
|
@@ -31,10 +31,16 @@ import {
|
|
|
31
31
|
* @param cb - Callback function that receives the event value
|
|
32
32
|
* @returns Function to call when you want to unsubscribe from the events
|
|
33
33
|
*
|
|
34
|
-
* @
|
|
34
|
+
* @public
|
|
35
35
|
*/
|
|
36
36
|
export type SubscribingFn<T> = (cb: (val: T) => void) => () => void
|
|
37
37
|
|
|
38
|
+
/** Network sync frame rate when in solo mode (no collaborators) @internal */
|
|
39
|
+
const SOLO_MODE_FPS = 1
|
|
40
|
+
|
|
41
|
+
/** Network sync frame rate when in collaborative mode (with collaborators) @internal */
|
|
42
|
+
const COLLABORATIVE_MODE_FPS = 30
|
|
43
|
+
|
|
38
44
|
/**
|
|
39
45
|
* WebSocket close code used by the server to signal a non-recoverable sync error.
|
|
40
46
|
* This close code indicates that the connection is being terminated due to an error
|
|
@@ -149,9 +155,9 @@ export type TLCustomMessageHandler = (this: null, data: any) => void
|
|
|
149
155
|
* Event object describing changes in socket connection status.
|
|
150
156
|
* Contains either a basic status change or an error with details.
|
|
151
157
|
*
|
|
152
|
-
* @
|
|
158
|
+
* @public
|
|
153
159
|
*/
|
|
154
|
-
export type
|
|
160
|
+
export type TLSocketStatusChangeEvent =
|
|
155
161
|
| {
|
|
156
162
|
/** Connection came online or went offline */
|
|
157
163
|
status: 'online' | 'offline'
|
|
@@ -169,7 +175,7 @@ export type TlSocketStatusChangeEvent =
|
|
|
169
175
|
*
|
|
170
176
|
* @internal
|
|
171
177
|
*/
|
|
172
|
-
export type TLSocketStatusListener = (params:
|
|
178
|
+
export type TLSocketStatusListener = (params: TLSocketStatusChangeEvent) => void
|
|
173
179
|
|
|
174
180
|
/**
|
|
175
181
|
* Possible connection states for a persistent client socket.
|
|
@@ -183,7 +189,7 @@ export type TLPersistentClientSocketStatus = 'online' | 'offline' | 'error'
|
|
|
183
189
|
* Mode for handling presence information in sync sessions.
|
|
184
190
|
* Controls whether presence data (cursors, selections) is shared with other clients.
|
|
185
191
|
*
|
|
186
|
-
* @
|
|
192
|
+
* @public
|
|
187
193
|
*/
|
|
188
194
|
export type TLPresenceMode =
|
|
189
195
|
/** No presence sharing - client operates independently */
|
|
@@ -217,9 +223,12 @@ export type TLPresenceMode =
|
|
|
217
223
|
* }
|
|
218
224
|
* ```
|
|
219
225
|
*
|
|
220
|
-
* @
|
|
226
|
+
* @public
|
|
221
227
|
*/
|
|
222
|
-
export interface TLPersistentClientSocket<
|
|
228
|
+
export interface TLPersistentClientSocket<
|
|
229
|
+
ClientSentMessage extends object = object,
|
|
230
|
+
ServerSentMessage extends object = object,
|
|
231
|
+
> {
|
|
223
232
|
/** Current connection state - online means actively connected and ready */
|
|
224
233
|
connectionStatus: 'online' | 'offline' | 'error'
|
|
225
234
|
|
|
@@ -227,27 +236,32 @@ export interface TLPersistentClientSocket<R extends UnknownRecord = UnknownRecor
|
|
|
227
236
|
* Send a protocol message to the sync server
|
|
228
237
|
* @param msg - Message to send (connect, push, ping, etc.)
|
|
229
238
|
*/
|
|
230
|
-
sendMessage(msg:
|
|
239
|
+
sendMessage(msg: ClientSentMessage): void
|
|
231
240
|
|
|
232
241
|
/**
|
|
233
242
|
* Subscribe to messages received from the server
|
|
234
243
|
* @param callback - Function called for each received message
|
|
235
244
|
* @returns Cleanup function to remove the listener
|
|
236
245
|
*/
|
|
237
|
-
onReceiveMessage: SubscribingFn<
|
|
246
|
+
onReceiveMessage: SubscribingFn<ServerSentMessage>
|
|
238
247
|
|
|
239
248
|
/**
|
|
240
249
|
* Subscribe to connection status changes
|
|
241
250
|
* @param callback - Function called when connection status changes
|
|
242
251
|
* @returns Cleanup function to remove the listener
|
|
243
252
|
*/
|
|
244
|
-
onStatusChange: SubscribingFn<
|
|
253
|
+
onStatusChange: SubscribingFn<TLSocketStatusChangeEvent>
|
|
245
254
|
|
|
246
255
|
/**
|
|
247
256
|
* Force a connection restart (disconnect then reconnect)
|
|
248
257
|
* Used for error recovery or when connection health checks fail
|
|
249
258
|
*/
|
|
250
259
|
restart(): void
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Close the connection
|
|
263
|
+
*/
|
|
264
|
+
close(): void
|
|
251
265
|
}
|
|
252
266
|
|
|
253
267
|
const PING_INTERVAL = 5000
|
|
@@ -312,7 +326,7 @@ const MAX_TIME_TO_WAIT_FOR_SERVER_INTERACTION_BEFORE_RESETTING_CONNECTION = PING
|
|
|
312
326
|
* })
|
|
313
327
|
* ```
|
|
314
328
|
*
|
|
315
|
-
* @
|
|
329
|
+
* @public
|
|
316
330
|
*/
|
|
317
331
|
export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>> {
|
|
318
332
|
/** The last clock time from the most recent server update */
|
|
@@ -335,14 +349,19 @@ export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>
|
|
|
335
349
|
|
|
336
350
|
private disposables: Array<() => void> = []
|
|
337
351
|
|
|
352
|
+
/** @internal */
|
|
338
353
|
readonly store: S
|
|
339
|
-
|
|
354
|
+
/** @internal */
|
|
355
|
+
readonly socket: TLPersistentClientSocket<TLSocketClientSentEvent<R>, TLSocketServerSentEvent<R>>
|
|
340
356
|
|
|
357
|
+
/** @internal */
|
|
341
358
|
readonly presenceState: Signal<R | null> | undefined
|
|
359
|
+
/** @internal */
|
|
342
360
|
readonly presenceMode: Signal<TLPresenceMode> | undefined
|
|
343
361
|
|
|
344
362
|
// isOnline is true when we have an open socket connection and we have
|
|
345
363
|
// established a connection with the server room (i.e. we have received a 'connect' message)
|
|
364
|
+
/** @internal */
|
|
346
365
|
isConnectedToRoom = false
|
|
347
366
|
|
|
348
367
|
/**
|
|
@@ -366,7 +385,7 @@ export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>
|
|
|
366
385
|
* @param details - Connection details
|
|
367
386
|
* - isReadonly - Whether the connection is in read-only mode
|
|
368
387
|
*/
|
|
369
|
-
|
|
388
|
+
private readonly onAfterConnect?: (self: this, details: { isReadonly: boolean }) => void
|
|
370
389
|
|
|
371
390
|
private readonly onCustomMessageReceived?: TLCustomMessageHandler
|
|
372
391
|
|
|
@@ -380,7 +399,7 @@ export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>
|
|
|
380
399
|
|
|
381
400
|
private readonly presenceType: R['typeName'] | null
|
|
382
401
|
|
|
383
|
-
didCancel?: () => boolean
|
|
402
|
+
private didCancel?: () => boolean
|
|
384
403
|
|
|
385
404
|
/**
|
|
386
405
|
* Creates a new TLSyncClient instance to manage synchronization with a remote server.
|
|
@@ -400,7 +419,7 @@ export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>
|
|
|
400
419
|
*/
|
|
401
420
|
constructor(config: {
|
|
402
421
|
store: S
|
|
403
|
-
socket: TLPersistentClientSocket<
|
|
422
|
+
socket: TLPersistentClientSocket<any, any>
|
|
404
423
|
presence: Signal<R | null>
|
|
405
424
|
presenceMode?: Signal<TLPresenceMode>
|
|
406
425
|
onLoad(self: TLSyncClient<R, S>): void
|
|
@@ -516,6 +535,7 @@ export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>
|
|
|
516
535
|
}
|
|
517
536
|
}
|
|
518
537
|
|
|
538
|
+
/** @internal */
|
|
519
539
|
latestConnectRequestId: string | null = null
|
|
520
540
|
|
|
521
541
|
/**
|
|
@@ -641,7 +661,7 @@ export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>
|
|
|
641
661
|
this.lastServerClock = event.serverClock
|
|
642
662
|
}
|
|
643
663
|
|
|
644
|
-
incomingDiffBuffer: TLSocketServerSentDataEvent<R>[] = []
|
|
664
|
+
private incomingDiffBuffer: TLSocketServerSentDataEvent<R>[] = []
|
|
645
665
|
|
|
646
666
|
/** Handle events received from the server */
|
|
647
667
|
private handleServerEvent(event: TLSocketServerSentEvent<R>) {
|
|
@@ -701,7 +721,7 @@ export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>
|
|
|
701
721
|
this.scheduleRebase.cancel?.()
|
|
702
722
|
}
|
|
703
723
|
|
|
704
|
-
lastPushedPresenceState: R | null = null
|
|
724
|
+
private lastPushedPresenceState: R | null = null
|
|
705
725
|
|
|
706
726
|
private pushPresence(nextPresence: R | null) {
|
|
707
727
|
// make sure we push any document changes first
|
|
@@ -786,6 +806,11 @@ export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>
|
|
|
786
806
|
this.flushPendingPushRequests()
|
|
787
807
|
}
|
|
788
808
|
|
|
809
|
+
/** Get the target FPS for network operations based on presence mode */
|
|
810
|
+
private getSyncFps(): number {
|
|
811
|
+
return this.presenceMode?.get() === 'solo' ? SOLO_MODE_FPS : COLLABORATIVE_MODE_FPS
|
|
812
|
+
}
|
|
813
|
+
|
|
789
814
|
/** Send any unsent push requests to the server */
|
|
790
815
|
private flushPendingPushRequests = fpsThrottle(() => {
|
|
791
816
|
this.debug('flushing pending push requests', {
|
|
@@ -805,7 +830,7 @@ export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>
|
|
|
805
830
|
pendingPushRequest.sent = true
|
|
806
831
|
}
|
|
807
832
|
}
|
|
808
|
-
})
|
|
833
|
+
}, this.getSyncFps.bind(this))
|
|
809
834
|
|
|
810
835
|
/**
|
|
811
836
|
* Applies a 'network' diff to the store this does value-based equality checking so that if the
|
|
@@ -913,5 +938,5 @@ export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>
|
|
|
913
938
|
}
|
|
914
939
|
}
|
|
915
940
|
|
|
916
|
-
private scheduleRebase = fpsThrottle(this.rebase)
|
|
941
|
+
private scheduleRebase = fpsThrottle(this.rebase, this.getSyncFps.bind(this))
|
|
917
942
|
}
|
|
@@ -62,7 +62,7 @@ export class TestSocketPair<R extends UnknownRecord> {
|
|
|
62
62
|
}
|
|
63
63
|
didReceiveFromClient?: (msg: TLSocketClientSentEvent<R>) => void = undefined
|
|
64
64
|
clientDisconnected?: () => void = undefined
|
|
65
|
-
clientSocket: TLPersistentClientSocket<R
|
|
65
|
+
clientSocket: TLPersistentClientSocket<TLSocketClientSentEvent<R>, TLSocketServerSentEvent<R>> = {
|
|
66
66
|
connectionStatus: 'offline',
|
|
67
67
|
onStatusChange: (cb) => {
|
|
68
68
|
this.callbacks.onStatusChange = cb
|
|
@@ -76,7 +76,7 @@ export class TestSocketPair<R extends UnknownRecord> {
|
|
|
76
76
|
this.callbacks.onReceiveMessage = null
|
|
77
77
|
}
|
|
78
78
|
},
|
|
79
|
-
sendMessage: (msg
|
|
79
|
+
sendMessage: (msg) => {
|
|
80
80
|
if (this.clientSocket.connectionStatus !== 'online') {
|
|
81
81
|
throw new Error('trying to send before open')
|
|
82
82
|
}
|
|
@@ -87,6 +87,9 @@ export class TestSocketPair<R extends UnknownRecord> {
|
|
|
87
87
|
this.disconnect()
|
|
88
88
|
this.connect()
|
|
89
89
|
},
|
|
90
|
+
close: () => {
|
|
91
|
+
this.disconnect()
|
|
92
|
+
},
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
callbacks = {
|