@tldraw/sync-core 4.6.0-next.5a871ec02ff3 → 4.6.0-next.6594d48ace27
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.js +1 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/ClientWebSocketAdapter.js +3 -1
- package/dist-cjs/lib/ClientWebSocketAdapter.js.map +2 -2
- package/dist-cjs/lib/DurableObjectSqliteSyncWrapper.js +4 -0
- package/dist-cjs/lib/DurableObjectSqliteSyncWrapper.js.map +2 -2
- package/dist-cjs/lib/InMemorySyncStorage.js +1 -0
- package/dist-cjs/lib/InMemorySyncStorage.js.map +2 -2
- package/dist-cjs/lib/NodeSqliteWrapper.js +2 -0
- package/dist-cjs/lib/NodeSqliteWrapper.js.map +1 -1
- package/dist-cjs/lib/RoomSession.js.map +1 -1
- package/dist-cjs/lib/SQLiteSyncStorage.js +2 -0
- package/dist-cjs/lib/SQLiteSyncStorage.js.map +1 -1
- package/dist-cjs/lib/ServerSocketAdapter.js +2 -1
- package/dist-cjs/lib/ServerSocketAdapter.js.map +2 -2
- package/dist-cjs/lib/TLRemoteSyncError.js +1 -0
- package/dist-cjs/lib/TLRemoteSyncError.js.map +1 -1
- package/dist-cjs/lib/TLSocketRoom.js +4 -1
- package/dist-cjs/lib/TLSocketRoom.js.map +2 -2
- package/dist-cjs/lib/TLSyncClient.js +5 -1
- package/dist-cjs/lib/TLSyncClient.js.map +2 -2
- package/dist-cjs/lib/TLSyncRoom.js +7 -1
- package/dist-cjs/lib/TLSyncRoom.js.map +2 -2
- package/dist-cjs/lib/protocol.js.map +1 -1
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/ClientWebSocketAdapter.mjs +3 -1
- package/dist-esm/lib/ClientWebSocketAdapter.mjs.map +2 -2
- package/dist-esm/lib/DurableObjectSqliteSyncWrapper.mjs +4 -0
- package/dist-esm/lib/DurableObjectSqliteSyncWrapper.mjs.map +2 -2
- package/dist-esm/lib/InMemorySyncStorage.mjs +1 -0
- package/dist-esm/lib/InMemorySyncStorage.mjs.map +2 -2
- package/dist-esm/lib/NodeSqliteWrapper.mjs +2 -0
- package/dist-esm/lib/NodeSqliteWrapper.mjs.map +1 -1
- package/dist-esm/lib/RoomSession.mjs.map +1 -1
- package/dist-esm/lib/SQLiteSyncStorage.mjs +2 -0
- package/dist-esm/lib/SQLiteSyncStorage.mjs.map +1 -1
- package/dist-esm/lib/ServerSocketAdapter.mjs +2 -1
- package/dist-esm/lib/ServerSocketAdapter.mjs.map +2 -2
- package/dist-esm/lib/TLRemoteSyncError.mjs +1 -0
- package/dist-esm/lib/TLRemoteSyncError.mjs.map +1 -1
- package/dist-esm/lib/TLSocketRoom.mjs +4 -1
- package/dist-esm/lib/TLSocketRoom.mjs.map +2 -2
- package/dist-esm/lib/TLSyncClient.mjs +5 -1
- package/dist-esm/lib/TLSyncClient.mjs.map +2 -2
- package/dist-esm/lib/TLSyncRoom.mjs +7 -1
- package/dist-esm/lib/TLSyncRoom.mjs.map +2 -2
- package/dist-esm/lib/protocol.mjs.map +1 -1
- package/package.json +6 -6
- package/src/index.ts +2 -0
- package/src/lib/ClientWebSocketAdapter.test.ts +2 -2
- package/src/lib/ClientWebSocketAdapter.ts +5 -5
- package/src/lib/DurableObjectSqliteSyncWrapper.ts +1 -2
- package/src/lib/InMemorySyncStorage.ts +3 -3
- package/src/lib/RoomSession.ts +1 -1
- package/src/lib/ServerSocketAdapter.test.ts +1 -1
- package/src/lib/ServerSocketAdapter.ts +7 -7
- package/src/lib/TLSocketRoom.ts +7 -7
- package/src/lib/TLSyncClient.test.ts +4 -7
- package/src/lib/TLSyncClient.ts +4 -1
- package/src/lib/TLSyncRoom.ts +9 -1
- package/src/lib/protocol.ts +2 -0
- package/src/test/RandomSource.ts +1 -1
- package/src/test/SQLiteSyncStorage.test.ts +1 -1
- package/src/test/TLSocketRoom.test.ts +8 -12
- package/src/test/TLSyncRoom.test.ts +1 -1
- package/src/test/TestSocketPair.ts +2 -2
- package/src/test/syncFuzz.test.ts +13 -6
- package/src/test/upgradeDowngrade.test.ts +2 -2
- package/src/test/validation.test.ts +1 -1
|
@@ -30,13 +30,10 @@ const protocolVersion = getTlsyncProtocolVersion()
|
|
|
30
30
|
type TestRecord = TLRecord
|
|
31
31
|
|
|
32
32
|
// Mock socket implementation for testing
|
|
33
|
-
class MockSocket
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
TLSocketServerSentEvent<TestRecord>
|
|
38
|
-
>
|
|
39
|
-
{
|
|
33
|
+
class MockSocket implements TLPersistentClientSocket<
|
|
34
|
+
TLSocketClientSentEvent<TestRecord>,
|
|
35
|
+
TLSocketServerSentEvent<TestRecord>
|
|
36
|
+
> {
|
|
40
37
|
connectionStatus: 'online' | 'offline' | 'error' = 'offline'
|
|
41
38
|
private messageListeners: Array<(msg: TLSocketServerSentEvent<TestRecord>) => void> = []
|
|
42
39
|
private statusListeners: Array<(event: TLSocketStatusChangeEvent) => void> = []
|
package/src/lib/TLSyncClient.ts
CHANGED
|
@@ -826,6 +826,9 @@ export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>
|
|
|
826
826
|
this.disposables.forEach((dispose) => dispose())
|
|
827
827
|
this.sendUnsentChanges.cancel?.()
|
|
828
828
|
this.scheduleRebase.cancel?.()
|
|
829
|
+
if (typeof window !== 'undefined' && (window as any).tlsync === this) {
|
|
830
|
+
delete (window as any).tlsync
|
|
831
|
+
}
|
|
829
832
|
}
|
|
830
833
|
|
|
831
834
|
private lastPushedPresenceState: R | null = null
|
|
@@ -903,7 +906,7 @@ export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>
|
|
|
903
906
|
}
|
|
904
907
|
}
|
|
905
908
|
|
|
906
|
-
// eslint-disable-next-line
|
|
909
|
+
// eslint-disable-next-line tldraw/prefer-class-methods
|
|
907
910
|
private rebase = () => {
|
|
908
911
|
// need to make sure that our speculative changes are in sync with the actual store instance before
|
|
909
912
|
// proceeding, to avoid inconsistency bugs.
|
package/src/lib/TLSyncRoom.ts
CHANGED
|
@@ -910,7 +910,15 @@ export class TLSyncRoom<R extends UnknownRecord, SessionMeta> {
|
|
|
910
910
|
sessionSchema,
|
|
911
911
|
requiresDownMigrations,
|
|
912
912
|
{
|
|
913
|
-
|
|
913
|
+
// Exclude the connecting session's own presence — it will push fresh
|
|
914
|
+
// data immediately after connecting. Sending the stale record back
|
|
915
|
+
// would leave an orphaned presence in the client's local store (the
|
|
916
|
+
// server never echoes a session's own updates back to it).
|
|
917
|
+
puts: Object.fromEntries(
|
|
918
|
+
[...this.presenceStore.values()]
|
|
919
|
+
.filter((p) => p.id !== session.presenceId)
|
|
920
|
+
.map((p) => [p.id, p])
|
|
921
|
+
),
|
|
914
922
|
deletes: [],
|
|
915
923
|
}
|
|
916
924
|
)
|
package/src/lib/protocol.ts
CHANGED
|
@@ -69,8 +69,10 @@ export const TLIncompatibilityReason = {
|
|
|
69
69
|
* @internal
|
|
70
70
|
* @deprecated replaced by websocket .close status/reason
|
|
71
71
|
*/
|
|
72
|
+
/* eslint-disable @typescript-eslint/no-deprecated */
|
|
72
73
|
export type TLIncompatibilityReason =
|
|
73
74
|
(typeof TLIncompatibilityReason)[keyof typeof TLIncompatibilityReason]
|
|
75
|
+
/* eslint-enable @typescript-eslint/no-deprecated */
|
|
74
76
|
|
|
75
77
|
/**
|
|
76
78
|
* Union type representing all possible message types that can be sent from server to client.
|
package/src/test/RandomSource.ts
CHANGED
|
@@ -19,7 +19,7 @@ export class RandomSource {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
randomAction<Result>(
|
|
22
|
-
// eslint-disable-next-line
|
|
22
|
+
// eslint-disable-next-line tldraw/method-signature-style
|
|
23
23
|
choices: Array<(() => Result) | { weight: number; do: () => any }>,
|
|
24
24
|
randomWeights?: boolean
|
|
25
25
|
): Result {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DatabaseSync } from 'node:sqlite'
|
|
1
2
|
import {
|
|
2
3
|
BaseRecord,
|
|
3
4
|
createMigrationSequence,
|
|
@@ -13,7 +14,6 @@ import {
|
|
|
13
14
|
TLRecord,
|
|
14
15
|
} from '@tldraw/tlschema'
|
|
15
16
|
import { IndexKey, ZERO_INDEX_KEY } from '@tldraw/utils'
|
|
16
|
-
import { DatabaseSync } from 'node:sqlite'
|
|
17
17
|
import { vi } from 'vitest'
|
|
18
18
|
import { MAX_TOMBSTONES, TOMBSTONE_PRUNE_BUFFER_SIZE } from '../lib/InMemorySyncStorage'
|
|
19
19
|
import { NodeSqliteWrapper } from '../lib/NodeSqliteWrapper'
|
|
@@ -1344,12 +1344,10 @@ describe('TLSocketRoom.updateStore', () => {
|
|
|
1344
1344
|
document.name = 'My lovely document'
|
|
1345
1345
|
store.put(document)
|
|
1346
1346
|
})
|
|
1347
|
-
|
|
1348
|
-
(
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
).name
|
|
1352
|
-
).toBe('My lovely document')
|
|
1347
|
+
const docRecord = storage
|
|
1348
|
+
.getSnapshot()
|
|
1349
|
+
.documents.find((r) => r.state.id === 'document:document') as any
|
|
1350
|
+
expect(docRecord.state.name).toBe('My lovely document')
|
|
1353
1351
|
expect(clock).toBeLessThan(storage.getClock())
|
|
1354
1352
|
})
|
|
1355
1353
|
|
|
@@ -1359,12 +1357,10 @@ describe('TLSocketRoom.updateStore', () => {
|
|
|
1359
1357
|
const document = store.get('document:document') as TLDocument
|
|
1360
1358
|
document.name = 'My lovely document'
|
|
1361
1359
|
})
|
|
1362
|
-
|
|
1363
|
-
(
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
).name
|
|
1367
|
-
).toBe('')
|
|
1360
|
+
const docRecord = storage
|
|
1361
|
+
.getSnapshot()
|
|
1362
|
+
.documents.find((r) => r.state.id === 'document:document') as any
|
|
1363
|
+
expect(docRecord.state.name).toBe('')
|
|
1368
1364
|
expect(clock).toBe(storage.getClock())
|
|
1369
1365
|
})
|
|
1370
1366
|
|
|
@@ -16,13 +16,13 @@ import {
|
|
|
16
16
|
import { IndexKey, ZERO_INDEX_KEY, mockUniqueId, sortById } from '@tldraw/utils'
|
|
17
17
|
import { vi } from 'vitest'
|
|
18
18
|
import { InMemorySyncStorage } from '../lib/InMemorySyncStorage'
|
|
19
|
-
import { RoomSnapshot, TLRoomSocket, TLSyncRoom } from '../lib/TLSyncRoom'
|
|
20
19
|
import {
|
|
21
20
|
TLConnectRequest,
|
|
22
21
|
TLPushRequest,
|
|
23
22
|
TLSocketServerSentEvent,
|
|
24
23
|
getTlsyncProtocolVersion,
|
|
25
24
|
} from '../lib/protocol'
|
|
25
|
+
import { RoomSnapshot, TLRoomSocket, TLSyncRoom } from '../lib/TLSyncRoom'
|
|
26
26
|
|
|
27
27
|
const schema = createTLSchema()
|
|
28
28
|
const compareById = (a: { id: string }, b: { id: string }) => a.id.localeCompare(b.id)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { UnknownRecord } from '@tldraw/store'
|
|
2
2
|
import { structuredClone } from '@tldraw/utils'
|
|
3
|
+
import { TLSocketClientSentEvent, TLSocketServerSentEvent } from '../lib/protocol'
|
|
3
4
|
import {
|
|
4
5
|
TLPersistentClientSocket,
|
|
5
6
|
TLSocketStatusListener,
|
|
@@ -7,7 +8,6 @@ import {
|
|
|
7
8
|
TLSyncErrorCloseEventReason,
|
|
8
9
|
} from '../lib/TLSyncClient'
|
|
9
10
|
import { TLRoomSocket } from '../lib/TLSyncRoom'
|
|
10
|
-
import { TLSocketClientSentEvent, TLSocketServerSentEvent } from '../lib/protocol'
|
|
11
11
|
import { TestServer } from './TestServer'
|
|
12
12
|
|
|
13
13
|
export class TestSocketPair<R extends UnknownRecord> {
|
|
@@ -97,7 +97,7 @@ export class TestSocketPair<R extends UnknownRecord> {
|
|
|
97
97
|
onStatusChange: null as null | TLSocketStatusListener,
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
// eslint-disable-next-line no-
|
|
100
|
+
// eslint-disable-next-line tldraw/no-setter-getter
|
|
101
101
|
get isConnected() {
|
|
102
102
|
return this.clientSocket.connectionStatus === 'online'
|
|
103
103
|
}
|
|
@@ -2,10 +2,12 @@ import {
|
|
|
2
2
|
Editor,
|
|
3
3
|
TLRecord,
|
|
4
4
|
TLStore,
|
|
5
|
+
UserRecordType,
|
|
5
6
|
computed,
|
|
6
7
|
createPresenceStateDerivation,
|
|
7
8
|
createTLSchema,
|
|
8
9
|
createTLStore,
|
|
10
|
+
createUserId,
|
|
9
11
|
isRecordsDiffEmpty,
|
|
10
12
|
mockUniqueId,
|
|
11
13
|
uniqueId,
|
|
@@ -83,12 +85,13 @@ class FuzzTestInstance extends RandomSource {
|
|
|
83
85
|
this.editor = new FuzzEditor(this.id, this.seed, this.store)
|
|
84
86
|
},
|
|
85
87
|
presence: createPresenceStateDerivation(
|
|
86
|
-
computed('', () =>
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
computed('', () =>
|
|
89
|
+
UserRecordType.create({
|
|
90
|
+
id: createUserId(this.id),
|
|
91
|
+
name: 'test',
|
|
92
|
+
color: 'red',
|
|
93
|
+
})
|
|
94
|
+
)
|
|
92
95
|
)(this.store),
|
|
93
96
|
})
|
|
94
97
|
|
|
@@ -287,6 +290,10 @@ test('seed 5279266392988747 - undo/redo page integrity regression', () => {
|
|
|
287
290
|
runTest(5279266392988747)
|
|
288
291
|
})
|
|
289
292
|
|
|
293
|
+
test('seed 8090628137862085 - duplicate index key regression', () => {
|
|
294
|
+
runTest(8090628137862085)
|
|
295
|
+
})
|
|
296
|
+
|
|
290
297
|
for (let i = 0; i < NUM_TESTS; i++) {
|
|
291
298
|
const seed = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)
|
|
292
299
|
test(`seed ${seed}`, () => {
|
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
createRecordType,
|
|
12
12
|
} from '@tldraw/store'
|
|
13
13
|
import { vi, type Mock } from 'vitest'
|
|
14
|
-
import { TLSyncClient, TLSyncErrorCloseEventReason } from '../lib/TLSyncClient'
|
|
15
|
-
import { RoomSnapshot, TLRoomSocket } from '../lib/TLSyncRoom'
|
|
16
14
|
import { RecordOpType, ValueOpType } from '../lib/diff'
|
|
17
15
|
import { TLSocketServerSentEvent, getTlsyncProtocolVersion } from '../lib/protocol'
|
|
16
|
+
import { TLSyncClient, TLSyncErrorCloseEventReason } from '../lib/TLSyncClient'
|
|
17
|
+
import { RoomSnapshot, TLRoomSocket } from '../lib/TLSyncRoom'
|
|
18
18
|
import { TestServer } from './TestServer'
|
|
19
19
|
import { TestSocketPair } from './TestSocketPair'
|
|
20
20
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { computed } from '@tldraw/state'
|
|
2
2
|
import { RecordId, Store, StoreSchema, UnknownRecord, createRecordType } from '@tldraw/store'
|
|
3
3
|
import { vi } from 'vitest'
|
|
4
|
-
import { TLSyncClient, TLSyncErrorCloseEventReason } from '../lib/TLSyncClient'
|
|
5
4
|
import { RecordOpType } from '../lib/diff'
|
|
5
|
+
import { TLSyncClient, TLSyncErrorCloseEventReason } from '../lib/TLSyncClient'
|
|
6
6
|
import { TestServer } from './TestServer'
|
|
7
7
|
import { TestSocketPair } from './TestSocketPair'
|
|
8
8
|
|