@tldraw/sync-core 4.2.1 → 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
package/dist-cjs/index.d.ts
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { Atom } from '@tldraw/state';
|
|
2
2
|
import { AtomMap } from '@tldraw/store';
|
|
3
|
+
import { DebouncedFunc } from 'lodash';
|
|
3
4
|
import { Emitter } from 'nanoevents';
|
|
4
5
|
import { RecordsDiff } from '@tldraw/store';
|
|
5
6
|
import { RecordType } from '@tldraw/store';
|
|
6
|
-
import { Result } from '@tldraw/utils';
|
|
7
7
|
import { SerializedSchema } from '@tldraw/store';
|
|
8
|
+
import { SerializedSchemaV2 } from '@tldraw/store';
|
|
8
9
|
import { Signal } from '@tldraw/state';
|
|
9
10
|
import { Store } from '@tldraw/store';
|
|
10
11
|
import { StoreSchema } from '@tldraw/store';
|
|
12
|
+
import { StoreSnapshot } from '@tldraw/store';
|
|
13
|
+
import { SynchronousStorage } from '@tldraw/store';
|
|
14
|
+
import { TLDocument } from '@tldraw/tlschema';
|
|
15
|
+
import { TLPage } from '@tldraw/tlschema';
|
|
11
16
|
import { TLRecord } from '@tldraw/tlschema';
|
|
12
17
|
import { TLStoreSnapshot } from '@tldraw/tlschema';
|
|
18
|
+
import { TLStoreSnapshot as TLStoreSnapshot_2 } from 'tldraw';
|
|
13
19
|
import { UnknownRecord } from '@tldraw/store';
|
|
14
20
|
|
|
15
21
|
/* Excluded from this release type: AppendOp */
|
|
@@ -20,16 +26,103 @@ import { UnknownRecord } from '@tldraw/store';
|
|
|
20
26
|
|
|
21
27
|
/* Excluded from this release type: ClientWebSocketAdapter */
|
|
22
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Default initial snapshot for a new room.
|
|
31
|
+
* @public
|
|
32
|
+
*/
|
|
33
|
+
export declare const DEFAULT_INITIAL_SNAPSHOT: {
|
|
34
|
+
documentClock: number;
|
|
35
|
+
documents: ({
|
|
36
|
+
lastChangedClock: number;
|
|
37
|
+
state: TLDocument;
|
|
38
|
+
} | {
|
|
39
|
+
lastChangedClock: number;
|
|
40
|
+
state: TLPage;
|
|
41
|
+
})[];
|
|
42
|
+
schema: SerializedSchemaV2;
|
|
43
|
+
tombstoneHistoryStartsAtClock: number;
|
|
44
|
+
};
|
|
45
|
+
|
|
23
46
|
/* Excluded from this release type: DeleteOp */
|
|
24
47
|
|
|
25
48
|
/* Excluded from this release type: diffRecord */
|
|
26
49
|
|
|
27
|
-
|
|
50
|
+
/**
|
|
51
|
+
* A wrapper around Cloudflare Durable Object's SqlStorage that implements TLSyncSqliteWrapper.
|
|
52
|
+
*
|
|
53
|
+
* Use this wrapper with SQLiteSyncStorage to persist tldraw sync state using
|
|
54
|
+
* Cloudflare Durable Object's built-in SQLite storage. This provides automatic
|
|
55
|
+
* persistence that survives Durable Object hibernation and restarts.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* import { SQLiteSyncStorage, DurableObjectSqliteSyncWrapper } from '@tldraw/sync-core'
|
|
60
|
+
*
|
|
61
|
+
* // In your Durable Object class:
|
|
62
|
+
* class MyDurableObject extends DurableObject {
|
|
63
|
+
* private storage: SQLiteSyncStorage
|
|
64
|
+
*
|
|
65
|
+
* constructor(ctx: DurableObjectState, env: Env) {
|
|
66
|
+
* super(ctx, env)
|
|
67
|
+
* const sql = new DurableObjectSqliteSyncWrapper(ctx.storage)
|
|
68
|
+
* this.storage = new SQLiteSyncStorage({ sql })
|
|
69
|
+
* }
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* // With table prefix to avoid conflicts with other tables
|
|
76
|
+
* const sql = new DurableObjectSqliteSyncWrapper(this.ctx.storage, { tablePrefix: 'tldraw_' })
|
|
77
|
+
* // Creates tables: tldraw_documents, tldraw_tombstones, tldraw_metadata
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* @public
|
|
81
|
+
*/
|
|
82
|
+
export declare class DurableObjectSqliteSyncWrapper implements TLSyncSqliteWrapper {
|
|
83
|
+
private storage;
|
|
84
|
+
config?: TLSyncSqliteWrapperConfig | undefined;
|
|
85
|
+
constructor(storage: {
|
|
86
|
+
sql: {
|
|
87
|
+
exec(sql: string, ...bindings: unknown[]): Iterable<any> & {
|
|
88
|
+
toArray(): any[];
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
transactionSync(callback: () => any): any;
|
|
92
|
+
}, config?: TLSyncSqliteWrapperConfig | undefined);
|
|
93
|
+
exec(sql: string): void;
|
|
94
|
+
prepare<TResult extends TLSqliteRow | void = void, TParams extends TLSqliteInputValue[] = []>(sql: string): TLSyncSqliteStatement<TResult, TParams>;
|
|
95
|
+
transaction<T>(callback: () => T): T;
|
|
96
|
+
}
|
|
28
97
|
|
|
29
98
|
/* Excluded from this release type: getNetworkDiff */
|
|
30
99
|
|
|
31
100
|
/* Excluded from this release type: getTlsyncProtocolVersion */
|
|
32
101
|
|
|
102
|
+
/**
|
|
103
|
+
* In-memory implementation of TLSyncStorage using AtomMap for documents and tombstones,
|
|
104
|
+
* and atoms for clock values. This is the default storage implementation used by TLSyncRoom.
|
|
105
|
+
*
|
|
106
|
+
* @public
|
|
107
|
+
*/
|
|
108
|
+
export declare class InMemorySyncStorage<R extends UnknownRecord> implements TLSyncStorage<R> {
|
|
109
|
+
/* Excluded from this release type: documents */
|
|
110
|
+
/* Excluded from this release type: tombstones */
|
|
111
|
+
/* Excluded from this release type: schema */
|
|
112
|
+
/* Excluded from this release type: documentClock */
|
|
113
|
+
/* Excluded from this release type: tombstoneHistoryStartsAtClock */
|
|
114
|
+
private notifier;
|
|
115
|
+
onChange(callback: (arg: TLSyncStorageOnChangeCallbackProps) => unknown): () => void;
|
|
116
|
+
constructor({ snapshot, onChange, }?: {
|
|
117
|
+
onChange?(arg: TLSyncStorageOnChangeCallbackProps): unknown;
|
|
118
|
+
snapshot?: RoomSnapshot;
|
|
119
|
+
});
|
|
120
|
+
transaction<T>(callback: TLSyncStorageTransactionCallback<R, T>, opts?: TLSyncStorageTransactionOptions): TLSyncStorageTransactionResult<T, R>;
|
|
121
|
+
getClock(): number;
|
|
122
|
+
/* Excluded from this release type: pruneTombstones */
|
|
123
|
+
getSnapshot(): RoomSnapshot;
|
|
124
|
+
}
|
|
125
|
+
|
|
33
126
|
/**
|
|
34
127
|
* Assembles chunked JSON messages back into complete objects.
|
|
35
128
|
* Handles both regular JSON messages and chunked messages created by the chunk() function.
|
|
@@ -66,8 +159,8 @@ export declare class JsonChunkAssembler {
|
|
|
66
159
|
*
|
|
67
160
|
* @param msg - The message to process, either JSON or chunk format
|
|
68
161
|
* @returns Result object with data/stringified on success, error object on failure, or null for incomplete chunks
|
|
69
|
-
*
|
|
70
|
-
*
|
|
162
|
+
* - `\{ data: object, stringified: string \}` - Successfully parsed complete message
|
|
163
|
+
* - `\{ error: Error \}` - Parse error or invalid chunk sequence
|
|
71
164
|
* - `null` - Chunk received but more chunks expected
|
|
72
165
|
*
|
|
73
166
|
* @example
|
|
@@ -94,8 +187,68 @@ export declare class JsonChunkAssembler {
|
|
|
94
187
|
} | null;
|
|
95
188
|
}
|
|
96
189
|
|
|
190
|
+
/**
|
|
191
|
+
* Loads a snapshot into storage during a transaction.
|
|
192
|
+
* Migrates the snapshot to the current schema and loads it into storage.
|
|
193
|
+
*
|
|
194
|
+
* @public
|
|
195
|
+
* @param txn - The transaction to load the snapshot into
|
|
196
|
+
* @param schema - The current schema
|
|
197
|
+
* @param snapshot - The snapshot to load
|
|
198
|
+
*/
|
|
199
|
+
export declare function loadSnapshotIntoStorage<R extends UnknownRecord>(txn: TLSyncStorageTransaction<R>, schema: StoreSchema<R, any>, snapshot: RoomSnapshot | TLStoreSnapshot_2): void;
|
|
200
|
+
|
|
201
|
+
/* Excluded from this release type: MinimalDocStore */
|
|
202
|
+
|
|
97
203
|
/* Excluded from this release type: NetworkDiff */
|
|
98
204
|
|
|
205
|
+
/**
|
|
206
|
+
* A wrapper around synchronous SQLite databases that implements TLSyncSqliteWrapper.
|
|
207
|
+
* Works with both `node:sqlite` DatabaseSync (Node.js 22.5+) and `better-sqlite3` Database.
|
|
208
|
+
*
|
|
209
|
+
* Use this wrapper with SQLiteSyncStorage to persist tldraw sync state to a SQLite database
|
|
210
|
+
* in Node.js environments.
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```ts
|
|
214
|
+
* // With node:sqlite (Node.js 22.5+)
|
|
215
|
+
* import { DatabaseSync } from 'node:sqlite'
|
|
216
|
+
* import { SQLiteSyncStorage, NodeSqliteWrapper } from '@tldraw/sync-core'
|
|
217
|
+
*
|
|
218
|
+
* const db = new DatabaseSync(':memory:')
|
|
219
|
+
* const sql = new NodeSqliteWrapper(db)
|
|
220
|
+
* const storage = new SQLiteSyncStorage({ sql })
|
|
221
|
+
* ```
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```ts
|
|
225
|
+
* // With better-sqlite3
|
|
226
|
+
* import Database from 'better-sqlite3'
|
|
227
|
+
* import { SQLiteSyncStorage, NodeSqliteWrapper } from '@tldraw/sync-core'
|
|
228
|
+
*
|
|
229
|
+
* const db = new Database(':memory:')
|
|
230
|
+
* const sql = new NodeSqliteWrapper(db)
|
|
231
|
+
* const storage = new SQLiteSyncStorage({ sql })
|
|
232
|
+
* ```
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* // With table prefix to avoid conflicts with other tables
|
|
237
|
+
* const sql = new NodeSqliteWrapper(db, { tablePrefix: 'tldraw_' })
|
|
238
|
+
* // Creates tables: tldraw_documents, tldraw_tombstones, tldraw_metadata
|
|
239
|
+
* ```
|
|
240
|
+
*
|
|
241
|
+
* @public
|
|
242
|
+
*/
|
|
243
|
+
export declare class NodeSqliteWrapper implements TLSyncSqliteWrapper {
|
|
244
|
+
private db;
|
|
245
|
+
config?: TLSyncSqliteWrapperConfig | undefined;
|
|
246
|
+
constructor(db: SyncSqliteDatabase, config?: TLSyncSqliteWrapperConfig | undefined);
|
|
247
|
+
exec(sql: string): void;
|
|
248
|
+
prepare<TResult extends TLSqliteRow | void = void, TParams extends TLSqliteInputValue[] = TLSqliteInputValue[]>(sql: string): TLSyncSqliteStatement<TResult, TParams>;
|
|
249
|
+
transaction<T>(callback: () => T): T;
|
|
250
|
+
}
|
|
251
|
+
|
|
99
252
|
/* Excluded from this release type: ObjectDiff */
|
|
100
253
|
|
|
101
254
|
/**
|
|
@@ -119,6 +272,8 @@ export declare type OmitVoid<T, KS extends keyof T = keyof T> = {
|
|
|
119
272
|
|
|
120
273
|
/* Excluded from this release type: PersistedRoomSnapshotForSupabase */
|
|
121
274
|
|
|
275
|
+
/* Excluded from this release type: PresenceStore */
|
|
276
|
+
|
|
122
277
|
/* Excluded from this release type: PutOp */
|
|
123
278
|
|
|
124
279
|
/* Excluded from this release type: ReconnectManager */
|
|
@@ -143,7 +298,7 @@ export declare interface RoomSnapshot {
|
|
|
143
298
|
/**
|
|
144
299
|
* The current logical clock value for the room
|
|
145
300
|
*/
|
|
146
|
-
clock
|
|
301
|
+
clock?: number;
|
|
147
302
|
/**
|
|
148
303
|
* Clock value when document data was last changed (optional for backwards compatibility)
|
|
149
304
|
*/
|
|
@@ -185,6 +340,7 @@ export declare interface RoomSnapshot {
|
|
|
185
340
|
* ```
|
|
186
341
|
*
|
|
187
342
|
* @public
|
|
343
|
+
* @deprecated use the storage.transaction method instead
|
|
188
344
|
*/
|
|
189
345
|
export declare interface RoomStoreMethods<R extends UnknownRecord = UnknownRecord> {
|
|
190
346
|
/**
|
|
@@ -214,6 +370,73 @@ export declare interface RoomStoreMethods<R extends UnknownRecord = UnknownRecor
|
|
|
214
370
|
getAll(): R[];
|
|
215
371
|
}
|
|
216
372
|
|
|
373
|
+
/**
|
|
374
|
+
* SQLite-based implementation of TLSyncStorage.
|
|
375
|
+
* Stores documents, tombstones, metadata, and clock values in SQLite tables.
|
|
376
|
+
*
|
|
377
|
+
* This storage backend provides persistent synchronization state that survives
|
|
378
|
+
* process restarts, unlike InMemorySyncStorage which loses data when the process ends.
|
|
379
|
+
*
|
|
380
|
+
* @example
|
|
381
|
+
* ```ts
|
|
382
|
+
* // With Cloudflare Durable Objects
|
|
383
|
+
* import { SQLiteSyncStorage, DurableObjectSqliteSyncWrapper } from '@tldraw/sync-core'
|
|
384
|
+
*
|
|
385
|
+
* const sql = new DurableObjectSqliteSyncWrapper(this.ctx.storage)
|
|
386
|
+
* const storage = new SQLiteSyncStorage({ sql })
|
|
387
|
+
* ```
|
|
388
|
+
*
|
|
389
|
+
* @example
|
|
390
|
+
* ```ts
|
|
391
|
+
* // With Node.js sqlite (Node 22.5+)
|
|
392
|
+
* import { DatabaseSync } from 'node:sqlite'
|
|
393
|
+
* import { SQLiteSyncStorage, NodeSqliteWrapper } from '@tldraw/sync-core'
|
|
394
|
+
*
|
|
395
|
+
* const db = new DatabaseSync('sync-state.db')
|
|
396
|
+
* const sql = new NodeSqliteWrapper(db)
|
|
397
|
+
* const storage = new SQLiteSyncStorage({ sql })
|
|
398
|
+
* ```
|
|
399
|
+
*
|
|
400
|
+
* @example
|
|
401
|
+
* ```ts
|
|
402
|
+
* // Initialize with an existing snapshot
|
|
403
|
+
* const storage = new SQLiteSyncStorage({ sql, snapshot: existingSnapshot })
|
|
404
|
+
* ```
|
|
405
|
+
*
|
|
406
|
+
* @public
|
|
407
|
+
*/
|
|
408
|
+
export declare class SQLiteSyncStorage<R extends UnknownRecord> implements TLSyncStorage<R> {
|
|
409
|
+
/**
|
|
410
|
+
* Check if the storage has been initialized (has data in the clock table).
|
|
411
|
+
* Useful for determining whether to load from an external source on first access.
|
|
412
|
+
*/
|
|
413
|
+
static hasBeenInitialized(storage: TLSyncSqliteWrapper): boolean;
|
|
414
|
+
/**
|
|
415
|
+
* Get the current document clock value from storage without fully initializing.
|
|
416
|
+
* Returns null if storage has not been initialized.
|
|
417
|
+
* Useful for comparing storage freshness against external sources.
|
|
418
|
+
*/
|
|
419
|
+
static getDocumentClock(storage: TLSyncSqliteWrapper): null | number;
|
|
420
|
+
private readonly stmts;
|
|
421
|
+
private readonly sql;
|
|
422
|
+
constructor({ sql, snapshot, onChange, }: {
|
|
423
|
+
onChange?(arg: TLSyncStorageOnChangeCallbackProps): unknown;
|
|
424
|
+
snapshot?: RoomSnapshot | StoreSnapshot<R>;
|
|
425
|
+
sql: TLSyncSqliteWrapper;
|
|
426
|
+
});
|
|
427
|
+
private notifier;
|
|
428
|
+
onChange(callback: (arg: TLSyncStorageOnChangeCallbackProps) => void): () => void;
|
|
429
|
+
transaction<T>(callback: TLSyncStorageTransactionCallback<R, T>, opts?: TLSyncStorageTransactionOptions): TLSyncStorageTransactionResult<T, R>;
|
|
430
|
+
getClock(): number;
|
|
431
|
+
/* Excluded from this release type: _getTombstoneHistoryStartsAtClock */
|
|
432
|
+
/* Excluded from this release type: _getSchema */
|
|
433
|
+
/* Excluded from this release type: _setSchema */
|
|
434
|
+
/* Excluded from this release type: pruneTombstones */
|
|
435
|
+
getSnapshot(): RoomSnapshot;
|
|
436
|
+
private _iterateDocuments;
|
|
437
|
+
private _iterateTombstones;
|
|
438
|
+
}
|
|
439
|
+
|
|
217
440
|
/**
|
|
218
441
|
* Function type for subscribing to events with a callback.
|
|
219
442
|
* Returns an unsubscribe function to clean up the listener.
|
|
@@ -225,6 +448,29 @@ export declare interface RoomStoreMethods<R extends UnknownRecord = UnknownRecor
|
|
|
225
448
|
*/
|
|
226
449
|
export declare type SubscribingFn<T> = (cb: (val: T) => void) => () => void;
|
|
227
450
|
|
|
451
|
+
/**
|
|
452
|
+
* Minimal interface for a synchronous SQLite database.
|
|
453
|
+
*
|
|
454
|
+
* This interface is compatible with:
|
|
455
|
+
* - `node:sqlite` DatabaseSync (Node.js 22.5+)
|
|
456
|
+
* - `better-sqlite3` Database
|
|
457
|
+
*
|
|
458
|
+
* Any SQLite library that provides synchronous `exec` and `prepare` methods
|
|
459
|
+
* with the signatures below can be used with {@link NodeSqliteWrapper}.
|
|
460
|
+
*
|
|
461
|
+
* @public
|
|
462
|
+
*/
|
|
463
|
+
export declare interface SyncSqliteDatabase {
|
|
464
|
+
/** Execute raw SQL without returning results */
|
|
465
|
+
exec(sql: string): void;
|
|
466
|
+
/** Prepare a statement for execution */
|
|
467
|
+
prepare(sql: string): {
|
|
468
|
+
all(...params: unknown[]): unknown[];
|
|
469
|
+
iterate(...params: unknown[]): IterableIterator<unknown>;
|
|
470
|
+
run(...params: unknown[]): unknown;
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
228
474
|
/* Excluded from this release type: TLConnectRequest */
|
|
229
475
|
|
|
230
476
|
/**
|
|
@@ -453,35 +699,12 @@ export declare class TLRemoteSyncError extends Error {
|
|
|
453
699
|
* @public
|
|
454
700
|
*/
|
|
455
701
|
export declare class TLSocketRoom<R extends UnknownRecord = UnknownRecord, SessionMeta = void> {
|
|
456
|
-
readonly opts:
|
|
457
|
-
/* Excluded from this release type: onPresenceChange */
|
|
458
|
-
clientTimeout?: number;
|
|
459
|
-
initialSnapshot?: RoomSnapshot | TLStoreSnapshot;
|
|
460
|
-
log?: TLSyncLog;
|
|
461
|
-
onAfterReceiveMessage?: (args: {
|
|
462
|
-
/* Excluded from this release type: message */
|
|
463
|
-
meta: SessionMeta;
|
|
464
|
-
sessionId: string;
|
|
465
|
-
stringified: string;
|
|
466
|
-
}) => void;
|
|
467
|
-
onBeforeSendMessage?: (args: {
|
|
468
|
-
/* Excluded from this release type: message */
|
|
469
|
-
meta: SessionMeta;
|
|
470
|
-
sessionId: string;
|
|
471
|
-
stringified: string;
|
|
472
|
-
}) => void;
|
|
473
|
-
onDataChange?(): void;
|
|
474
|
-
onSessionRemoved?: (room: TLSocketRoom<R, SessionMeta>, args: {
|
|
475
|
-
meta: SessionMeta;
|
|
476
|
-
numSessionsRemaining: number;
|
|
477
|
-
sessionId: string;
|
|
478
|
-
}) => void;
|
|
479
|
-
schema?: StoreSchema<R, any>;
|
|
480
|
-
};
|
|
702
|
+
readonly opts: TLSocketRoomOptions<R, SessionMeta>;
|
|
481
703
|
private room;
|
|
482
704
|
private readonly sessions;
|
|
483
705
|
readonly log?: TLSyncLog;
|
|
484
|
-
|
|
706
|
+
storage: TLSyncStorage<R>;
|
|
707
|
+
private disposables;
|
|
485
708
|
/**
|
|
486
709
|
* Creates a new TLSocketRoom instance for managing collaborative document synchronization.
|
|
487
710
|
*
|
|
@@ -496,31 +719,7 @@ export declare class TLSocketRoom<R extends UnknownRecord = UnknownRecord, Sessi
|
|
|
496
719
|
* - onDataChange - Called when document data changes
|
|
497
720
|
* - onPresenceChange - Called when presence data changes
|
|
498
721
|
*/
|
|
499
|
-
constructor(opts:
|
|
500
|
-
/* Excluded from this release type: onPresenceChange */
|
|
501
|
-
clientTimeout?: number;
|
|
502
|
-
initialSnapshot?: RoomSnapshot | TLStoreSnapshot;
|
|
503
|
-
log?: TLSyncLog;
|
|
504
|
-
onAfterReceiveMessage?: (args: {
|
|
505
|
-
/* Excluded from this release type: message */
|
|
506
|
-
meta: SessionMeta;
|
|
507
|
-
sessionId: string;
|
|
508
|
-
stringified: string;
|
|
509
|
-
}) => void;
|
|
510
|
-
onBeforeSendMessage?: (args: {
|
|
511
|
-
/* Excluded from this release type: message */
|
|
512
|
-
meta: SessionMeta;
|
|
513
|
-
sessionId: string;
|
|
514
|
-
stringified: string;
|
|
515
|
-
}) => void;
|
|
516
|
-
onDataChange?(): void;
|
|
517
|
-
onSessionRemoved?: (room: TLSocketRoom<R, SessionMeta>, args: {
|
|
518
|
-
meta: SessionMeta;
|
|
519
|
-
numSessionsRemaining: number;
|
|
520
|
-
sessionId: string;
|
|
521
|
-
}) => void;
|
|
522
|
-
schema?: StoreSchema<R, any>;
|
|
523
|
-
});
|
|
722
|
+
constructor(opts: TLSocketRoomOptions<R, SessionMeta>);
|
|
524
723
|
/**
|
|
525
724
|
* Returns the number of active sessions.
|
|
526
725
|
* Note that this is not the same as the number of connected sockets!
|
|
@@ -658,7 +857,7 @@ export declare class TLSocketRoom<R extends UnknownRecord = UnknownRecord, Sessi
|
|
|
658
857
|
* }
|
|
659
858
|
* ```
|
|
660
859
|
*/
|
|
661
|
-
getRecord(id: string): R
|
|
860
|
+
getRecord(id: string): R;
|
|
662
861
|
/**
|
|
663
862
|
* Returns information about all active sessions in the room. Each session
|
|
664
863
|
* represents a connected client with their current connection status and metadata.
|
|
@@ -694,6 +893,7 @@ export declare class TLSocketRoom<R extends UnknownRecord = UnknownRecord, Sessi
|
|
|
694
893
|
* to restore the room state later or revert to a previous version.
|
|
695
894
|
*
|
|
696
895
|
* @returns Complete room snapshot including documents, clock values, and tombstones
|
|
896
|
+
* @deprecated if you need to do this use
|
|
697
897
|
*
|
|
698
898
|
* @example
|
|
699
899
|
* ```ts
|
|
@@ -708,7 +908,6 @@ export declare class TLSocketRoom<R extends UnknownRecord = UnknownRecord, Sessi
|
|
|
708
908
|
*/
|
|
709
909
|
getCurrentSnapshot(): RoomSnapshot;
|
|
710
910
|
/* Excluded from this release type: getPresenceRecords */
|
|
711
|
-
/* Excluded from this release type: getCurrentSerializedSnapshot */
|
|
712
911
|
/**
|
|
713
912
|
* Loads a document snapshot, completely replacing the current room state.
|
|
714
913
|
* This will disconnect all current clients and update the document to match
|
|
@@ -770,6 +969,7 @@ export declare class TLSocketRoom<R extends UnknownRecord = UnknownRecord, Sessi
|
|
|
770
969
|
* }
|
|
771
970
|
* })
|
|
772
971
|
* ```
|
|
972
|
+
* @deprecated use the storage.transaction method instead
|
|
773
973
|
*/
|
|
774
974
|
updateStore(updater: (store: RoomStoreMethods<R>) => Promise<void> | void): Promise<void>;
|
|
775
975
|
/**
|
|
@@ -859,6 +1059,43 @@ export declare class TLSocketRoom<R extends UnknownRecord = UnknownRecord, Sessi
|
|
|
859
1059
|
isClosed(): boolean;
|
|
860
1060
|
}
|
|
861
1061
|
|
|
1062
|
+
/**
|
|
1063
|
+
* Base options for TLSocketRoom.
|
|
1064
|
+
* @public
|
|
1065
|
+
*/
|
|
1066
|
+
export declare interface TLSocketRoomOptions<R extends UnknownRecord, SessionMeta> {
|
|
1067
|
+
storage?: TLSyncStorage<R>;
|
|
1068
|
+
/**
|
|
1069
|
+
* @deprecated use the storage option instead
|
|
1070
|
+
*/
|
|
1071
|
+
initialSnapshot?: RoomSnapshot | TLStoreSnapshot;
|
|
1072
|
+
/**
|
|
1073
|
+
* @deprecated use the storage option with an onChange callback instead
|
|
1074
|
+
*/
|
|
1075
|
+
onDataChange?(): void;
|
|
1076
|
+
schema?: StoreSchema<R, any>;
|
|
1077
|
+
clientTimeout?: number;
|
|
1078
|
+
log?: TLSyncLog;
|
|
1079
|
+
onSessionRemoved?: (room: TLSocketRoom<R, SessionMeta>, args: {
|
|
1080
|
+
meta: SessionMeta;
|
|
1081
|
+
numSessionsRemaining: number;
|
|
1082
|
+
sessionId: string;
|
|
1083
|
+
}) => void;
|
|
1084
|
+
onBeforeSendMessage?: (args: {
|
|
1085
|
+
/* Excluded from this release type: message */
|
|
1086
|
+
meta: SessionMeta;
|
|
1087
|
+
sessionId: string;
|
|
1088
|
+
stringified: string;
|
|
1089
|
+
}) => void;
|
|
1090
|
+
onAfterReceiveMessage?: (args: {
|
|
1091
|
+
/* Excluded from this release type: message */
|
|
1092
|
+
meta: SessionMeta;
|
|
1093
|
+
sessionId: string;
|
|
1094
|
+
stringified: string;
|
|
1095
|
+
}) => void;
|
|
1096
|
+
/* Excluded from this release type: onPresenceChange */
|
|
1097
|
+
}
|
|
1098
|
+
|
|
862
1099
|
/* Excluded from this release type: TLSocketServerSentDataEvent */
|
|
863
1100
|
|
|
864
1101
|
/* Excluded from this release type: TLSocketServerSentEvent */
|
|
@@ -881,6 +1118,26 @@ export declare type TLSocketStatusChangeEvent = {
|
|
|
881
1118
|
|
|
882
1119
|
/* Excluded from this release type: TLSocketStatusListener */
|
|
883
1120
|
|
|
1121
|
+
/**
|
|
1122
|
+
* Valid input value types for SQLite query parameters.
|
|
1123
|
+
* These are the types that can be passed as bindings to prepared statements.
|
|
1124
|
+
* @public
|
|
1125
|
+
*/
|
|
1126
|
+
export declare type TLSqliteInputValue = bigint | null | number | string | Uint8Array;
|
|
1127
|
+
|
|
1128
|
+
/**
|
|
1129
|
+
* Possible output value types returned from SQLite queries.
|
|
1130
|
+
* Includes all input types plus Uint8Array for BLOB columns.
|
|
1131
|
+
* @public
|
|
1132
|
+
*/
|
|
1133
|
+
export declare type TLSqliteOutputValue = bigint | null | number | string | Uint8Array;
|
|
1134
|
+
|
|
1135
|
+
/**
|
|
1136
|
+
* A row returned from a SQLite query, mapping column names to their values.
|
|
1137
|
+
* @public
|
|
1138
|
+
*/
|
|
1139
|
+
export declare type TLSqliteRow = Record<string, TLSqliteOutputValue>;
|
|
1140
|
+
|
|
884
1141
|
/**
|
|
885
1142
|
* Main client-side synchronization engine for collaborative tldraw applications.
|
|
886
1143
|
*
|
|
@@ -1144,6 +1401,15 @@ export declare const TLSyncErrorCloseEventReason: {
|
|
|
1144
1401
|
*/
|
|
1145
1402
|
export declare type TLSyncErrorCloseEventReason = (typeof TLSyncErrorCloseEventReason)[keyof typeof TLSyncErrorCloseEventReason];
|
|
1146
1403
|
|
|
1404
|
+
/**
|
|
1405
|
+
* Respresents a diff of puts and deletes.
|
|
1406
|
+
* @public
|
|
1407
|
+
*/
|
|
1408
|
+
export declare interface TLSyncForwardDiff<R extends UnknownRecord> {
|
|
1409
|
+
puts: Record<string, [before: R, after: R] | R>;
|
|
1410
|
+
deletes: string[];
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1147
1413
|
/**
|
|
1148
1414
|
* Logging interface for TLSocketRoom operations. Provides optional methods
|
|
1149
1415
|
* for warning and error logging during synchronization operations.
|
|
@@ -1175,6 +1441,165 @@ export declare interface TLSyncLog {
|
|
|
1175
1441
|
|
|
1176
1442
|
/* Excluded from this release type: TLSyncRoom */
|
|
1177
1443
|
|
|
1444
|
+
/**
|
|
1445
|
+
* A prepared statement that can be executed multiple times with different bindings.
|
|
1446
|
+
* @public
|
|
1447
|
+
*/
|
|
1448
|
+
export declare interface TLSyncSqliteStatement<TResult extends TLSqliteRow | void, TParams extends TLSqliteInputValue[] = []> {
|
|
1449
|
+
/** Execute the statement and iterate over results one at a time */
|
|
1450
|
+
iterate(...bindings: TParams): IterableIterator<TResult>;
|
|
1451
|
+
/** Execute the statement and return all results as an array */
|
|
1452
|
+
all(...bindings: TParams): TResult[];
|
|
1453
|
+
/** Execute the statement without returning results (for DML) */
|
|
1454
|
+
run(...bindings: TParams): void;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
/**
|
|
1458
|
+
* Interface for SQLite storage with prepare, exec and transaction capabilities.
|
|
1459
|
+
* @public
|
|
1460
|
+
*/
|
|
1461
|
+
export declare interface TLSyncSqliteWrapper {
|
|
1462
|
+
/** Optional configuration for table names. If not provided, defaults are used. */
|
|
1463
|
+
readonly config?: TLSyncSqliteWrapperConfig;
|
|
1464
|
+
/** Prepare a SQL statement for execution */
|
|
1465
|
+
prepare<TResult extends TLSqliteRow | void, TParams extends TLSqliteInputValue[] = []>(sql: string): TLSyncSqliteStatement<TResult, TParams>;
|
|
1466
|
+
/** Execute raw SQL (for DDL, multi-statement scripts) */
|
|
1467
|
+
exec(sql: string): void;
|
|
1468
|
+
/** Execute a callback within a transaction */
|
|
1469
|
+
transaction<T>(callback: () => T): T;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
/**
|
|
1473
|
+
* Configuration for SQLiteSyncStorage.
|
|
1474
|
+
* @public
|
|
1475
|
+
*/
|
|
1476
|
+
export declare interface TLSyncSqliteWrapperConfig {
|
|
1477
|
+
/** Prefix for all table names (default: ''). E.g. 'sync_' creates tables 'sync_documents', 'sync_tombstones', 'sync_metadata' */
|
|
1478
|
+
tablePrefix?: string;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
/**
|
|
1482
|
+
* Pluggable synchronous transactional storage layer for TLSyncRoom.
|
|
1483
|
+
* Provides methods for managing documents, tombstones, and clocks within transactions.
|
|
1484
|
+
*
|
|
1485
|
+
* @public
|
|
1486
|
+
*/
|
|
1487
|
+
export declare interface TLSyncStorage<R extends UnknownRecord> {
|
|
1488
|
+
transaction<T>(callback: TLSyncStorageTransactionCallback<R, T>, opts?: TLSyncStorageTransactionOptions): TLSyncStorageTransactionResult<T, R>;
|
|
1489
|
+
getClock(): number;
|
|
1490
|
+
onChange(callback: (arg: TLSyncStorageOnChangeCallbackProps) => unknown): () => void;
|
|
1491
|
+
getSnapshot?(): RoomSnapshot;
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
/**
|
|
1495
|
+
* Result returned from getChangesSince, containing all changes since a given clock time.
|
|
1496
|
+
* @public
|
|
1497
|
+
*/
|
|
1498
|
+
export declare interface TLSyncStorageGetChangesSinceResult<R extends UnknownRecord> {
|
|
1499
|
+
/**
|
|
1500
|
+
* The changes as a TLSyncForwardDiff.
|
|
1501
|
+
*/
|
|
1502
|
+
diff: TLSyncForwardDiff<R>;
|
|
1503
|
+
/**
|
|
1504
|
+
* If true, the client should wipe all local data and replace with the server's state.
|
|
1505
|
+
* This happens when the client's clock is too old and we've lost tombstone history.
|
|
1506
|
+
*/
|
|
1507
|
+
wipeAll: boolean;
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
/**
|
|
1511
|
+
* Properties passed to the onChange callback.
|
|
1512
|
+
* @public
|
|
1513
|
+
*/
|
|
1514
|
+
export declare interface TLSyncStorageOnChangeCallbackProps {
|
|
1515
|
+
/**
|
|
1516
|
+
* The ID of the transaction that caused the change.
|
|
1517
|
+
* This is useful for ignoring certain changes in onChange callbacks.
|
|
1518
|
+
*/
|
|
1519
|
+
id?: string;
|
|
1520
|
+
documentClock: number;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
/**
|
|
1524
|
+
* Transaction interface for storage operations. Provides methods to read and modify
|
|
1525
|
+
* documents, tombstones, and metadata within a transaction.
|
|
1526
|
+
*
|
|
1527
|
+
* @public
|
|
1528
|
+
*/
|
|
1529
|
+
export declare interface TLSyncStorageTransaction<R extends UnknownRecord> extends SynchronousStorage<R> {
|
|
1530
|
+
/**
|
|
1531
|
+
* Get the current clock value.
|
|
1532
|
+
* If the clock has incremented during the transaction,
|
|
1533
|
+
* the incremented value will be returned.
|
|
1534
|
+
*
|
|
1535
|
+
* @returns The current clock value
|
|
1536
|
+
*/
|
|
1537
|
+
getClock(): number;
|
|
1538
|
+
/**
|
|
1539
|
+
* Get all changes (document updates and deletions) since a given clock time.
|
|
1540
|
+
* This is the main method for calculating diffs for client sync.
|
|
1541
|
+
*
|
|
1542
|
+
* @param sinceClock - The clock time to get changes since
|
|
1543
|
+
* @returns Changes since the specified clock time
|
|
1544
|
+
*/
|
|
1545
|
+
getChangesSince(sinceClock: number): TLSyncStorageGetChangesSinceResult<R> | undefined;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
/**
|
|
1549
|
+
* Callback type for a transaction.
|
|
1550
|
+
* The conditional return type ensures that the callback is synchronous.
|
|
1551
|
+
* @public
|
|
1552
|
+
*/
|
|
1553
|
+
export declare type TLSyncStorageTransactionCallback<R extends UnknownRecord, T> = (txn: TLSyncStorageTransaction<R>) => T extends Promise<any> ? {
|
|
1554
|
+
__error: 'Transaction callbacks cannot be async. Use synchronous operations only.';
|
|
1555
|
+
} : T;
|
|
1556
|
+
|
|
1557
|
+
/**
|
|
1558
|
+
* Options for a transaction.
|
|
1559
|
+
* @public
|
|
1560
|
+
*/
|
|
1561
|
+
export declare interface TLSyncStorageTransactionOptions {
|
|
1562
|
+
/**
|
|
1563
|
+
* Use this if you need to identify the transaction for logging or debugging purposes
|
|
1564
|
+
* or for ignoring certain changes in onChange callbacks
|
|
1565
|
+
*/
|
|
1566
|
+
id?: string;
|
|
1567
|
+
/**
|
|
1568
|
+
* Controls when the storage layer should emit the actual changes that occurred during the transaction.
|
|
1569
|
+
*
|
|
1570
|
+
* - `'always'` - Always emit the changes, regardless of whether they were applied verbatim
|
|
1571
|
+
* - `'when-different'` - Only emit changes if the storage layer modified/embellished the records
|
|
1572
|
+
* (e.g., added server timestamps, normalized data, etc.)
|
|
1573
|
+
*
|
|
1574
|
+
* When changes are emitted, they will be available in the `changes` field of the transaction result.
|
|
1575
|
+
* This is useful when the storage layer may transform records and the caller needs to know
|
|
1576
|
+
* what actually changed rather than what was requested.
|
|
1577
|
+
*/
|
|
1578
|
+
emitChanges?: 'always' | 'when-different';
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
/**
|
|
1582
|
+
* Result returned from a storage transaction.
|
|
1583
|
+
* @public
|
|
1584
|
+
*/
|
|
1585
|
+
export declare interface TLSyncStorageTransactionResult<T, R extends UnknownRecord = UnknownRecord> {
|
|
1586
|
+
documentClock: number;
|
|
1587
|
+
didChange: boolean;
|
|
1588
|
+
result: T;
|
|
1589
|
+
/**
|
|
1590
|
+
* The actual changes that occurred during the transaction, if requested via `emitChanges` option.
|
|
1591
|
+
* This is a RecordsDiff where:
|
|
1592
|
+
* - `added` contains records that were put (we don't have "from" state for emitted changes)
|
|
1593
|
+
* - `removed` contains records that were deleted (with placeholder values since we only have IDs)
|
|
1594
|
+
* - `updated` is empty (emitted changes don't track before/after pairs)
|
|
1595
|
+
*
|
|
1596
|
+
* Only populated when:
|
|
1597
|
+
* - `emitChanges: 'always'` was specified, or
|
|
1598
|
+
* - `emitChanges: 'when-different'` was specified and the storage layer modified records
|
|
1599
|
+
*/
|
|
1600
|
+
changes?: TLSyncForwardDiff<R>;
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1178
1603
|
/* Excluded from this release type: ValueOp */
|
|
1179
1604
|
|
|
1180
1605
|
/* Excluded from this release type: ValueOpType */
|