@tldraw/sync-core 5.3.0-internal.fba91ed55f6c → 5.3.0-next.91d2a20b898c

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 (50) hide show
  1. package/dist-cjs/index.d.ts +3 -154
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/InMemorySyncStorage.js +20 -55
  5. package/dist-cjs/lib/InMemorySyncStorage.js.map +2 -2
  6. package/dist-cjs/lib/RoomSession.js.map +1 -1
  7. package/dist-cjs/lib/SQLiteSyncStorage.js +52 -115
  8. package/dist-cjs/lib/SQLiteSyncStorage.js.map +2 -2
  9. package/dist-cjs/lib/TLSocketRoom.js +2 -27
  10. package/dist-cjs/lib/TLSocketRoom.js.map +2 -2
  11. package/dist-cjs/lib/TLSyncClient.js +1 -6
  12. package/dist-cjs/lib/TLSyncClient.js.map +2 -2
  13. package/dist-cjs/lib/TLSyncRoom.js +10 -160
  14. package/dist-cjs/lib/TLSyncRoom.js.map +3 -3
  15. package/dist-cjs/lib/TLSyncStorage.js.map +2 -2
  16. package/dist-cjs/lib/protocol.js.map +2 -2
  17. package/dist-esm/index.d.mts +3 -154
  18. package/dist-esm/index.mjs +1 -1
  19. package/dist-esm/index.mjs.map +2 -2
  20. package/dist-esm/lib/InMemorySyncStorage.mjs +20 -55
  21. package/dist-esm/lib/InMemorySyncStorage.mjs.map +2 -2
  22. package/dist-esm/lib/RoomSession.mjs.map +1 -1
  23. package/dist-esm/lib/SQLiteSyncStorage.mjs +52 -115
  24. package/dist-esm/lib/SQLiteSyncStorage.mjs.map +2 -2
  25. package/dist-esm/lib/TLSocketRoom.mjs +2 -27
  26. package/dist-esm/lib/TLSocketRoom.mjs.map +2 -2
  27. package/dist-esm/lib/TLSyncClient.mjs +1 -6
  28. package/dist-esm/lib/TLSyncClient.mjs.map +2 -2
  29. package/dist-esm/lib/TLSyncRoom.mjs +10 -160
  30. package/dist-esm/lib/TLSyncRoom.mjs.map +3 -3
  31. package/dist-esm/lib/TLSyncStorage.mjs.map +2 -2
  32. package/dist-esm/lib/protocol.mjs.map +2 -2
  33. package/package.json +6 -6
  34. package/src/index.ts +0 -3
  35. package/src/lib/InMemorySyncStorage.ts +21 -74
  36. package/src/lib/RoomSession.ts +2 -7
  37. package/src/lib/SQLiteSyncStorage.test.ts +2 -29
  38. package/src/lib/SQLiteSyncStorage.ts +59 -158
  39. package/src/lib/TLSocketRoom.ts +3 -61
  40. package/src/lib/TLSyncClient.test.ts +2 -9
  41. package/src/lib/TLSyncClient.ts +3 -15
  42. package/src/lib/TLSyncRoom.ts +10 -294
  43. package/src/lib/TLSyncStorage.ts +0 -8
  44. package/src/lib/protocol.ts +0 -17
  45. package/src/test/TLSocketRoom.test.ts +2 -37
  46. package/src/test/TLSyncRoom.test.ts +0 -25
  47. package/src/test/TestServer.ts +4 -14
  48. package/src/test/storageContractSuite.ts +0 -79
  49. package/src/test/upgradeDowngrade.test.ts +2 -144
  50. package/src/test/objectStore.test.ts +0 -630
@@ -3,15 +3,14 @@ import { createTLSchema, TLInstancePresence, TLStoreSnapshot } from '@tldraw/tls
3
3
  import { getOwnProperty, hasOwnProperty, isEqual, structuredClone } from '@tldraw/utils'
4
4
  import { JsonChunkAssembler } from './chunk'
5
5
  import { DEFAULT_INITIAL_SNAPSHOT, InMemorySyncStorage } from './InMemorySyncStorage'
6
- import { TLObjectStoreAccess, TLSocketServerSentEvent } from './protocol'
6
+ import { TLSocketServerSentEvent } from './protocol'
7
7
  import { RoomSessionState } from './RoomSession'
8
8
  import { ServerSocketAdapter, WebSocketMinimal } from './ServerSocketAdapter'
9
9
  import { TLSyncErrorCloseEventReason } from './TLSyncClient'
10
- import { RoomSnapshot, TLRecordAuthorizers, TLSyncRoom } from './TLSyncRoom'
10
+ import { RoomSnapshot, TLSyncRoom } from './TLSyncRoom'
11
11
  import {
12
12
  convertStoreSnapshotToRoomSnapshot,
13
13
  loadSnapshotIntoStorage,
14
- TLSyncForwardDiff,
15
14
  TLSyncStorage,
16
15
  } from './TLSyncStorage'
17
16
 
@@ -72,11 +71,6 @@ export interface TLSyncLog {
72
71
  export interface SessionStateSnapshot {
73
72
  serializedSchema: SerializedSchema
74
73
  isReadonly: boolean
75
- /**
76
- * Write access for the record types listed in `objectTypes`. Optional so snapshots persisted
77
- * before this field existed resume cleanly (they fail closed to 'read').
78
- */
79
- objectAccess?: TLObjectStoreAccess
80
74
  presenceId: string | null
81
75
  presenceRecord: UnknownRecord | null
82
76
  requiresLegacyRejection: boolean
@@ -126,30 +120,6 @@ export interface TLSocketRoomOptions<R extends UnknownRecord, SessionMeta> {
126
120
  }) => void
127
121
  /** @internal */
128
122
  onPresenceChange?(): void
129
- /**
130
- * Called once after a client push commits, with the committed document diff. Use to react to
131
- * document changes as soon as they commit — e.g. project certain record types to an external
132
- * store. Best-effort: do not throw and do not block.
133
- *
134
- * Only fires for client pushes. Server-initiated changes — `updateStore`, `loadSnapshot`, or
135
- * writing to the storage directly — do not trigger it, so anything mirroring room state through
136
- * this callback must handle those paths itself.
137
- */
138
- // eslint-disable-next-line tldraw/method-signature-style
139
- onCommittedChanges?: (args: { diff: TLSyncForwardDiff<R>; documentClock: number }) => void
140
- /**
141
- * Record type names to serve through the object-store lane instead of the document lane.
142
- * Each must be a document-scoped type registered in the schema. Object-lane writes are gated
143
- * per session by `objectAccess` (see {@link TLSocketRoom.handleSocketConnect}) rather than
144
- * `isReadonly`, so e.g. a session can be allowed to comment without being allowed to edit.
145
- */
146
- objectTypes?: readonly string[]
147
- /**
148
- * Per-type authorizers for client record writes (create, update, delete): veto writes the
149
- * session isn't allowed to make, or rewrite the record on create — e.g. force a comment's
150
- * `authorId` to the signed-in user. See {@link TLRecordAuthorizers}.
151
- */
152
- authorizeRecord?: TLRecordAuthorizers<R, SessionMeta>
153
123
  /**
154
124
  * When set, the room will call {@link TLSocketRoom.getSessionSnapshot} after
155
125
  * no message activity for a session for 5s and pass the result to this callback.
@@ -260,8 +230,6 @@ export class TLSocketRoom<R extends UnknownRecord = UnknownRecord, SessionMeta =
260
230
  // eslint-disable-next-line @typescript-eslint/no-deprecated
261
231
  opts.initialSnapshot ?? DEFAULT_INITIAL_SNAPSHOT
262
232
  ),
263
- // keep the storage partition in step with the room's object lane
264
- objectTypes: opts.objectTypes,
265
233
  })
266
234
 
267
235
  // eslint-disable-next-line @typescript-eslint/no-deprecated
@@ -275,9 +243,6 @@ export class TLSocketRoom<R extends UnknownRecord = UnknownRecord, SessionMeta =
275
243
  }
276
244
  this.room = new TLSyncRoom<R, SessionMeta>({
277
245
  onPresenceChange: opts.onPresenceChange,
278
- onCommittedChanges: opts.onCommittedChanges,
279
- objectTypes: opts.objectTypes,
280
- authorizeRecord: opts.authorizeRecord,
281
246
  schema: opts.schema ?? (createTLSchema() as any),
282
247
  log: opts.log,
283
248
  storage,
@@ -318,9 +283,6 @@ export class TLSocketRoom<R extends UnknownRecord = UnknownRecord, SessionMeta =
318
283
  * - sessionId - Unique identifier for the client session (typically from browser tab)
319
284
  * - socket - WebSocket-like object for client communication
320
285
  * - isReadonly - Whether the client can modify the document (defaults to false)
321
- * - objectAccess - Write access for object-store lane record types (defaults to 'write').
322
- * Independent of isReadonly, so a session can be allowed to write objects (e.g. comments)
323
- * without being allowed to edit the document.
324
286
  * - meta - Additional session metadata (required if SessionMeta is not void)
325
287
  *
326
288
  * @example
@@ -348,10 +310,9 @@ export class TLSocketRoom<R extends UnknownRecord = UnknownRecord, SessionMeta =
348
310
  sessionId: string
349
311
  socket: WebSocketMinimal
350
312
  isReadonly?: boolean
351
- objectAccess?: TLObjectStoreAccess
352
313
  } & (SessionMeta extends void ? object : { meta: SessionMeta })
353
314
  ) {
354
- const { sessionId, socket, isReadonly = false, objectAccess = 'write' } = opts
315
+ const { sessionId, socket, isReadonly = false } = opts
355
316
  const handleSocketMessage = (event: MessageEvent) =>
356
317
  this.handleSocketMessage(sessionId, event.data)
357
318
  const handleSocketError = this.handleSocketError.bind(this, sessionId)
@@ -370,7 +331,6 @@ export class TLSocketRoom<R extends UnknownRecord = UnknownRecord, SessionMeta =
370
331
  this.room.handleNewSession({
371
332
  sessionId,
372
333
  isReadonly,
373
- objectAccess,
374
334
  socket: new ServerSocketAdapter({
375
335
  ws: socket,
376
336
  onBeforeSendMessage: this.opts.onBeforeSendMessage
@@ -580,9 +540,6 @@ export class TLSocketRoom<R extends UnknownRecord = UnknownRecord, SessionMeta =
580
540
  this.room.handleResumedSession({
581
541
  sessionId,
582
542
  isReadonly: snapshot.isReadonly,
583
- // snapshots persisted before this field existed fail closed — those sessions predate
584
- // the record types gated by objectAccess, so they have nothing to write anyway
585
- objectAccess: snapshot.objectAccess ?? 'read',
586
543
  serializedSchema: snapshot.serializedSchema,
587
544
  presenceId: snapshot.presenceId,
588
545
  presenceRecord: snapshot.presenceRecord,
@@ -638,7 +595,6 @@ export class TLSocketRoom<R extends UnknownRecord = UnknownRecord, SessionMeta =
638
595
  return {
639
596
  serializedSchema: session.serializedSchema,
640
597
  isReadonly: session.isReadonly,
641
- objectAccess: session.objectAccess,
642
598
  presenceId: session.presenceId,
643
599
  presenceRecord,
644
600
  requiresLegacyRejection: session.requiresLegacyRejection,
@@ -714,7 +670,6 @@ export class TLSocketRoom<R extends UnknownRecord = UnknownRecord, SessionMeta =
714
670
  sessionId: string
715
671
  isConnected: boolean
716
672
  isReadonly: boolean
717
- objectAccess: TLObjectStoreAccess
718
673
  meta: SessionMeta
719
674
  }> {
720
675
  return [...this.room.sessions.values()].map((session) => {
@@ -722,7 +677,6 @@ export class TLSocketRoom<R extends UnknownRecord = UnknownRecord, SessionMeta =
722
677
  sessionId: session.sessionId,
723
678
  isConnected: session.state === RoomSessionState.Connected,
724
679
  isReadonly: session.isReadonly,
725
- objectAccess: session.objectAccess,
726
680
  meta: session.meta,
727
681
  }
728
682
  })
@@ -754,18 +708,6 @@ export class TLSocketRoom<R extends UnknownRecord = UnknownRecord, SessionMeta =
754
708
  throw new Error('getCurrentSnapshot is not supported for this storage type')
755
709
  }
756
710
 
757
- /**
758
- * Returns a snapshot of the object-store lane (see `objectTypes`), for persisting
759
- * object-lane records separately from the document. Same entry shape as
760
- * {@link RoomSnapshot.documents}.
761
- */
762
- getCurrentObjectsSnapshot(): RoomSnapshot['documents'] {
763
- if (this.storage.getObjectsSnapshot) {
764
- return this.storage.getObjectsSnapshot()
765
- }
766
- throw new Error('getCurrentObjectsSnapshot is not supported for this storage type')
767
- }
768
-
769
711
  /**
770
712
  * Retrieves all presence records from the document store. Presence records
771
713
  * contain ephemeral user state like cursor positions and selections.
@@ -476,20 +476,13 @@ describe('TLSyncClient', () => {
476
476
  client = createClient()
477
477
  socket.mockServerMessage(createConnectMessage({ isReadonly: false }))
478
478
  expect(client.isConnectedToRoom).toBe(true)
479
- // objectAccess defaults to 'write' when the server doesn't send it
480
- expect(onAfterConnect).toHaveBeenCalledWith(client, {
481
- isReadonly: false,
482
- objectAccess: 'write',
483
- })
479
+ expect(onAfterConnect).toHaveBeenCalledWith(client, { isReadonly: false })
484
480
 
485
481
  // reconnect as readonly
486
482
  socket.mockConnectionStatus('offline')
487
483
  socket.mockConnectionStatus('online')
488
484
  socket.mockServerMessage(createConnectMessage({ isReadonly: true }))
489
- expect(onAfterConnect).toHaveBeenLastCalledWith(client, {
490
- isReadonly: true,
491
- objectAccess: 'write',
492
- })
485
+ expect(onAfterConnect).toHaveBeenLastCalledWith(client, { isReadonly: true })
493
486
  })
494
487
 
495
488
  it('[CL7] pushes the current presence state after connecting', () => {
@@ -24,7 +24,6 @@ import {
24
24
  } from './diff'
25
25
  import { interval } from './interval'
26
26
  import {
27
- TLObjectStoreAccess,
28
27
  TLPushRequest,
29
28
  TLSocketClientSentEvent,
30
29
  TLSocketServerSentDataEvent,
@@ -438,13 +437,8 @@ export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>
438
437
  * @param self - The TLSyncClient instance that connected
439
438
  * @param details - Connection details
440
439
  * - isReadonly - Whether the connection is in read-only mode
441
- * - objectAccess - Write access for object-store lane record types (defaults to 'write'
442
- * when the server doesn't send it, e.g. older servers or rooms with no object lane)
443
440
  */
444
- private readonly onAfterConnect?: (
445
- self: this,
446
- details: { isReadonly: boolean; objectAccess: TLObjectStoreAccess }
447
- ) => void
441
+ private readonly onAfterConnect?: (self: this, details: { isReadonly: boolean }) => void
448
442
 
449
443
  private readonly onCustomMessageReceived?: TLCustomMessageHandler
450
444
 
@@ -484,10 +478,7 @@ export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>
484
478
  onLoad(self: TLSyncClient<R, S>): void
485
479
  onSyncError(reason: string): void
486
480
  onCustomMessageReceived?: TLCustomMessageHandler
487
- onAfterConnect?(
488
- self: TLSyncClient<R, S>,
489
- details: { isReadonly: boolean; objectAccess: TLObjectStoreAccess }
490
- ): void
481
+ onAfterConnect?(self: TLSyncClient<R, S>, details: { isReadonly: boolean }): void
491
482
  didCancel?(): boolean
492
483
  }) {
493
484
  this.didCancel = config.didCancel
@@ -766,10 +757,7 @@ export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>
766
757
  // this.isConnectedToRoom = true
767
758
  // this.store.applyDiff(stashedChanges, false)
768
759
 
769
- this.onAfterConnect?.(this, {
770
- isReadonly: event.isReadonly,
771
- objectAccess: event.objectAccess ?? 'write',
772
- })
760
+ this.onAfterConnect?.(this, { isReadonly: event.isReadonly })
773
761
  const presence = this.presenceState?.get()
774
762
  if (presence) {
775
763
  this.pushPresence(presence)