@tldraw/sync-core 4.2.0 → 4.2.2
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 +483 -58
- package/dist-cjs/index.js +13 -3
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/DurableObjectSqliteSyncWrapper.js +55 -0
- package/dist-cjs/lib/DurableObjectSqliteSyncWrapper.js.map +7 -0
- package/dist-cjs/lib/InMemorySyncStorage.js +287 -0
- package/dist-cjs/lib/InMemorySyncStorage.js.map +7 -0
- package/dist-cjs/lib/MicrotaskNotifier.js +50 -0
- package/dist-cjs/lib/MicrotaskNotifier.js.map +7 -0
- package/dist-cjs/lib/NodeSqliteWrapper.js +48 -0
- package/dist-cjs/lib/NodeSqliteWrapper.js.map +7 -0
- package/dist-cjs/lib/RoomSession.js.map +1 -1
- package/dist-cjs/lib/SQLiteSyncStorage.js +428 -0
- package/dist-cjs/lib/SQLiteSyncStorage.js.map +7 -0
- package/dist-cjs/lib/TLSocketRoom.js +117 -69
- package/dist-cjs/lib/TLSocketRoom.js.map +2 -2
- package/dist-cjs/lib/TLSyncClient.js +7 -0
- package/dist-cjs/lib/TLSyncClient.js.map +2 -2
- package/dist-cjs/lib/TLSyncRoom.js +357 -688
- package/dist-cjs/lib/TLSyncRoom.js.map +3 -3
- package/dist-cjs/lib/TLSyncStorage.js +76 -0
- package/dist-cjs/lib/TLSyncStorage.js.map +7 -0
- package/dist-cjs/lib/chunk.js +2 -2
- package/dist-cjs/lib/chunk.js.map +1 -1
- package/dist-cjs/lib/recordDiff.js +52 -0
- package/dist-cjs/lib/recordDiff.js.map +7 -0
- package/dist-esm/index.d.mts +483 -58
- package/dist-esm/index.mjs +20 -5
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/DurableObjectSqliteSyncWrapper.mjs +35 -0
- package/dist-esm/lib/DurableObjectSqliteSyncWrapper.mjs.map +7 -0
- package/dist-esm/lib/InMemorySyncStorage.mjs +272 -0
- package/dist-esm/lib/InMemorySyncStorage.mjs.map +7 -0
- package/dist-esm/lib/MicrotaskNotifier.mjs +30 -0
- package/dist-esm/lib/MicrotaskNotifier.mjs.map +7 -0
- package/dist-esm/lib/NodeSqliteWrapper.mjs +28 -0
- package/dist-esm/lib/NodeSqliteWrapper.mjs.map +7 -0
- package/dist-esm/lib/RoomSession.mjs.map +1 -1
- package/dist-esm/lib/SQLiteSyncStorage.mjs +414 -0
- package/dist-esm/lib/SQLiteSyncStorage.mjs.map +7 -0
- package/dist-esm/lib/TLSocketRoom.mjs +121 -70
- package/dist-esm/lib/TLSocketRoom.mjs.map +2 -2
- package/dist-esm/lib/TLSyncClient.mjs +7 -0
- package/dist-esm/lib/TLSyncClient.mjs.map +2 -2
- package/dist-esm/lib/TLSyncRoom.mjs +370 -702
- package/dist-esm/lib/TLSyncRoom.mjs.map +3 -3
- package/dist-esm/lib/TLSyncStorage.mjs +56 -0
- package/dist-esm/lib/TLSyncStorage.mjs.map +7 -0
- package/dist-esm/lib/chunk.mjs +2 -2
- package/dist-esm/lib/chunk.mjs.map +1 -1
- package/dist-esm/lib/recordDiff.mjs +32 -0
- package/dist-esm/lib/recordDiff.mjs.map +7 -0
- package/package.json +12 -11
- package/src/index.ts +32 -3
- package/src/lib/ClientWebSocketAdapter.test.ts +3 -0
- package/src/lib/DurableObjectSqliteSyncWrapper.ts +95 -0
- package/src/lib/InMemorySyncStorage.ts +387 -0
- package/src/lib/MicrotaskNotifier.test.ts +429 -0
- package/src/lib/MicrotaskNotifier.ts +38 -0
- package/src/lib/NodeSqliteSyncWrapper.integration.test.ts +270 -0
- package/src/lib/NodeSqliteSyncWrapper.test.ts +272 -0
- package/src/lib/NodeSqliteWrapper.ts +99 -0
- package/src/lib/RoomSession.test.ts +1 -0
- package/src/lib/RoomSession.ts +2 -0
- package/src/lib/SQLiteSyncStorage.ts +627 -0
- package/src/lib/TLSocketRoom.ts +228 -114
- package/src/lib/TLSyncClient.ts +12 -0
- package/src/lib/TLSyncRoom.ts +473 -913
- package/src/lib/TLSyncStorage.ts +216 -0
- package/src/lib/chunk.ts +2 -2
- package/src/lib/computeTombstonePruning.test.ts +352 -0
- package/src/lib/recordDiff.ts +73 -0
- package/src/test/FuzzEditor.ts +4 -5
- package/src/test/InMemorySyncStorage.test.ts +1684 -0
- package/src/test/SQLiteSyncStorage.test.ts +1378 -0
- package/src/test/TLSocketRoom.test.ts +255 -49
- package/src/test/TLSyncRoom.test.ts +1024 -534
- package/src/test/TestServer.ts +12 -1
- package/src/test/customMessages.test.ts +1 -1
- package/src/test/presenceMode.test.ts +6 -6
- package/src/test/syncFuzz.test.ts +2 -4
- package/src/test/upgradeDowngrade.test.ts +290 -8
- package/src/test/validation.test.ts +15 -10
- package/src/test/pruneTombstones.test.ts +0 -178
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { BaseRecord, createRecordType, RecordId, StoreSchema } from '@tldraw/store'
|
|
2
|
-
import { TLSyncRoom } from '../lib/TLSyncRoom'
|
|
3
|
-
import { findMin } from '../lib/findMin'
|
|
4
|
-
|
|
5
|
-
interface TestRecord extends BaseRecord<'test', RecordId<TestRecord>> {
|
|
6
|
-
name: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
describe('TLSyncRoom pruneTombstones', () => {
|
|
10
|
-
let room: TLSyncRoom<TestRecord, any>
|
|
11
|
-
let TestRecordType: any
|
|
12
|
-
let schema: StoreSchema<TestRecord, any>
|
|
13
|
-
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
TestRecordType = createRecordType<TestRecord>('test', {
|
|
16
|
-
scope: 'document',
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
schema = StoreSchema.create({
|
|
20
|
-
test: TestRecordType,
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
// Create room with empty snapshot to avoid default documents being converted to tombstones
|
|
24
|
-
room = new TLSyncRoom({
|
|
25
|
-
schema,
|
|
26
|
-
snapshot: {
|
|
27
|
-
clock: 0,
|
|
28
|
-
documents: [],
|
|
29
|
-
},
|
|
30
|
-
})
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it('should not prune when tombstone count is below threshold', () => {
|
|
34
|
-
// Add some tombstones but below MAX_TOMBSTONES (3000)
|
|
35
|
-
for (let i = 0; i < 100; i++) {
|
|
36
|
-
room.tombstones.set(`doc${i}`, i + 1)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const initialSize = room.tombstones.size
|
|
40
|
-
const initialHistoryClock = room.tombstoneHistoryStartsAtClock
|
|
41
|
-
|
|
42
|
-
// Reset needsPrune flag and call pruneTombstones
|
|
43
|
-
;(room as any).needsPrune = true
|
|
44
|
-
;(room as any).pruneTombstones()
|
|
45
|
-
|
|
46
|
-
// Should not have pruned anything
|
|
47
|
-
expect(room.tombstones.size).toBe(initialSize)
|
|
48
|
-
expect(room.tombstoneHistoryStartsAtClock).toBe(initialHistoryClock)
|
|
49
|
-
|
|
50
|
-
expect(findMin(room.tombstones.values())).toBeGreaterThanOrEqual(
|
|
51
|
-
room.tombstoneHistoryStartsAtClock
|
|
52
|
-
)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('should prune tombstones when count exceeds threshold', () => {
|
|
56
|
-
// Add more tombstones than MAX_TOMBSTONES
|
|
57
|
-
const totalTombstones = 3200 // Above MAX_TOMBSTONES (3000)
|
|
58
|
-
for (let i = 0; i < totalTombstones; i++) {
|
|
59
|
-
room.tombstones.set(`doc${i}`, i + 1)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const startCock = room.tombstoneHistoryStartsAtClock
|
|
63
|
-
|
|
64
|
-
expect(room.tombstones.size).toBe(totalTombstones)
|
|
65
|
-
|
|
66
|
-
// Reset needsPrune flag and call pruneTombstones
|
|
67
|
-
;(room as any).needsPrune = true
|
|
68
|
-
;(room as any).pruneTombstones()
|
|
69
|
-
|
|
70
|
-
expect(room.tombstones.size).toBeLessThan(totalTombstones)
|
|
71
|
-
expect(room.tombstoneHistoryStartsAtClock).toBeGreaterThan(startCock)
|
|
72
|
-
|
|
73
|
-
expect(room.tombstones.size).toMatchInlineSnapshot(`2700`) // should be about 1500
|
|
74
|
-
expect(room.tombstoneHistoryStartsAtClock).toMatchInlineSnapshot(`501`) // should be about 1700
|
|
75
|
-
|
|
76
|
-
expect(findMin(room.tombstones.values())).toBeGreaterThanOrEqual(
|
|
77
|
-
room.tombstoneHistoryStartsAtClock
|
|
78
|
-
)
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
it('should handle tombstones with same clock value correctly', () => {
|
|
82
|
-
// Add tombstones with some having the same clock values
|
|
83
|
-
const totalTombstones = 3200
|
|
84
|
-
for (let i = 0; i < totalTombstones; i++) {
|
|
85
|
-
// Use clock values that repeat: 1, 1, 1, ..., 2, 2, 2, ..., 320, 320, 320
|
|
86
|
-
const clock = Math.floor(i / 10) + 1
|
|
87
|
-
room.tombstones.set(`doc${i}`, clock)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const startCock = room.tombstoneHistoryStartsAtClock
|
|
91
|
-
|
|
92
|
-
// Reset needsPrune flag and call pruneTombstones
|
|
93
|
-
;(room as any).needsPrune = true
|
|
94
|
-
;(room as any).pruneTombstones()
|
|
95
|
-
|
|
96
|
-
// The algorithm keeps the oldest tombstones (preserving history)
|
|
97
|
-
// With repeating clock values, we have 10 tombstones for each clock 1-320
|
|
98
|
-
// We keep the oldest 200 tombstones (clocks 1-20)
|
|
99
|
-
// We delete the newest 3000 tombstones (clocks 21-320)
|
|
100
|
-
expect(room.tombstones.size).toBeLessThan(totalTombstones)
|
|
101
|
-
expect(room.tombstoneHistoryStartsAtClock).toBeGreaterThan(startCock)
|
|
102
|
-
|
|
103
|
-
expect(room.tombstones.size).toMatchInlineSnapshot(`2700`) // should be about 1500
|
|
104
|
-
expect(room.tombstoneHistoryStartsAtClock).toMatchInlineSnapshot(`51`) // should be about 150
|
|
105
|
-
|
|
106
|
-
expect(findMin(room.tombstones.values())).toBeGreaterThanOrEqual(
|
|
107
|
-
room.tombstoneHistoryStartsAtClock
|
|
108
|
-
)
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
it('should handle edge case where all tombstones have same clock value', () => {
|
|
112
|
-
// Add tombstones all with the same clock value
|
|
113
|
-
const totalTombstones = 3200
|
|
114
|
-
const sameClock = 100
|
|
115
|
-
for (let i = 0; i < totalTombstones; i++) {
|
|
116
|
-
room.tombstones.set(`doc${i}`, sameClock)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const startClock = room.tombstoneHistoryStartsAtClock
|
|
120
|
-
|
|
121
|
-
// Reset needsPrune flag and call pruneTombstones
|
|
122
|
-
;(room as any).needsPrune = true
|
|
123
|
-
;(room as any).pruneTombstones()
|
|
124
|
-
|
|
125
|
-
// When all tombstones have the same clock value, the algorithm deletes all of them
|
|
126
|
-
// because the while loop advances to the end and all tombstones are marked for deletion
|
|
127
|
-
expect(room.tombstones.size).toBeLessThan(totalTombstones)
|
|
128
|
-
expect(room.tombstoneHistoryStartsAtClock).toBeGreaterThan(startClock)
|
|
129
|
-
|
|
130
|
-
expect(room.tombstones.size).toMatchInlineSnapshot(`0`) // all deleted
|
|
131
|
-
expect(room.tombstoneHistoryStartsAtClock).toMatchInlineSnapshot(`101`) // next clock after deletion
|
|
132
|
-
|
|
133
|
-
expect(findMin(room.tombstones.values())).toBe(null) // findMin returns null for empty collections
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
it('should handle exact threshold case', () => {
|
|
137
|
-
// Add exactly MAX_TOMBSTONES tombstones
|
|
138
|
-
for (let i = 0; i < 3000; i++) {
|
|
139
|
-
room.tombstones.set(`doc${i}`, i + 1)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const initialSize = room.tombstones.size
|
|
143
|
-
expect(initialSize).toBe(3000)
|
|
144
|
-
|
|
145
|
-
// Reset needsPrune flag and call pruneTombstones
|
|
146
|
-
;(room as any).needsPrune = true
|
|
147
|
-
;(room as any).pruneTombstones()
|
|
148
|
-
|
|
149
|
-
// Should not prune anything since we're exactly at the threshold
|
|
150
|
-
expect(room.tombstones.size).toBe(initialSize)
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
it('should handle very large tombstone counts', () => {
|
|
154
|
-
// Test with a much larger number of tombstones
|
|
155
|
-
const totalTombstones = 10000
|
|
156
|
-
for (let i = 0; i < totalTombstones; i++) {
|
|
157
|
-
room.tombstones.set(`doc${i}`, i + 1)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const startClock = room.tombstoneHistoryStartsAtClock
|
|
161
|
-
|
|
162
|
-
// Reset needsPrune flag and call pruneTombstones
|
|
163
|
-
;(room as any).needsPrune = true
|
|
164
|
-
;(room as any).pruneTombstones()
|
|
165
|
-
|
|
166
|
-
// The algorithm keeps the oldest tombstones (preserving history)
|
|
167
|
-
// With 10000 tombstones, we keep about 7000 and delete about 3000
|
|
168
|
-
expect(room.tombstones.size).toBeLessThan(totalTombstones)
|
|
169
|
-
expect(room.tombstoneHistoryStartsAtClock).toBeGreaterThan(startClock)
|
|
170
|
-
|
|
171
|
-
expect(room.tombstones.size).toMatchInlineSnapshot(`2700`) // should be about 1500
|
|
172
|
-
expect(room.tombstoneHistoryStartsAtClock).toMatchInlineSnapshot(`7301`) // should be about 1500
|
|
173
|
-
|
|
174
|
-
expect(findMin(room.tombstones.values())).toBeGreaterThanOrEqual(
|
|
175
|
-
room.tombstoneHistoryStartsAtClock
|
|
176
|
-
)
|
|
177
|
-
})
|
|
178
|
-
})
|