@tldraw/sync-core 4.6.0-next.30b99cd52fc8 → 4.6.0-next.35cf541abcf9

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 (45) hide show
  1. package/dist-cjs/index.js +1 -1
  2. package/dist-cjs/lib/ClientWebSocketAdapter.js +2 -0
  3. package/dist-cjs/lib/ClientWebSocketAdapter.js.map +1 -1
  4. package/dist-cjs/lib/DurableObjectSqliteSyncWrapper.js +4 -0
  5. package/dist-cjs/lib/DurableObjectSqliteSyncWrapper.js.map +1 -1
  6. package/dist-cjs/lib/InMemorySyncStorage.js +1 -0
  7. package/dist-cjs/lib/InMemorySyncStorage.js.map +1 -1
  8. package/dist-cjs/lib/NodeSqliteWrapper.js +2 -0
  9. package/dist-cjs/lib/NodeSqliteWrapper.js.map +1 -1
  10. package/dist-cjs/lib/SQLiteSyncStorage.js +2 -0
  11. package/dist-cjs/lib/SQLiteSyncStorage.js.map +1 -1
  12. package/dist-cjs/lib/ServerSocketAdapter.js +1 -0
  13. package/dist-cjs/lib/ServerSocketAdapter.js.map +1 -1
  14. package/dist-cjs/lib/TLRemoteSyncError.js +1 -0
  15. package/dist-cjs/lib/TLRemoteSyncError.js.map +1 -1
  16. package/dist-cjs/lib/TLSocketRoom.js +3 -0
  17. package/dist-cjs/lib/TLSocketRoom.js.map +1 -1
  18. package/dist-cjs/lib/TLSyncClient.js +1 -0
  19. package/dist-cjs/lib/TLSyncClient.js.map +1 -1
  20. package/dist-cjs/lib/TLSyncRoom.js +7 -1
  21. package/dist-cjs/lib/TLSyncRoom.js.map +2 -2
  22. package/dist-esm/index.mjs +1 -1
  23. package/dist-esm/lib/ClientWebSocketAdapter.mjs +2 -0
  24. package/dist-esm/lib/ClientWebSocketAdapter.mjs.map +1 -1
  25. package/dist-esm/lib/DurableObjectSqliteSyncWrapper.mjs +4 -0
  26. package/dist-esm/lib/DurableObjectSqliteSyncWrapper.mjs.map +1 -1
  27. package/dist-esm/lib/InMemorySyncStorage.mjs +1 -0
  28. package/dist-esm/lib/InMemorySyncStorage.mjs.map +1 -1
  29. package/dist-esm/lib/NodeSqliteWrapper.mjs +2 -0
  30. package/dist-esm/lib/NodeSqliteWrapper.mjs.map +1 -1
  31. package/dist-esm/lib/SQLiteSyncStorage.mjs +2 -0
  32. package/dist-esm/lib/SQLiteSyncStorage.mjs.map +1 -1
  33. package/dist-esm/lib/ServerSocketAdapter.mjs +1 -0
  34. package/dist-esm/lib/ServerSocketAdapter.mjs.map +1 -1
  35. package/dist-esm/lib/TLRemoteSyncError.mjs +1 -0
  36. package/dist-esm/lib/TLRemoteSyncError.mjs.map +1 -1
  37. package/dist-esm/lib/TLSocketRoom.mjs +3 -0
  38. package/dist-esm/lib/TLSocketRoom.mjs.map +1 -1
  39. package/dist-esm/lib/TLSyncClient.mjs +1 -0
  40. package/dist-esm/lib/TLSyncClient.mjs.map +1 -1
  41. package/dist-esm/lib/TLSyncRoom.mjs +7 -1
  42. package/dist-esm/lib/TLSyncRoom.mjs.map +2 -2
  43. package/package.json +6 -6
  44. package/src/lib/TLSyncRoom.ts +9 -1
  45. package/src/test/syncFuzz.test.ts +4 -0
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/DurableObjectSqliteSyncWrapper.ts"],
4
4
  "sourcesContent": ["import {\n\ttype TLSqliteInputValue,\n\ttype TLSqliteRow,\n\ttype TLSyncSqliteStatement,\n\ttype TLSyncSqliteWrapper,\n\ttype TLSyncSqliteWrapperConfig,\n} from './SQLiteSyncStorage'\n\n/**\n * Mimics a prepared statement interface for Durable Objects SQLite.\n * Rather than actually preparing the statement, it just stores the SQL and\n * executes it fresh each time. This is still fast because DO SQLite maintains\n * an internal LRU cache of prepared statements.\n */\nclass DurableObjectStatement<\n\tTResult extends TLSqliteRow | void,\n\tTParams extends TLSqliteInputValue[],\n> implements TLSyncSqliteStatement<TResult, TParams> {\n\tconstructor(\n\t\tprivate sql: {\n\t\t\texec(sql: string, ...bindings: unknown[]): Iterable<any> & { toArray(): any[] }\n\t\t},\n\t\tprivate query: string\n\t) {}\n\n\titerate(...bindings: TParams): IterableIterator<TResult> {\n\t\tconst result = this.sql.exec(this.query, ...bindings)\n\t\treturn result[Symbol.iterator]() as IterableIterator<TResult>\n\t}\n\n\tall(...bindings: TParams): TResult[] {\n\t\treturn this.sql.exec(this.query, ...bindings).toArray()\n\t}\n\n\trun(...bindings: TParams): void {\n\t\tthis.sql.exec(this.query, ...bindings)\n\t}\n}\n\n/**\n * A wrapper around Cloudflare Durable Object's SqlStorage that implements TLSyncSqliteWrapper.\n *\n * Use this wrapper with SQLiteSyncStorage to persist tldraw sync state using\n * Cloudflare Durable Object's built-in SQLite storage. This provides automatic\n * persistence that survives Durable Object hibernation and restarts.\n *\n * @example\n * ```ts\n * import { SQLiteSyncStorage, DurableObjectSqliteSyncWrapper } from '@tldraw/sync-core'\n *\n * // In your Durable Object class:\n * class MyDurableObject extends DurableObject {\n * private storage: SQLiteSyncStorage\n *\n * constructor(ctx: DurableObjectState, env: Env) {\n * super(ctx, env)\n * const sql = new DurableObjectSqliteSyncWrapper(ctx.storage)\n * this.storage = new SQLiteSyncStorage({ sql })\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // With table prefix to avoid conflicts with other tables\n * const sql = new DurableObjectSqliteSyncWrapper(this.ctx.storage, { tablePrefix: 'tldraw_' })\n * // Creates tables: tldraw_documents, tldraw_tombstones, tldraw_metadata\n * ```\n *\n * @public\n */\nexport class DurableObjectSqliteSyncWrapper implements TLSyncSqliteWrapper {\n\tconstructor(\n\t\tprivate storage: {\n\t\t\tsql: { exec(sql: string, ...bindings: unknown[]): Iterable<any> & { toArray(): any[] } }\n\t\t\ttransactionSync(callback: () => any): any\n\t\t},\n\t\tpublic config?: TLSyncSqliteWrapperConfig\n\t) {}\n\n\texec(sql: string): void {\n\t\tthis.storage.sql.exec(sql)\n\t}\n\n\tprepare<TResult extends TLSqliteRow | void = void, TParams extends TLSqliteInputValue[] = []>(\n\t\tsql: string\n\t): TLSyncSqliteStatement<TResult, TParams> {\n\t\treturn new DurableObjectStatement<TResult, TParams>(this.storage.sql, sql)\n\t}\n\n\ttransaction<T>(callback: () => T): T {\n\t\treturn this.storage.transactionSync(callback)\n\t}\n}\n"],
5
- "mappings": "AAcA,MAAM,uBAG+C;AAAA,EACpD,YACS,KAGA,OACP;AAJO;AAGA;AAAA,EACN;AAAA,EAEH,WAAW,UAA8C;AACxD,UAAM,SAAS,KAAK,IAAI,KAAK,KAAK,OAAO,GAAG,QAAQ;AACpD,WAAO,OAAO,OAAO,QAAQ,EAAE;AAAA,EAChC;AAAA,EAEA,OAAO,UAA8B;AACpC,WAAO,KAAK,IAAI,KAAK,KAAK,OAAO,GAAG,QAAQ,EAAE,QAAQ;AAAA,EACvD;AAAA,EAEA,OAAO,UAAyB;AAC/B,SAAK,IAAI,KAAK,KAAK,OAAO,GAAG,QAAQ;AAAA,EACtC;AACD;AAkCO,MAAM,+BAA8D;AAAA,EAC1E,YACS,SAID,QACN;AALO;AAID;AAAA,EACL;AAAA,EAEH,KAAK,KAAmB;AACvB,SAAK,QAAQ,IAAI,KAAK,GAAG;AAAA,EAC1B;AAAA,EAEA,QACC,KAC0C;AAC1C,WAAO,IAAI,uBAAyC,KAAK,QAAQ,KAAK,GAAG;AAAA,EAC1E;AAAA,EAEA,YAAe,UAAsB;AACpC,WAAO,KAAK,QAAQ,gBAAgB,QAAQ;AAAA,EAC7C;AACD;",
5
+ "mappings": "AAcA,MAAM,uBAG+C;AAAA,EACpD,YACS,KAGA,OACP;AAJO;AAGA;AAAA,EACN;AAAA,EAJM;AAAA,EAGA;AAAA,EAGT,WAAW,UAA8C;AACxD,UAAM,SAAS,KAAK,IAAI,KAAK,KAAK,OAAO,GAAG,QAAQ;AACpD,WAAO,OAAO,OAAO,QAAQ,EAAE;AAAA,EAChC;AAAA,EAEA,OAAO,UAA8B;AACpC,WAAO,KAAK,IAAI,KAAK,KAAK,OAAO,GAAG,QAAQ,EAAE,QAAQ;AAAA,EACvD;AAAA,EAEA,OAAO,UAAyB;AAC/B,SAAK,IAAI,KAAK,KAAK,OAAO,GAAG,QAAQ;AAAA,EACtC;AACD;AAkCO,MAAM,+BAA8D;AAAA,EAC1E,YACS,SAID,QACN;AALO;AAID;AAAA,EACL;AAAA,EALM;AAAA,EAID;AAAA,EAGR,KAAK,KAAmB;AACvB,SAAK,QAAQ,IAAI,KAAK,GAAG;AAAA,EAC1B;AAAA,EAEA,QACC,KAC0C;AAC1C,WAAO,IAAI,uBAAyC,KAAK,QAAQ,KAAK,GAAG;AAAA,EAC1E;AAAA,EAEA,YAAe,UAAsB;AACpC,WAAO,KAAK,QAAQ,gBAAgB,QAAQ;AAAA,EAC7C;AACD;",
6
6
  "names": []
7
7
  }
@@ -167,6 +167,7 @@ class InMemorySyncStorageTransaction {
167
167
  this.storage = storage;
168
168
  this._clock = this.storage.documentClock.get();
169
169
  }
170
+ storage;
170
171
  _clock;
171
172
  _closed = false;
172
173
  /** @internal */
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/InMemorySyncStorage.ts"],
4
4
  "sourcesContent": ["import { atom, Atom, transaction } from '@tldraw/state'\nimport { AtomMap, devFreeze, SerializedSchema, UnknownRecord } from '@tldraw/store'\nimport {\n\tcreateTLSchema,\n\tDocumentRecordType,\n\tPageRecordType,\n\tTLDOCUMENT_ID,\n\tTLPageId,\n} from '@tldraw/tlschema'\nimport { assert, IndexKey, objectMapEntries, throttle } from '@tldraw/utils'\nimport { MicrotaskNotifier } from './MicrotaskNotifier'\nimport { RoomSnapshot } from './TLSyncRoom'\nimport {\n\tTLSyncForwardDiff,\n\tTLSyncStorage,\n\tTLSyncStorageGetChangesSinceResult,\n\tTLSyncStorageOnChangeCallbackProps,\n\tTLSyncStorageTransaction,\n\tTLSyncStorageTransactionCallback,\n\tTLSyncStorageTransactionOptions,\n\tTLSyncStorageTransactionResult,\n} from './TLSyncStorage'\n\n/** @internal */\nexport const TOMBSTONE_PRUNE_BUFFER_SIZE = 1000\n/** @internal */\nexport const MAX_TOMBSTONES = 5000\n\n/**\n * Result of computing which tombstones to prune.\n * @internal\n */\nexport interface TombstonePruneResult {\n\t/** The new value for tombstoneHistoryStartsAtClock */\n\tnewTombstoneHistoryStartsAtClock: number\n\t/** IDs of tombstones to delete */\n\tidsToDelete: string[]\n}\n\n/**\n * Computes which tombstones should be pruned, avoiding partial history for any clock value.\n * Returns null if no pruning is needed (tombstone count <= maxTombstones).\n *\n * @param tombstones - Array of tombstones sorted by clock ascending (oldest first)\n * @param documentClock - Current document clock (used as fallback if all tombstones are deleted)\n * @param maxTombstones - Maximum number of tombstones to keep (default: MAX_TOMBSTONES)\n * @param pruneBufferSize - Extra tombstones to prune beyond the threshold (default: TOMBSTONE_PRUNE_BUFFER_SIZE)\n * @returns Pruning result or null if no pruning needed\n *\n * @internal\n */\nexport function computeTombstonePruning({\n\ttombstones,\n\tdocumentClock,\n\tmaxTombstones = MAX_TOMBSTONES,\n\tpruneBufferSize = TOMBSTONE_PRUNE_BUFFER_SIZE,\n}: {\n\ttombstones: Array<{ id: string; clock: number }>\n\tdocumentClock: number\n\tmaxTombstones?: number\n\tpruneBufferSize?: number\n}): TombstonePruneResult | null {\n\tif (tombstones.length <= maxTombstones) {\n\t\treturn null\n\t}\n\n\t// Determine how many to delete, avoiding partial history for a clock value\n\tlet cutoff = pruneBufferSize + tombstones.length - maxTombstones\n\twhile (\n\t\tcutoff < tombstones.length &&\n\t\ttombstones[cutoff - 1]?.clock === tombstones[cutoff]?.clock\n\t) {\n\t\tcutoff++\n\t}\n\n\t// Set history start to the oldest remaining tombstone's clock\n\t// (or documentClock if we're deleting everything)\n\tconst oldestRemaining = tombstones[cutoff]\n\tconst newTombstoneHistoryStartsAtClock = oldestRemaining?.clock ?? documentClock\n\n\t// Collect the oldest tombstones to delete (first cutoff entries)\n\tconst idsToDelete = tombstones.slice(0, cutoff).map((t) => t.id)\n\n\treturn { newTombstoneHistoryStartsAtClock, idsToDelete }\n}\n\n/**\n * Default initial snapshot for a new room.\n * @public\n */\nexport const DEFAULT_INITIAL_SNAPSHOT = {\n\tdocumentClock: 0,\n\ttombstoneHistoryStartsAtClock: 0,\n\tschema: createTLSchema().serialize(),\n\tdocuments: [\n\t\t{\n\t\t\tstate: DocumentRecordType.create({ id: TLDOCUMENT_ID }),\n\t\t\tlastChangedClock: 0,\n\t\t},\n\t\t{\n\t\t\tstate: PageRecordType.create({\n\t\t\t\tid: 'page:page' as TLPageId,\n\t\t\t\tname: 'Page 1',\n\t\t\t\tindex: 'a1' as IndexKey,\n\t\t\t}),\n\t\t\tlastChangedClock: 0,\n\t\t},\n\t],\n}\n\n/**\n * In-memory implementation of TLSyncStorage using AtomMap for documents and tombstones,\n * and atoms for clock values. This is the default storage implementation used by TLSyncRoom.\n *\n * @public\n */\nexport class InMemorySyncStorage<R extends UnknownRecord> implements TLSyncStorage<R> {\n\t/** @internal */\n\tdocuments: AtomMap<string, { state: R; lastChangedClock: number }>\n\t/** @internal */\n\ttombstones: AtomMap<string, number>\n\t/** @internal */\n\tschema: Atom<SerializedSchema>\n\t/** @internal */\n\tdocumentClock: Atom<number>\n\t/** @internal */\n\ttombstoneHistoryStartsAtClock: Atom<number>\n\n\tprivate notifier = new MicrotaskNotifier<[TLSyncStorageOnChangeCallbackProps]>()\n\tonChange(callback: (arg: TLSyncStorageOnChangeCallbackProps) => unknown): () => void {\n\t\treturn this.notifier.register(callback)\n\t}\n\n\tconstructor({\n\t\tsnapshot = DEFAULT_INITIAL_SNAPSHOT,\n\t\tonChange,\n\t}: {\n\t\tsnapshot?: RoomSnapshot\n\t\tonChange?(arg: TLSyncStorageOnChangeCallbackProps): unknown\n\t} = {}) {\n\t\tconst maxClockValue = Math.max(\n\t\t\t0,\n\t\t\t...Object.values(snapshot.tombstones ?? {}),\n\t\t\t...Object.values(snapshot.documents.map((d) => d.lastChangedClock))\n\t\t)\n\t\tthis.documents = new AtomMap(\n\t\t\t'room documents',\n\t\t\tsnapshot.documents.map((d) => [\n\t\t\t\td.state.id,\n\t\t\t\t{ state: devFreeze(d.state) as R, lastChangedClock: d.lastChangedClock },\n\t\t\t])\n\t\t)\n\t\tconst documentClock = Math.max(maxClockValue, snapshot.documentClock ?? snapshot.clock ?? 0)\n\n\t\tthis.documentClock = atom('document clock', documentClock)\n\t\t// math.min to make sure the tombstone history starts at or before the document clock\n\t\tconst tombstoneHistoryStartsAtClock = Math.min(\n\t\t\tsnapshot.tombstoneHistoryStartsAtClock ?? documentClock,\n\t\t\tdocumentClock\n\t\t)\n\t\tthis.tombstoneHistoryStartsAtClock = atom(\n\t\t\t'tombstone history starts at clock',\n\t\t\ttombstoneHistoryStartsAtClock\n\t\t)\n\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\tthis.schema = atom('schema', snapshot.schema ?? createTLSchema().serializeEarliestVersion())\n\t\tthis.tombstones = new AtomMap(\n\t\t\t'room tombstones',\n\t\t\t// If the tombstone history starts now (or we didn't have the\n\t\t\t// tombstoneHistoryStartsAtClock) then there are no tombstones\n\t\t\ttombstoneHistoryStartsAtClock === documentClock\n\t\t\t\t? []\n\t\t\t\t: objectMapEntries(snapshot.tombstones ?? {})\n\t\t)\n\t\tif (onChange) {\n\t\t\tthis.onChange(onChange)\n\t\t}\n\t}\n\n\ttransaction<T>(\n\t\tcallback: TLSyncStorageTransactionCallback<R, T>,\n\t\topts?: TLSyncStorageTransactionOptions\n\t): TLSyncStorageTransactionResult<T, R> {\n\t\tconst clockBefore = this.documentClock.get()\n\t\tconst trackChanges = opts?.emitChanges === 'always'\n\t\tconst txn = new InMemorySyncStorageTransaction<R>(this)\n\t\tlet result: T\n\t\tlet changes: TLSyncForwardDiff<R> | undefined\n\t\ttry {\n\t\t\tresult = transaction(() => {\n\t\t\t\treturn callback(txn as any)\n\t\t\t}) as T\n\t\t\tif (trackChanges) {\n\t\t\t\tchanges = txn.getChangesSince(clockBefore)?.diff\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error('Error in transaction', error)\n\t\t\tthrow error\n\t\t} finally {\n\t\t\ttxn.close()\n\t\t}\n\t\tif (\n\t\t\ttypeof result === 'object' &&\n\t\t\tresult &&\n\t\t\t'then' in result &&\n\t\t\ttypeof result.then === 'function'\n\t\t) {\n\t\t\tconst err = new Error('Transaction must return a value, not a promise')\n\t\t\tconsole.error(err)\n\t\t\tthrow err\n\t\t}\n\n\t\tconst clockAfter = this.documentClock.get()\n\t\tconst didChange = clockAfter > clockBefore\n\t\tif (didChange) {\n\t\t\tthis.notifier.notify({ id: opts?.id, documentClock: clockAfter })\n\t\t}\n\t\t// InMemorySyncStorage applies changes verbatim, so we only emit changes\n\t\t// when 'always' is specified (not for 'when-different')\n\t\treturn { documentClock: clockAfter, didChange: clockAfter > clockBefore, result, changes }\n\t}\n\n\tgetClock(): number {\n\t\treturn this.documentClock.get()\n\t}\n\n\t/** @internal */\n\tpruneTombstones = throttle(\n\t\t() => {\n\t\t\tif (this.tombstones.size > MAX_TOMBSTONES) {\n\t\t\t\t// Convert to array and sort by clock ascending (oldest first)\n\t\t\t\tconst tombstones = Array.from(this.tombstones.entries())\n\t\t\t\t\t.map(([id, clock]) => ({ id, clock }))\n\t\t\t\t\t.sort((a, b) => a.clock - b.clock)\n\n\t\t\t\tconst result = computeTombstonePruning({\n\t\t\t\t\ttombstones,\n\t\t\t\t\tdocumentClock: this.documentClock.get(),\n\t\t\t\t})\n\t\t\t\tif (result) {\n\t\t\t\t\tthis.tombstoneHistoryStartsAtClock.set(result.newTombstoneHistoryStartsAtClock)\n\t\t\t\t\tthis.tombstones.deleteMany(result.idsToDelete)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t1000,\n\t\t// prevent this from running synchronously to avoid blocking requests\n\t\t{ leading: false }\n\t)\n\n\tgetSnapshot(): RoomSnapshot {\n\t\treturn {\n\t\t\ttombstoneHistoryStartsAtClock: this.tombstoneHistoryStartsAtClock.get(),\n\t\t\tdocumentClock: this.documentClock.get(),\n\t\t\tdocuments: Array.from(this.documents.values()),\n\t\t\ttombstones: Object.fromEntries(this.tombstones.entries()),\n\t\t\tschema: this.schema.get(),\n\t\t}\n\t}\n}\n\n/**\n * Transaction implementation for InMemorySyncStorage.\n * Provides access to documents, tombstones, and metadata within a transaction.\n *\n * @internal\n */\nclass InMemorySyncStorageTransaction<\n\tR extends UnknownRecord,\n> implements TLSyncStorageTransaction<R> {\n\tprivate _clock\n\tprivate _closed = false\n\n\tconstructor(private storage: InMemorySyncStorage<R>) {\n\t\tthis._clock = this.storage.documentClock.get()\n\t}\n\n\t/** @internal */\n\tclose() {\n\t\tthis._closed = true\n\t}\n\n\tprivate assertNotClosed() {\n\t\tassert(!this._closed, 'Transaction has ended, iterator cannot be consumed')\n\t}\n\n\tgetClock(): number {\n\t\treturn this._clock\n\t}\n\n\tprivate didIncrementClock: boolean = false\n\tprivate getNextClock(): number {\n\t\tif (!this.didIncrementClock) {\n\t\t\tthis.didIncrementClock = true\n\t\t\tthis._clock = this.storage.documentClock.set(this.storage.documentClock.get() + 1)\n\t\t}\n\t\treturn this._clock\n\t}\n\n\tget(id: string): R | undefined {\n\t\tthis.assertNotClosed()\n\t\treturn this.storage.documents.get(id)?.state\n\t}\n\n\tset(id: string, record: R): void {\n\t\tthis.assertNotClosed()\n\t\tassert(id === record.id, `Record id mismatch: key does not match record.id`)\n\t\tconst clock = this.getNextClock()\n\t\t// Automatically clear tombstone if it exists\n\t\tif (this.storage.tombstones.has(id)) {\n\t\t\tthis.storage.tombstones.delete(id)\n\t\t}\n\t\tthis.storage.documents.set(id, {\n\t\t\tstate: devFreeze(record) as R,\n\t\t\tlastChangedClock: clock,\n\t\t})\n\t}\n\n\tdelete(id: string): void {\n\t\tthis.assertNotClosed()\n\t\t// Only create a tombstone if the record actually exists\n\t\tif (!this.storage.documents.has(id)) return\n\t\tconst clock = this.getNextClock()\n\t\tthis.storage.documents.delete(id)\n\t\tthis.storage.tombstones.set(id, clock)\n\t\tthis.storage.pruneTombstones()\n\t}\n\n\t*entries(): IterableIterator<[string, R]> {\n\t\tthis.assertNotClosed()\n\t\tfor (const [id, record] of this.storage.documents.entries()) {\n\t\t\tthis.assertNotClosed()\n\t\t\tyield [id, record.state]\n\t\t}\n\t}\n\n\t*keys(): IterableIterator<string> {\n\t\tthis.assertNotClosed()\n\t\tfor (const key of this.storage.documents.keys()) {\n\t\t\tthis.assertNotClosed()\n\t\t\tyield key\n\t\t}\n\t}\n\n\t*values(): IterableIterator<R> {\n\t\tthis.assertNotClosed()\n\t\tfor (const record of this.storage.documents.values()) {\n\t\t\tthis.assertNotClosed()\n\t\t\tyield record.state\n\t\t}\n\t}\n\n\tgetSchema(): SerializedSchema {\n\t\tthis.assertNotClosed()\n\t\treturn this.storage.schema.get()\n\t}\n\n\tsetSchema(schema: SerializedSchema): void {\n\t\tthis.assertNotClosed()\n\t\tthis.storage.schema.set(schema)\n\t}\n\n\tgetChangesSince(sinceClock: number): TLSyncStorageGetChangesSinceResult<R> | undefined {\n\t\tthis.assertNotClosed()\n\t\tconst clock = this.storage.documentClock.get()\n\t\tif (sinceClock === clock) return undefined\n\t\tif (sinceClock > clock) {\n\t\t\t// something went wrong, wipe the slate clean\n\t\t\tsinceClock = -1\n\t\t}\n\t\tconst diff: TLSyncForwardDiff<R> = { puts: {}, deletes: [] }\n\t\tconst wipeAll = sinceClock < this.storage.tombstoneHistoryStartsAtClock.get()\n\t\tfor (const doc of this.storage.documents.values()) {\n\t\t\tif (wipeAll || doc.lastChangedClock > sinceClock) {\n\t\t\t\t// For historical changes, we don't have \"from\" state, so use added\n\t\t\t\tdiff.puts[doc.state.id] = doc.state as R\n\t\t\t}\n\t\t}\n\t\tif (!wipeAll) {\n\t\t\tfor (const [id, clock] of this.storage.tombstones.entries()) {\n\t\t\t\tif (clock > sinceClock) {\n\t\t\t\t\t// For tombstones, we don't have the removed record, use placeholder\n\t\t\t\t\tdiff.deletes.push(id)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn { diff, wipeAll }\n\t}\n}\n"],
5
- "mappings": "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",
5
+ "mappings": "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",
6
6
  "names": ["clock"]
7
7
  }
@@ -3,6 +3,8 @@ class NodeSqliteWrapper {
3
3
  this.db = db;
4
4
  this.config = config;
5
5
  }
6
+ db;
7
+ config;
6
8
  exec(sql) {
7
9
  this.db.exec(sql);
8
10
  }
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/NodeSqliteWrapper.ts"],
4
4
  "sourcesContent": ["import {\n\ttype TLSqliteInputValue,\n\ttype TLSqliteRow,\n\ttype TLSyncSqliteStatement,\n\ttype TLSyncSqliteWrapper,\n\ttype TLSyncSqliteWrapperConfig,\n} from './SQLiteSyncStorage'\n\n/**\n * Minimal interface for a synchronous SQLite database.\n *\n * This interface is compatible with:\n * - `node:sqlite` DatabaseSync (Node.js 22.5+)\n * - `better-sqlite3` Database\n *\n * Any SQLite library that provides synchronous `exec` and `prepare` methods\n * with the signatures below can be used with {@link NodeSqliteWrapper}.\n *\n * @public\n */\nexport interface SyncSqliteDatabase {\n\t/** Execute raw SQL without returning results */\n\texec(sql: string): void\n\t/** Prepare a statement for execution */\n\tprepare(sql: string): {\n\t\titerate(...params: unknown[]): IterableIterator<unknown>\n\t\tall(...params: unknown[]): unknown[]\n\t\trun(...params: unknown[]): unknown\n\t}\n}\n\n/**\n * A wrapper around synchronous SQLite databases that implements TLSyncSqliteWrapper.\n * Works with both `node:sqlite` DatabaseSync (Node.js 22.5+) and `better-sqlite3` Database.\n *\n * Use this wrapper with SQLiteSyncStorage to persist tldraw sync state to a SQLite database\n * in Node.js environments.\n *\n * @example\n * ```ts\n * // With node:sqlite (Node.js 22.5+)\n * import { DatabaseSync } from 'node:sqlite'\n * import { SQLiteSyncStorage, NodeSqliteWrapper } from '@tldraw/sync-core'\n *\n * const db = new DatabaseSync(':memory:')\n * const sql = new NodeSqliteWrapper(db)\n * const storage = new SQLiteSyncStorage({ sql })\n * ```\n *\n * @example\n * ```ts\n * // With better-sqlite3\n * import Database from 'better-sqlite3'\n * import { SQLiteSyncStorage, NodeSqliteWrapper } from '@tldraw/sync-core'\n *\n * const db = new Database(':memory:')\n * const sql = new NodeSqliteWrapper(db)\n * const storage = new SQLiteSyncStorage({ sql })\n * ```\n *\n * @example\n * ```ts\n * // With table prefix to avoid conflicts with other tables\n * const sql = new NodeSqliteWrapper(db, { tablePrefix: 'tldraw_' })\n * // Creates tables: tldraw_documents, tldraw_tombstones, tldraw_metadata\n * ```\n *\n * @public\n */\nexport class NodeSqliteWrapper implements TLSyncSqliteWrapper {\n\tconstructor(\n\t\tprivate db: SyncSqliteDatabase,\n\t\tpublic config?: TLSyncSqliteWrapperConfig\n\t) {}\n\n\texec(sql: string): void {\n\t\tthis.db.exec(sql)\n\t}\n\n\tprepare<\n\t\tTResult extends TLSqliteRow | void = void,\n\t\tTParams extends TLSqliteInputValue[] = TLSqliteInputValue[],\n\t>(sql: string): TLSyncSqliteStatement<TResult, TParams> {\n\t\treturn this.db.prepare(sql) as unknown as TLSyncSqliteStatement<TResult, TParams>\n\t}\n\n\ttransaction<T>(callback: () => T): T {\n\t\tthis.db.exec('BEGIN')\n\t\tlet result: T\n\t\ttry {\n\t\t\tresult = callback()\n\t\t} catch (e) {\n\t\t\tthis.db.exec('ROLLBACK')\n\t\t\tthrow e\n\t\t}\n\t\tthis.db.exec('COMMIT')\n\t\treturn result\n\t}\n}\n"],
5
- "mappings": "AAqEO,MAAM,kBAAiD;AAAA,EAC7D,YACS,IACD,QACN;AAFO;AACD;AAAA,EACL;AAAA,EAEH,KAAK,KAAmB;AACvB,SAAK,GAAG,KAAK,GAAG;AAAA,EACjB;AAAA,EAEA,QAGE,KAAsD;AACvD,WAAO,KAAK,GAAG,QAAQ,GAAG;AAAA,EAC3B;AAAA,EAEA,YAAe,UAAsB;AACpC,SAAK,GAAG,KAAK,OAAO;AACpB,QAAI;AACJ,QAAI;AACH,eAAS,SAAS;AAAA,IACnB,SAAS,GAAG;AACX,WAAK,GAAG,KAAK,UAAU;AACvB,YAAM;AAAA,IACP;AACA,SAAK,GAAG,KAAK,QAAQ;AACrB,WAAO;AAAA,EACR;AACD;",
5
+ "mappings": "AAqEO,MAAM,kBAAiD;AAAA,EAC7D,YACS,IACD,QACN;AAFO;AACD;AAAA,EACL;AAAA,EAFM;AAAA,EACD;AAAA,EAGR,KAAK,KAAmB;AACvB,SAAK,GAAG,KAAK,GAAG;AAAA,EACjB;AAAA,EAEA,QAGE,KAAsD;AACvD,WAAO,KAAK,GAAG,QAAQ,GAAG;AAAA,EAC3B;AAAA,EAEA,YAAe,UAAsB;AACpC,SAAK,GAAG,KAAK,OAAO;AACpB,QAAI;AACJ,QAAI;AACH,eAAS,SAAS;AAAA,IACnB,SAAS,GAAG;AACX,WAAK,GAAG,KAAK,UAAU;AACvB,YAAM;AAAA,IACP;AACA,SAAK,GAAG,KAAK,QAAQ;AACrB,WAAO;AAAA,EACR;AACD;",
6
6
  "names": []
7
7
  }
@@ -309,6 +309,8 @@ class SQLiteSyncStorageTransaction {
309
309
  this.stmts = stmts;
310
310
  this._clock = this.storage.getClock();
311
311
  }
312
+ storage;
313
+ stmts;
312
314
  _clock;
313
315
  _closed = false;
314
316
  _didIncrementClock = false;
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/SQLiteSyncStorage.ts"],
4
4
  "sourcesContent": ["import { transaction } from '@tldraw/state'\nimport { SerializedSchema, StoreSnapshot, UnknownRecord } from '@tldraw/store'\nimport { assert, objectMapEntries, throttle } from '@tldraw/utils'\nimport {\n\tcomputeTombstonePruning,\n\tDEFAULT_INITIAL_SNAPSHOT,\n\tMAX_TOMBSTONES,\n} from './InMemorySyncStorage'\nimport { MicrotaskNotifier } from './MicrotaskNotifier'\nimport { RoomSnapshot } from './TLSyncRoom'\nimport {\n\tconvertStoreSnapshotToRoomSnapshot,\n\tTLSyncForwardDiff,\n\tTLSyncStorage,\n\tTLSyncStorageGetChangesSinceResult,\n\tTLSyncStorageOnChangeCallbackProps,\n\tTLSyncStorageTransaction,\n\tTLSyncStorageTransactionCallback,\n\tTLSyncStorageTransactionOptions,\n\tTLSyncStorageTransactionResult,\n} from './TLSyncStorage'\n\n/**\n * Valid input value types for SQLite query parameters.\n * These are the types that can be passed as bindings to prepared statements.\n * @public\n */\nexport type TLSqliteInputValue = null | number | bigint | string | Uint8Array\n\n/**\n * Possible output value types returned from SQLite queries.\n * Includes all input types plus Uint8Array for BLOB columns.\n * @public\n */\nexport type TLSqliteOutputValue = null | number | bigint | string | Uint8Array\n\n/**\n * A row returned from a SQLite query, mapping column names to their values.\n * @public\n */\nexport type TLSqliteRow = Record<string, TLSqliteOutputValue>\n\n/**\n * A prepared statement that can be executed multiple times with different bindings.\n * @public\n */\nexport interface TLSyncSqliteStatement<\n\tTResult extends TLSqliteRow | void,\n\tTParams extends TLSqliteInputValue[] = [],\n> {\n\t/** Execute the statement and iterate over results one at a time */\n\titerate(...bindings: TParams): IterableIterator<TResult>\n\t/** Execute the statement and return all results as an array */\n\tall(...bindings: TParams): TResult[]\n\t/** Execute the statement without returning results (for DML) */\n\trun(...bindings: TParams): void\n}\n\n/**\n * Configuration for SQLiteSyncStorage.\n * @public\n */\nexport interface TLSyncSqliteWrapperConfig {\n\t/** Prefix for all table names (default: ''). E.g. 'sync_' creates tables 'sync_documents', 'sync_tombstones', 'sync_metadata' */\n\ttablePrefix?: string\n}\n\n/**\n * Interface for SQLite storage with prepare, exec and transaction capabilities.\n * @public\n */\nexport interface TLSyncSqliteWrapper {\n\t/** Optional configuration for table names. If not provided, defaults are used. */\n\treadonly config?: TLSyncSqliteWrapperConfig\n\t/** Prepare a SQL statement for execution */\n\tprepare<TResult extends TLSqliteRow | void, TParams extends TLSqliteInputValue[] = []>(\n\t\tsql: string\n\t): TLSyncSqliteStatement<TResult, TParams>\n\t/** Execute raw SQL (for DDL, multi-statement scripts) */\n\texec(sql: string): void\n\t/** Execute a callback within a transaction */\n\ttransaction<T>(callback: () => T): T\n}\n\nexport function migrateSqliteSyncStorage(\n\tstorage: TLSyncSqliteWrapper,\n\t{\n\t\tdocumentsTable = 'documents',\n\t\ttombstonesTable = 'tombstones',\n\t\tmetadataTable = 'metadata',\n\t}: { documentsTable?: string; tombstonesTable?: string; metadataTable?: string } = {}\n): void {\n\tlet migrationVersion = 0\n\ttry {\n\t\tconst row = storage\n\t\t\t.prepare<{\n\t\t\t\tmigrationVersion: number\n\t\t\t}>(`SELECT migrationVersion FROM ${metadataTable} LIMIT 1`)\n\t\t\t.all()[0]\n\t\tmigrationVersion = row?.migrationVersion ?? 0\n\t} catch (_e) {\n\t\t// noop\n\t}\n\n\tif (migrationVersion === 0) {\n\t\tmigrationVersion++\n\t\tstorage.exec(`\n\t\t\tCREATE TABLE ${documentsTable} (\n\t\t\t\tid TEXT PRIMARY KEY,\n\t\t\t\tstate BLOB NOT NULL,\n\t\t\t\tlastChangedClock INTEGER NOT NULL\n\t\t\t);\n\n\t\t\tCREATE INDEX idx_${documentsTable}_lastChangedClock ON ${documentsTable}(lastChangedClock);\n\n\t\t\tCREATE TABLE ${tombstonesTable} (\n\t\t\t\tid TEXT PRIMARY KEY,\n\t\t\t\tclock INTEGER NOT NULL\n\t\t\t);\n\t\t\tCREATE INDEX idx_${tombstonesTable}_clock ON ${tombstonesTable}(clock);\n\n\t\t\t-- This table is used to store the metadata for the sync storage.\n\t\t\t-- There should only be one row in this table.\n\t\t\tCREATE TABLE ${metadataTable} (\n\t\t\t migrationVersion INTEGER NOT NULL,\n\t\t\t\tdocumentClock INTEGER NOT NULL,\n\t\t\t\ttombstoneHistoryStartsAtClock INTEGER NOT NULL,\n\t\t\t\tschema TEXT NOT NULL\n\t\t\t);\n\t\t\t\n\t\t\tINSERT INTO ${metadataTable} (migrationVersion, documentClock, tombstoneHistoryStartsAtClock, schema) VALUES (2, 0, 0, '')\n\t\t`)\n\t\t// Skip migration 2 since we created the table with BLOB already\n\t\tmigrationVersion++\n\t}\n\n\tif (migrationVersion === 1) {\n\t\t// Migration 2: Convert state column from TEXT to BLOB\n\t\t// SQLite doesn't support ALTER COLUMN, so we need to recreate the table\n\t\tmigrationVersion++\n\t\tstorage.exec(`\n\t\t\tCREATE TABLE ${documentsTable}_new (\n\t\t\t\tid TEXT PRIMARY KEY,\n\t\t\t\tstate BLOB NOT NULL,\n\t\t\t\tlastChangedClock INTEGER NOT NULL\n\t\t\t);\n\t\t\t\n\t\t\tINSERT INTO ${documentsTable}_new (id, state, lastChangedClock)\n\t\t\tSELECT id, CAST(state AS BLOB), lastChangedClock FROM ${documentsTable};\n\t\t\t\n\t\t\tDROP TABLE ${documentsTable};\n\t\t\t\n\t\t\tALTER TABLE ${documentsTable}_new RENAME TO ${documentsTable};\n\t\t\t\n\t\t\tCREATE INDEX idx_${documentsTable}_lastChangedClock ON ${documentsTable}(lastChangedClock);\n\t\t`)\n\t}\n\n\t// add more migrations here if and when needed\n\n\tstorage.exec(`UPDATE ${metadataTable} SET migrationVersion = ${migrationVersion}`)\n}\n\nconst textEncoder = new TextEncoder()\nconst textDecoder = new TextDecoder()\n\nfunction encodeState(state: unknown): Uint8Array {\n\treturn textEncoder.encode(JSON.stringify(state))\n}\n\nfunction decodeState<T>(state: Uint8Array): T {\n\treturn JSON.parse(textDecoder.decode(state))\n}\n\n/**\n * SQLite-based implementation of TLSyncStorage.\n * Stores documents, tombstones, metadata, and clock values in SQLite tables.\n *\n * This storage backend provides persistent synchronization state that survives\n * process restarts, unlike InMemorySyncStorage which loses data when the process ends.\n *\n * @example\n * ```ts\n * // With Cloudflare Durable Objects\n * import { SQLiteSyncStorage, DurableObjectSqliteSyncWrapper } from '@tldraw/sync-core'\n *\n * const sql = new DurableObjectSqliteSyncWrapper(this.ctx.storage)\n * const storage = new SQLiteSyncStorage({ sql })\n * ```\n *\n * @example\n * ```ts\n * // With Node.js sqlite (Node 22.5+)\n * import { DatabaseSync } from 'node:sqlite'\n * import { SQLiteSyncStorage, NodeSqliteWrapper } from '@tldraw/sync-core'\n *\n * const db = new DatabaseSync('sync-state.db')\n * const sql = new NodeSqliteWrapper(db)\n * const storage = new SQLiteSyncStorage({ sql })\n * ```\n *\n * @example\n * ```ts\n * // Initialize with an existing snapshot\n * const storage = new SQLiteSyncStorage({ sql, snapshot: existingSnapshot })\n * ```\n *\n * @public\n */\nexport class SQLiteSyncStorage<R extends UnknownRecord> implements TLSyncStorage<R> {\n\t/**\n\t * Check if the storage has been initialized (has data in the clock table).\n\t * Useful for determining whether to load from an external source on first access.\n\t */\n\tstatic hasBeenInitialized(storage: TLSyncSqliteWrapper): boolean {\n\t\tconst prefix = storage.config?.tablePrefix ?? ''\n\t\ttry {\n\t\t\tconst schema = storage\n\t\t\t\t.prepare<{ schema: string }>(`SELECT schema FROM ${prefix}metadata LIMIT 1`)\n\t\t\t\t.all()[0]?.schema\n\t\t\treturn !!schema\n\t\t} catch (_e) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Get the current document clock value from storage without fully initializing.\n\t * Returns null if storage has not been initialized.\n\t * Useful for comparing storage freshness against external sources.\n\t */\n\tstatic getDocumentClock(storage: TLSyncSqliteWrapper): number | null {\n\t\tconst prefix = storage.config?.tablePrefix ?? ''\n\t\ttry {\n\t\t\tconst row = storage\n\t\t\t\t.prepare<{ documentClock: number }>(`SELECT documentClock FROM ${prefix}metadata LIMIT 1`)\n\t\t\t\t.all()[0]\n\t\t\t// documentClock exists but could be 0, so we check if the storage is initialized\n\t\t\tif (row && SQLiteSyncStorage.hasBeenInitialized(storage)) {\n\t\t\t\treturn row.documentClock\n\t\t\t}\n\t\t\treturn null\n\t\t} catch (_e) {\n\t\t\treturn null\n\t\t}\n\t}\n\n\t// Prepared statements - created once, reused many times\n\tprivate readonly stmts\n\n\tprivate readonly sql: TLSyncSqliteWrapper\n\n\tconstructor({\n\t\tsql,\n\t\tsnapshot,\n\t\tonChange,\n\t}: {\n\t\tsql: TLSyncSqliteWrapper\n\t\tsnapshot?: RoomSnapshot | StoreSnapshot<R>\n\t\tonChange?(arg: TLSyncStorageOnChangeCallbackProps): unknown\n\t}) {\n\t\tthis.sql = sql\n\t\tconst prefix = sql.config?.tablePrefix ?? ''\n\t\tconst documentsTable = `${prefix}documents`\n\t\tconst tombstonesTable = `${prefix}tombstones`\n\t\tconst metadataTable = `${prefix}metadata`\n\n\t\tmigrateSqliteSyncStorage(this.sql, { documentsTable, tombstonesTable, metadataTable })\n\n\t\t// Prepare all statements once\n\t\tthis.stmts = {\n\t\t\t// Metadata\n\t\t\tgetDocumentClock: this.sql.prepare<{ documentClock: number }>(\n\t\t\t\t`SELECT documentClock FROM ${metadataTable} LIMIT 1`\n\t\t\t),\n\t\t\tgetTombstoneHistoryStartsAtClock: this.sql.prepare<{ tombstoneHistoryStartsAtClock: number }>(\n\t\t\t\t`SELECT tombstoneHistoryStartsAtClock FROM ${metadataTable}`\n\t\t\t),\n\t\t\tgetSchema: this.sql.prepare<{ schema: string }>(`SELECT schema FROM ${metadataTable}`),\n\t\t\tsetSchema: this.sql.prepare<void, [schema: string]>(`UPDATE ${metadataTable} SET schema = ?`),\n\t\t\tsetTombstoneHistoryStartsAtClock: this.sql.prepare<void, [clock: number]>(\n\t\t\t\t`UPDATE ${metadataTable} SET tombstoneHistoryStartsAtClock = ?`\n\t\t\t),\n\t\t\tincrementDocumentClock: this.sql.prepare<void>(\n\t\t\t\t`UPDATE ${metadataTable} SET documentClock = documentClock + 1`\n\t\t\t),\n\n\t\t\t// Documents\n\t\t\tgetDocument: this.sql.prepare<{ state: Uint8Array }, [id: string]>(\n\t\t\t\t`SELECT state FROM ${documentsTable} WHERE id = ?`\n\t\t\t),\n\t\t\tinsertDocument: this.sql.prepare<\n\t\t\t\tvoid,\n\t\t\t\t[id: string, state: Uint8Array, lastChangedClock: number]\n\t\t\t>(`INSERT OR REPLACE INTO ${documentsTable} (id, state, lastChangedClock) VALUES (?, ?, ?)`),\n\t\t\tdeleteDocument: this.sql.prepare<void, [id: string]>(\n\t\t\t\t`DELETE FROM ${documentsTable} WHERE id = ?`\n\t\t\t),\n\t\t\tdocumentExists: this.sql.prepare<{ id: string }, [id: string]>(\n\t\t\t\t`SELECT id FROM ${documentsTable} WHERE id = ?`\n\t\t\t),\n\t\t\titerateDocuments: this.sql.prepare<{ state: Uint8Array; lastChangedClock: number }>(\n\t\t\t\t`SELECT state, lastChangedClock FROM ${documentsTable}`\n\t\t\t),\n\t\t\titerateDocumentEntries: this.sql.prepare<{ id: string; state: Uint8Array }>(\n\t\t\t\t`SELECT id, state FROM ${documentsTable}`\n\t\t\t),\n\t\t\titerateDocumentKeys: this.sql.prepare<{ id: string }>(`SELECT id FROM ${documentsTable}`),\n\t\t\titerateDocumentValues: this.sql.prepare<{ state: Uint8Array }>(\n\t\t\t\t`SELECT state FROM ${documentsTable}`\n\t\t\t),\n\t\t\tgetDocumentsChangedSince: this.sql.prepare<{ state: Uint8Array }, [sinceClock: number]>(\n\t\t\t\t`SELECT state FROM ${documentsTable} WHERE lastChangedClock > ?`\n\t\t\t),\n\n\t\t\t// Tombstones\n\t\t\tinsertTombstone: this.sql.prepare<void, [id: string, clock: number]>(\n\t\t\t\t`INSERT OR REPLACE INTO ${tombstonesTable} (id, clock) VALUES (?, ?)`\n\t\t\t),\n\t\t\tdeleteTombstone: this.sql.prepare<void, [id: string]>(\n\t\t\t\t`DELETE FROM ${tombstonesTable} WHERE id = ?`\n\t\t\t),\n\t\t\tdeleteTombstonesBefore: this.sql.prepare<void, [clock: number]>(\n\t\t\t\t`DELETE FROM ${tombstonesTable} WHERE clock < ?`\n\t\t\t),\n\t\t\tcountTombstones: this.sql.prepare<{ count: number }>(\n\t\t\t\t`SELECT count(*) as count FROM ${tombstonesTable}`\n\t\t\t),\n\t\t\titerateTombstones: this.sql.prepare<{ id: string; clock: number }>(\n\t\t\t\t`SELECT id, clock FROM ${tombstonesTable} ORDER BY clock ASC`\n\t\t\t),\n\t\t\tgetTombstonesChangedSince: this.sql.prepare<{ id: string }, [sinceClock: number]>(\n\t\t\t\t`SELECT id FROM ${tombstonesTable} WHERE clock > ?`\n\t\t\t),\n\n\t\t\t// Initial setup (only used when loading a snapshot)\n\t\t\tupdateMetadata: this.sql.prepare<\n\t\t\t\tvoid,\n\t\t\t\t[documentClock: number, tombstoneHistoryStartsAtClock: number, schema: string]\n\t\t\t>(\n\t\t\t\t`UPDATE ${metadataTable} SET documentClock = ?, tombstoneHistoryStartsAtClock = ?, schema = ?`\n\t\t\t),\n\t\t}\n\n\t\t// Check if we already have data\n\t\tconst hasData = SQLiteSyncStorage.hasBeenInitialized(sql)\n\n\t\tif (snapshot || !hasData) {\n\t\t\tsnapshot = convertStoreSnapshotToRoomSnapshot(snapshot ?? DEFAULT_INITIAL_SNAPSHOT)\n\n\t\t\tconst documentClock = snapshot.documentClock ?? snapshot.clock ?? 0\n\t\t\tconst tombstoneHistoryStartsAtClock = snapshot.tombstoneHistoryStartsAtClock ?? documentClock\n\n\t\t\t// Clear existing data\n\t\t\tthis.sql.exec(`\n\t\t\t\tDELETE FROM ${documentsTable};\n\t\t\t\tDELETE FROM ${tombstonesTable};\n\t\t\t`)\n\n\t\t\t// Insert documents\n\t\t\tfor (const doc of snapshot.documents) {\n\t\t\t\tthis.stmts.insertDocument.run(doc.state.id, encodeState(doc.state), doc.lastChangedClock)\n\t\t\t}\n\n\t\t\t// Insert tombstones\n\t\t\tif (snapshot.tombstones) {\n\t\t\t\tfor (const [id, clock] of objectMapEntries(snapshot.tombstones)) {\n\t\t\t\t\tthis.stmts.insertTombstone.run(id, clock)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Insert metadata row\n\t\t\tthis.stmts.updateMetadata.run(\n\t\t\t\tdocumentClock,\n\t\t\t\ttombstoneHistoryStartsAtClock,\n\t\t\t\tJSON.stringify(snapshot.schema)\n\t\t\t)\n\t\t}\n\t\tif (onChange) {\n\t\t\tthis.onChange(onChange)\n\t\t}\n\t}\n\n\tprivate notifier = new MicrotaskNotifier<[TLSyncStorageOnChangeCallbackProps]>()\n\tonChange(callback: (arg: TLSyncStorageOnChangeCallbackProps) => void): () => void {\n\t\treturn this.notifier.register(callback)\n\t}\n\n\ttransaction<T>(\n\t\tcallback: TLSyncStorageTransactionCallback<R, T>,\n\t\topts?: TLSyncStorageTransactionOptions\n\t): TLSyncStorageTransactionResult<T, R> {\n\t\tconst clockBefore = this.getClock()\n\t\tconst trackChanges = opts?.emitChanges === 'always'\n\t\treturn this.sql.transaction(() => {\n\t\t\tconst txn = new SQLiteSyncStorageTransaction<R>(this, this.stmts)\n\t\t\tlet result: T\n\t\t\tlet changes: TLSyncForwardDiff<R> | undefined\n\t\t\ttry {\n\t\t\t\tresult = transaction(() => {\n\t\t\t\t\treturn callback(txn)\n\t\t\t\t}) as T\n\t\t\t\tif (trackChanges) {\n\t\t\t\t\tchanges = txn.getChangesSince(clockBefore)?.diff\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\ttxn.close()\n\t\t\t}\n\t\t\tif (\n\t\t\t\ttypeof result === 'object' &&\n\t\t\t\tresult &&\n\t\t\t\t'then' in result &&\n\t\t\t\ttypeof result.then === 'function'\n\t\t\t) {\n\t\t\t\tthrow new Error('Transaction must return a value, not a promise')\n\t\t\t}\n\n\t\t\tconst clockAfter = this.getClock()\n\t\t\tconst didChange = clockAfter > clockBefore\n\t\t\tif (didChange) {\n\t\t\t\tthis.notifier.notify({ id: opts?.id, documentClock: clockAfter })\n\t\t\t}\n\t\t\treturn { documentClock: clockAfter, didChange: clockAfter > clockBefore, result, changes }\n\t\t})\n\t}\n\n\tgetClock(): number {\n\t\tconst clockRow = this.stmts.getDocumentClock.all()[0]\n\t\treturn clockRow?.documentClock ?? 0\n\t}\n\n\t/** @internal */\n\t_getTombstoneHistoryStartsAtClock(): number {\n\t\tconst clockRow = this.stmts.getTombstoneHistoryStartsAtClock.all()[0]\n\t\treturn clockRow?.tombstoneHistoryStartsAtClock ?? 0\n\t}\n\n\t/** @internal */\n\t_getSchema(): SerializedSchema {\n\t\tconst clockRow = this.stmts.getSchema.all()[0]\n\t\tassert(clockRow, 'Storage not initialized - clock row missing')\n\t\treturn JSON.parse(clockRow.schema)\n\t}\n\n\t/** @internal */\n\t_setSchema(schema: SerializedSchema): void {\n\t\tthis.stmts.setSchema.run(JSON.stringify(schema))\n\t}\n\n\t/** @internal */\n\tpruneTombstones = throttle(\n\t\t() => {\n\t\t\tconst tombstoneCount = this.stmts.countTombstones.all()[0].count as number\n\t\t\tif (tombstoneCount > MAX_TOMBSTONES) {\n\t\t\t\t// Get all tombstones sorted by clock ascending (oldest first)\n\t\t\t\tconst tombstones = this.stmts.iterateTombstones.all()\n\n\t\t\t\tconst result = computeTombstonePruning({ tombstones, documentClock: this.getClock() })\n\t\t\t\tif (result) {\n\t\t\t\t\tthis.stmts.setTombstoneHistoryStartsAtClock.run(result.newTombstoneHistoryStartsAtClock)\n\t\t\t\t\t// Delete all tombstones with clock < newTombstoneHistoryStartsAtClock in one operation.\n\t\t\t\t\t// This works because computeTombstonePruning ensures we never split a clock value.\n\t\t\t\t\tthis.stmts.deleteTombstonesBefore.run(result.newTombstoneHistoryStartsAtClock)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t1000,\n\t\t// prevent this from running synchronously to avoid blocking requests\n\t\t{ leading: false }\n\t)\n\n\tgetSnapshot(): RoomSnapshot {\n\t\treturn {\n\t\t\ttombstoneHistoryStartsAtClock: this._getTombstoneHistoryStartsAtClock(),\n\t\t\tdocumentClock: this.getClock(),\n\t\t\tdocuments: Array.from(this._iterateDocuments()),\n\t\t\ttombstones: Object.fromEntries(this._iterateTombstones()),\n\t\t\tschema: this._getSchema(),\n\t\t}\n\t}\n\tprivate *_iterateDocuments(): IterableIterator<{ state: R; lastChangedClock: number }> {\n\t\tfor (const row of this.stmts.iterateDocuments.iterate()) {\n\t\t\tyield { state: decodeState<R>(row.state), lastChangedClock: row.lastChangedClock }\n\t\t}\n\t}\n\n\tprivate *_iterateTombstones(): IterableIterator<[string, number]> {\n\t\tfor (const row of this.stmts.iterateTombstones.iterate()) {\n\t\t\tyield [row.id, row.clock]\n\t\t}\n\t}\n}\n\n/**\n * Transaction implementation for SQLiteSyncStorage.\n * Provides access to documents, tombstones, and metadata within a transaction.\n *\n * @internal\n */\nclass SQLiteSyncStorageTransaction<R extends UnknownRecord> implements TLSyncStorageTransaction<R> {\n\tprivate _clock: number\n\tprivate _closed = false\n\tprivate _didIncrementClock: boolean = false\n\n\tconstructor(\n\t\tprivate storage: SQLiteSyncStorage<R>,\n\t\tprivate stmts: SQLiteSyncStorage<R>['stmts']\n\t) {\n\t\tthis._clock = this.storage.getClock()\n\t}\n\n\t/** @internal */\n\tclose() {\n\t\tthis._closed = true\n\t}\n\n\tprivate assertNotClosed() {\n\t\tassert(!this._closed, 'Transaction has ended, iterator cannot be consumed')\n\t}\n\n\tgetClock(): number {\n\t\treturn this._clock\n\t}\n\n\tprivate getNextClock(): number {\n\t\tif (!this._didIncrementClock) {\n\t\t\tthis._didIncrementClock = true\n\t\t\tthis.stmts.incrementDocumentClock.run()\n\t\t\tthis._clock = this.storage.getClock()\n\t\t}\n\t\treturn this._clock\n\t}\n\n\tget(id: string): R | undefined {\n\t\tthis.assertNotClosed()\n\t\tconst row = this.stmts.getDocument.all(id)[0]\n\t\tif (!row) return undefined\n\t\treturn decodeState<R>(row.state)\n\t}\n\n\tset(id: string, record: R): void {\n\t\tthis.assertNotClosed()\n\t\tassert(id === record.id, `Record id mismatch: key does not match record.id`)\n\t\tconst clock = this.getNextClock()\n\t\t// Automatically clear tombstone if it exists\n\t\tthis.stmts.deleteTombstone.run(id)\n\t\tthis.stmts.insertDocument.run(id, encodeState(record), clock)\n\t}\n\n\tdelete(id: string): void {\n\t\tthis.assertNotClosed()\n\t\t// Only create a tombstone if the record actually exists\n\t\tconst exists = this.stmts.documentExists.all(id)[0]\n\t\tif (!exists) return\n\t\tconst clock = this.getNextClock()\n\t\tthis.stmts.deleteDocument.run(id)\n\t\tthis.stmts.insertTombstone.run(id, clock)\n\t\tthis.storage.pruneTombstones()\n\t}\n\n\t*entries(): IterableIterator<[string, R]> {\n\t\tthis.assertNotClosed()\n\t\tfor (const row of this.stmts.iterateDocumentEntries.iterate()) {\n\t\t\tthis.assertNotClosed()\n\t\t\tyield [row.id, decodeState<R>(row.state)]\n\t\t}\n\t}\n\n\t*keys(): IterableIterator<string> {\n\t\tthis.assertNotClosed()\n\t\tfor (const row of this.stmts.iterateDocumentKeys.iterate()) {\n\t\t\tthis.assertNotClosed()\n\t\t\tyield row.id\n\t\t}\n\t}\n\n\t*values(): IterableIterator<R> {\n\t\tthis.assertNotClosed()\n\t\tfor (const row of this.stmts.iterateDocumentValues.iterate()) {\n\t\t\tthis.assertNotClosed()\n\t\t\tyield decodeState<R>(row.state)\n\t\t}\n\t}\n\n\tgetSchema(): SerializedSchema {\n\t\tthis.assertNotClosed()\n\t\treturn this.storage._getSchema()\n\t}\n\n\tsetSchema(schema: SerializedSchema): void {\n\t\tthis.assertNotClosed()\n\t\tthis.storage._setSchema(schema)\n\t}\n\n\tgetChangesSince(sinceClock: number): TLSyncStorageGetChangesSinceResult<R> | undefined {\n\t\tthis.assertNotClosed()\n\t\tconst clock = this.storage.getClock()\n\t\tif (sinceClock === clock) return undefined\n\t\tif (sinceClock > clock) {\n\t\t\t// something went wrong, wipe the slate clean\n\t\t\tsinceClock = -1\n\t\t}\n\t\tconst diff: TLSyncForwardDiff<R> = { puts: {}, deletes: [] }\n\t\tconst wipeAll = sinceClock < this.storage._getTombstoneHistoryStartsAtClock()\n\n\t\tif (wipeAll) {\n\t\t\t// If wipeAll, include all documents\n\t\t\tfor (const row of this.stmts.iterateDocumentValues.iterate()) {\n\t\t\t\tconst state = decodeState<R>(row.state)\n\t\t\t\tdiff.puts[state.id] = state\n\t\t\t}\n\t\t} else {\n\t\t\t// Get documents changed since clock\n\t\t\tfor (const row of this.stmts.getDocumentsChangedSince.iterate(sinceClock)) {\n\t\t\t\tconst state = decodeState<R>(row.state)\n\t\t\t\tdiff.puts[state.id] = state\n\t\t\t}\n\t\t\t// When wipeAll, deletes are redundant (full state is in puts). Only include tombstones otherwise.\n\t\t\tfor (const row of this.stmts.getTombstonesChangedSince.iterate(sinceClock)) {\n\t\t\t\tdiff.deletes.push(row.id)\n\t\t\t}\n\t\t}\n\n\t\treturn { diff, wipeAll }\n\t}\n}\n"],
5
- "mappings": "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",
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -7,6 +7,7 @@ class ServerSocketAdapter {
7
7
  constructor(opts) {
8
8
  this.opts = opts;
9
9
  }
10
+ opts;
10
11
  /**
11
12
  * Checks if the underlying WebSocket connection is currently open and ready to send messages.
12
13
  *
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/ServerSocketAdapter.ts"],
4
4
  "sourcesContent": ["import { UnknownRecord } from '@tldraw/store'\nimport { TLSocketServerSentEvent } from './protocol'\nimport { TLRoomSocket } from './TLSyncRoom'\n\n/**\n * Minimal server-side WebSocket interface that is compatible with various WebSocket implementations.\n * This interface abstracts over different WebSocket libraries and platforms to provide a consistent\n * API for the ServerSocketAdapter.\n *\n * Supports:\n * - The standard WebSocket interface (Cloudflare, Deno, some Node.js setups)\n * - The 'ws' WebSocket interface (Node.js ws library)\n * - The Bun.serve socket implementation\n *\n * @public\n * @example\n * ```ts\n * // Standard WebSocket\n * const standardWs: WebSocketMinimal = new WebSocket('ws://localhost:8080')\n *\n * // Node.js 'ws' library WebSocket\n * import WebSocket from 'ws'\n * const nodeWs: WebSocketMinimal = new WebSocket('ws://localhost:8080')\n *\n * // Bun WebSocket (in server context)\n * // const bunWs: WebSocketMinimal = server.upgrade(request)\n * ```\n */\nexport interface WebSocketMinimal {\n\t/**\n\t * Optional method to add event listeners for WebSocket events.\n\t * Not all WebSocket implementations provide this method.\n\t *\n\t * @param type - The event type to listen for\n\t * @param listener - The event handler function\n\t */\n\t// eslint-disable-next-line tldraw/method-signature-style\n\taddEventListener?: (type: 'message' | 'close' | 'error', listener: (event: any) => void) => void\n\n\t/**\n\t * Optional method to remove event listeners for WebSocket events.\n\t * Not all WebSocket implementations provide this method.\n\t *\n\t * @param type - The event type to stop listening for\n\t * @param listener - The event handler function to remove\n\t */\n\t// eslint-disable-next-line tldraw/method-signature-style\n\tremoveEventListener?: (\n\t\ttype: 'message' | 'close' | 'error',\n\t\tlistener: (event: any) => void\n\t) => void\n\n\t/**\n\t * Sends a string message through the WebSocket connection.\n\t *\n\t * @param data - The string data to send\n\t */\n\t// eslint-disable-next-line tldraw/method-signature-style\n\tsend: (data: string) => void\n\n\t/**\n\t * Closes the WebSocket connection.\n\t *\n\t * @param code - Optional close code (default: 1000 for normal closure)\n\t * @param reason - Optional human-readable close reason\n\t */\n\t// eslint-disable-next-line tldraw/method-signature-style\n\tclose: (code?: number, reason?: string) => void\n\n\t/**\n\t * The current state of the WebSocket connection.\n\t * - 0: CONNECTING\n\t * - 1: OPEN\n\t * - 2: CLOSING\n\t * - 3: CLOSED\n\t */\n\treadyState: number\n}\n\n/**\n * Configuration options for creating a ServerSocketAdapter instance.\n *\n * @internal\n */\nexport interface ServerSocketAdapterOptions<R extends UnknownRecord> {\n\t/** The underlying WebSocket connection to wrap */\n\treadonly ws: WebSocketMinimal\n\n\t/**\n\t * Optional callback invoked before each message is sent to the client.\n\t * Useful for logging, metrics, or message transformation.\n\t *\n\t * @param msg - The message object being sent\n\t * @param stringified - The JSON stringified version of the message\n\t */\n\t// eslint-disable-next-line tldraw/method-signature-style\n\treadonly onBeforeSendMessage?: (msg: TLSocketServerSentEvent<R>, stringified: string) => void\n}\n\n/**\n * Server-side adapter that wraps various WebSocket implementations to provide a consistent\n * TLRoomSocket interface for the TLSyncRoom. This adapter handles the differences between\n * WebSocket libraries and platforms, allowing sync-core to work across different server\n * environments.\n *\n * The adapter implements the TLRoomSocket interface, providing methods for sending messages,\n * checking connection status, and closing connections.\n *\n * @internal\n * @example\n * ```ts\n * import { ServerSocketAdapter } from '@tldraw/sync-core'\n *\n * // Wrap a standard WebSocket\n * const adapter = new ServerSocketAdapter({\n * ws: webSocketConnection,\n * onBeforeSendMessage: (msg, json) => {\n * console.log('Sending:', msg.type)\n * }\n * })\n *\n * // Use with TLSyncRoom\n * room.handleNewSession({\n * sessionId: 'session-123',\n * socket: adapter,\n * isReadonly: false\n * })\n * ```\n */\nexport class ServerSocketAdapter<R extends UnknownRecord> implements TLRoomSocket<R> {\n\t/**\n\t * Creates a new ServerSocketAdapter instance.\n\t *\n\t * opts - Configuration options for the adapter\n\t */\n\tconstructor(public readonly opts: ServerSocketAdapterOptions<R>) {}\n\n\t/**\n\t * Checks if the underlying WebSocket connection is currently open and ready to send messages.\n\t *\n\t * @returns True if the connection is open (readyState === 1), false otherwise\n\t */\n\t// eslint-disable-next-line tldraw/no-setter-getter\n\tget isOpen(): boolean {\n\t\treturn this.opts.ws.readyState === 1 // ready state open\n\t}\n\n\t/**\n\t * Sends a sync protocol message to the connected client. The message is JSON stringified\n\t * before being sent through the WebSocket. If configured, the onBeforeSendMessage callback\n\t * is invoked before sending.\n\t *\n\t * @param msg - The sync protocol message to send\n\t */\n\t// see TLRoomSocket for details on why this accepts a union and not just arrays\n\tsendMessage(msg: TLSocketServerSentEvent<R>) {\n\t\tconst message = JSON.stringify(msg)\n\t\tthis.opts.onBeforeSendMessage?.(msg, message)\n\t\tthis.opts.ws.send(message)\n\t}\n\n\t/**\n\t * Closes the WebSocket connection with an optional close code and reason.\n\t *\n\t * @param code - Optional close code (default: 1000 for normal closure)\n\t * @param reason - Optional human-readable reason for closing\n\t */\n\tclose(code?: number, reason?: string) {\n\t\tthis.opts.ws.close(code, reason)\n\t}\n}\n"],
5
- "mappings": "AAiIO,MAAM,oBAAwE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMpF,YAA4B,MAAqC;AAArC;AAAA,EAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQlE,IAAI,SAAkB;AACrB,WAAO,KAAK,KAAK,GAAG,eAAe;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,YAAY,KAAiC;AAC5C,UAAM,UAAU,KAAK,UAAU,GAAG;AAClC,SAAK,KAAK,sBAAsB,KAAK,OAAO;AAC5C,SAAK,KAAK,GAAG,KAAK,OAAO;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,MAAe,QAAiB;AACrC,SAAK,KAAK,GAAG,MAAM,MAAM,MAAM;AAAA,EAChC;AACD;",
5
+ "mappings": "AAiIO,MAAM,oBAAwE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMpF,YAA4B,MAAqC;AAArC;AAAA,EAAsC;AAAA,EAAtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ5B,IAAI,SAAkB;AACrB,WAAO,KAAK,KAAK,GAAG,eAAe;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,YAAY,KAAiC;AAC5C,UAAM,UAAU,KAAK,UAAU,GAAG;AAClC,SAAK,KAAK,sBAAsB,KAAK,OAAO;AAC5C,SAAK,KAAK,GAAG,KAAK,OAAO;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,MAAe,QAAiB;AACrC,SAAK,KAAK,GAAG,MAAM,MAAM,MAAM;AAAA,EAChC;AACD;",
6
6
  "names": []
7
7
  }
@@ -11,6 +11,7 @@ class TLRemoteSyncError extends Error {
11
11
  super(`sync error: ${reason}`);
12
12
  this.reason = reason;
13
13
  }
14
+ reason;
14
15
  name = "RemoteSyncError";
15
16
  }
16
17
  export {
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/TLRemoteSyncError.ts"],
4
4
  "sourcesContent": ["import { TLSyncErrorCloseEventReason } from './TLSyncClient'\n\n/**\n * Specialized error class for synchronization-related failures in tldraw collaboration.\n *\n * This error is thrown when the sync client encounters fatal errors that prevent\n * successful synchronization with the server. It captures both the error message\n * and the specific reason code that triggered the failure.\n *\n * Common scenarios include schema version mismatches, authentication failures,\n * network connectivity issues, and server-side validation errors.\n *\n * @example\n * ```ts\n * import { TLRemoteSyncError, TLSyncErrorCloseEventReason } from '@tldraw/sync-core'\n *\n * // Handle sync errors in your application\n * syncClient.onSyncError((error) => {\n * if (error instanceof TLRemoteSyncError) {\n * switch (error.reason) {\n * case TLSyncErrorCloseEventReason.NOT_AUTHENTICATED:\n * // Redirect user to login\n * break\n * case TLSyncErrorCloseEventReason.CLIENT_TOO_OLD:\n * // Show update required message\n * break\n * default:\n * console.error('Sync error:', error.message)\n * }\n * }\n * })\n * ```\n *\n * @example\n * ```ts\n * // Server-side: throwing a sync error\n * if (!hasPermission(userId, roomId)) {\n * throw new TLRemoteSyncError(TLSyncErrorCloseEventReason.FORBIDDEN)\n * }\n * ```\n *\n * @public\n */\nexport class TLRemoteSyncError extends Error {\n\toverride name = 'RemoteSyncError'\n\n\t/**\n\t * Creates a new TLRemoteSyncError with the specified reason.\n\t *\n\t * reason - The specific reason code or custom string describing why the sync failed.\n\t * When using predefined reasons from TLSyncErrorCloseEventReason, the client\n\t * can handle specific error types appropriately. Custom strings allow for\n\t * application-specific error details.\n\t */\n\tconstructor(public readonly reason: TLSyncErrorCloseEventReason | string) {\n\t\tsuper(`sync error: ${reason}`)\n\t}\n}\n"],
5
- "mappings": "AA2CO,MAAM,0BAA0B,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW5C,YAA4B,QAA8C;AACzE,UAAM,eAAe,MAAM,EAAE;AADF;AAAA,EAE5B;AAAA,EAZS,OAAO;AAajB;",
5
+ "mappings": "AA2CO,MAAM,0BAA0B,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW5C,YAA4B,QAA8C;AACzE,UAAM,eAAe,MAAM,EAAE;AADF;AAAA,EAE5B;AAAA,EAF4B;AAAA,EAVnB,OAAO;AAajB;",
6
6
  "names": []
7
7
  }
@@ -73,6 +73,7 @@ class TLSocketRoom {
73
73
  });
74
74
  this.log = "log" in opts ? opts.log : { error: console.error };
75
75
  }
76
+ opts;
76
77
  room;
77
78
  sessions = /* @__PURE__ */ new Map();
78
79
  log;
@@ -675,6 +676,8 @@ class StoreUpdateContext {
675
676
  this.snapshot = snapshot;
676
677
  this.schema = schema;
677
678
  }
679
+ snapshot;
680
+ schema;
678
681
  updates = {
679
682
  puts: {},
680
683
  deletes: /* @__PURE__ */ new Set()
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/TLSocketRoom.ts"],
4
4
  "sourcesContent": ["import type { SerializedSchema, StoreSchema, UnknownRecord } from '@tldraw/store'\nimport { createTLSchema, TLInstancePresence, TLStoreSnapshot } from '@tldraw/tlschema'\nimport { getOwnProperty, hasOwnProperty, isEqual, structuredClone } from '@tldraw/utils'\nimport { JsonChunkAssembler } from './chunk'\nimport { DEFAULT_INITIAL_SNAPSHOT, InMemorySyncStorage } from './InMemorySyncStorage'\nimport { TLSocketServerSentEvent } from './protocol'\nimport { RoomSessionState } from './RoomSession'\nimport { ServerSocketAdapter, WebSocketMinimal } from './ServerSocketAdapter'\nimport { TLSyncErrorCloseEventReason } from './TLSyncClient'\nimport { RoomSnapshot, TLSyncRoom } from './TLSyncRoom'\nimport {\n\tconvertStoreSnapshotToRoomSnapshot,\n\tloadSnapshotIntoStorage,\n\tTLSyncStorage,\n} from './TLSyncStorage'\n\n/**\n * Strip potentially large fields from a tldraw instance_presence record so the\n * snapshot stays small when stored in WebSocket attachments (e.g. for hibernation).\n * Keeps cursor, selection, page, and user identity; clears scribbles, chatMessage, brush.\n */\nfunction stripPresenceForSnapshot(record: UnknownRecord): UnknownRecord {\n\tif (record.typeName !== 'instance_presence') return record\n\tconst stripped = { ...record } as TLInstancePresence\n\tstripped.scribbles = []\n\tstripped.chatMessage = ''\n\tstripped.selectedShapeIds = []\n\tstripped.brush = null\n\n\treturn stripped as unknown as UnknownRecord\n}\n\n/**\n * Logging interface for TLSocketRoom operations. Provides optional methods\n * for warning and error logging during synchronization operations.\n *\n * @example\n * ```ts\n * const logger: TLSyncLog = {\n * warn: (...args) => console.warn('[SYNC]', ...args),\n * error: (...args) => console.error('[SYNC]', ...args)\n * }\n *\n * const room = new TLSocketRoom({ log: logger })\n * ```\n *\n * @public\n */\nexport interface TLSyncLog {\n\t/**\n\t * Optional warning logger for non-fatal sync issues\n\t * @param args - Arguments to log\n\t */\n\twarn?(...args: any[]): void\n\t/**\n\t * Optional error logger for sync errors and failures\n\t * @param args - Arguments to log\n\t */\n\terror?(...args: any[]): void\n}\n\n/**\n * A snapshot of per-session state that can be persisted and used to resume a session\n * after the server restarts (e.g., after Cloudflare Durable Object hibernation).\n *\n * Obtain via {@link TLSocketRoom.getSessionSnapshot} and restore via\n * {@link TLSocketRoom.handleSocketResume}.\n *\n * @public\n */\nexport interface SessionStateSnapshot {\n\tserializedSchema: SerializedSchema\n\tisReadonly: boolean\n\tpresenceId: string | null\n\tpresenceRecord: UnknownRecord | null\n\trequiresLegacyRejection: boolean\n\tsupportsStringAppend: boolean\n}\n\n/**\n * Base options for TLSocketRoom.\n * @public\n */\nexport interface TLSocketRoomOptions<R extends UnknownRecord, SessionMeta> {\n\tstorage?: TLSyncStorage<R>\n\t/**\n\t * @deprecated use the storage option instead\n\t */\n\tinitialSnapshot?: RoomSnapshot | TLStoreSnapshot\n\t/**\n\t * @deprecated use the storage option with an onChange callback instead\n\t */\n\tonDataChange?(): void\n\tschema?: StoreSchema<R, any>\n\t// how long to wait for a client to communicate before disconnecting them\n\tclientTimeout?: number\n\tlog?: TLSyncLog\n\t// a callback that is called when a client is disconnected\n\t// eslint-disable-next-line tldraw/method-signature-style\n\tonSessionRemoved?: (\n\t\troom: TLSocketRoom<R, SessionMeta>,\n\t\targs: { sessionId: string; numSessionsRemaining: number; meta: SessionMeta }\n\t) => void\n\t// a callback that is called whenever a message is sent\n\t// eslint-disable-next-line tldraw/method-signature-style\n\tonBeforeSendMessage?: (args: {\n\t\tsessionId: string\n\t\t/** @internal keep the protocol private for now */\n\t\tmessage: TLSocketServerSentEvent<R>\n\t\tstringified: string\n\t\tmeta: SessionMeta\n\t}) => void\n\t// eslint-disable-next-line tldraw/method-signature-style\n\tonAfterReceiveMessage?: (args: {\n\t\tsessionId: string\n\t\t/** @internal keep the protocol private for now */\n\t\tmessage: TLSocketServerSentEvent<R>\n\t\tstringified: string\n\t\tmeta: SessionMeta\n\t}) => void\n\t/** @internal */\n\tonPresenceChange?(): void\n\t/**\n\t * When set, the room will call {@link TLSocketRoom.getSessionSnapshot} after\n\t * no message activity for a session for 5s and pass the result to this callback.\n\t * Use for persisting snapshots to WebSocket attachments (e.g. Cloudflare hibernation).\n\t * The room clears any pending snapshot when the session closes.\n\t */\n\t// eslint-disable-next-line tldraw/method-signature-style\n\tonSessionSnapshot?: (sessionId: string, snapshot: SessionStateSnapshot) => void\n}\n\n/**\n * A server-side room that manages WebSocket connections and synchronizes tldraw document state\n * between multiple clients in real-time. Each room represents a collaborative document space\n * where users can work together on drawings with automatic conflict resolution.\n *\n * TLSocketRoom handles:\n * - WebSocket connection lifecycle management\n * - Real-time synchronization of document changes\n * - Session management and presence tracking\n * - Message chunking for large payloads\n * - Automatic client timeout and cleanup\n *\n * @example\n * ```ts\n * // Basic room setup\n * const room = new TLSocketRoom({\n * onSessionRemoved: (room, { sessionId, numSessionsRemaining }) => {\n * console.log(`Client ${sessionId} disconnected, ${numSessionsRemaining} remaining`)\n * if (numSessionsRemaining === 0) {\n * room.close()\n * }\n * },\n * onDataChange: () => {\n * console.log('Document data changed, consider persisting')\n * }\n * })\n *\n * // Handle new client connections\n * room.handleSocketConnect({\n * sessionId: 'user-session-123',\n * socket: webSocket,\n * isReadonly: false\n * })\n * ```\n *\n * @example\n * ```ts\n * // Room with initial snapshot and schema\n * const room = new TLSocketRoom({\n * initialSnapshot: existingSnapshot,\n * schema: myCustomSchema,\n * clientTimeout: 30000,\n * log: {\n * warn: (...args) => logger.warn('SYNC:', ...args),\n * error: (...args) => logger.error('SYNC:', ...args)\n * }\n * })\n *\n * // Update document programmatically\n * await room.updateStore(store => {\n * const shape = store.get('shape:abc123')\n * if (shape) {\n * shape.x = 100\n * store.put(shape)\n * }\n * })\n * ```\n *\n * @public\n */\nexport class TLSocketRoom<R extends UnknownRecord = UnknownRecord, SessionMeta = void> {\n\tprivate room: TLSyncRoom<R, SessionMeta>\n\tprivate readonly sessions = new Map<\n\t\tstring,\n\t\t// eslint-disable-next-line tldraw/method-signature-style\n\t\t{ assembler: JsonChunkAssembler; socket: WebSocketMinimal; unlisten: () => void }\n\t>()\n\treadonly log?: TLSyncLog\n\n\tpublic storage: TLSyncStorage<R>\n\n\tprivate disposables = new Set<() => void>()\n\tprivate readonly snapshotTimers = new Map<string, ReturnType<typeof setTimeout>>()\n\n\t/**\n\t * Creates a new TLSocketRoom instance for managing collaborative document synchronization.\n\t *\n\t * opts - Configuration options for the room\n\t * - initialSnapshot - Optional initial document state to load\n\t * - schema - Store schema defining record types and validation\n\t * - clientTimeout - Milliseconds to wait before disconnecting inactive clients\n\t * - log - Optional logger for warnings and errors\n\t * - onSessionRemoved - Called when a client session is removed\n\t * - onBeforeSendMessage - Called before sending messages to clients\n\t * - onAfterReceiveMessage - Called after receiving messages from clients\n\t * - onDataChange - Called when document data changes\n\t * - onPresenceChange - Called when presence data changes\n\t */\n\tconstructor(public readonly opts: TLSocketRoomOptions<R, SessionMeta>) {\n\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\tif (opts.storage && opts.initialSnapshot) {\n\t\t\tthrow new Error('Cannot provide both storage and initialSnapshot options')\n\t\t}\n\t\tconst storage = opts.storage\n\t\t\t? opts.storage\n\t\t\t: new InMemorySyncStorage<R>({\n\t\t\t\t\tsnapshot: convertStoreSnapshotToRoomSnapshot(\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t\t\t\topts.initialSnapshot ?? DEFAULT_INITIAL_SNAPSHOT\n\t\t\t\t\t),\n\t\t\t\t})\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\tif ('onDataChange' in opts && opts.onDataChange) {\n\t\t\tthis.disposables.add(\n\t\t\t\tstorage.onChange(() => {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t\t\topts.onDataChange?.()\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\t\tthis.room = new TLSyncRoom<R, SessionMeta>({\n\t\t\tonPresenceChange: opts.onPresenceChange,\n\t\t\tschema: opts.schema ?? (createTLSchema() as any),\n\t\t\tlog: opts.log,\n\t\t\tstorage,\n\t\t\tclientTimeout: opts.clientTimeout,\n\t\t})\n\t\tthis.storage = storage\n\t\tthis.room.events.on('session_removed', (args) => {\n\t\t\tthis.clearSnapshotTimer(args.sessionId)\n\t\t\tthis.sessions.delete(args.sessionId)\n\t\t\tif (this.opts.onSessionRemoved) {\n\t\t\t\tthis.opts.onSessionRemoved(this, {\n\t\t\t\t\tsessionId: args.sessionId,\n\t\t\t\t\tnumSessionsRemaining: this.room.sessions.size,\n\t\t\t\t\tmeta: args.meta,\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t\tthis.log = 'log' in opts ? opts.log : { error: console.error }\n\t}\n\n\t/**\n\t * Returns the number of active sessions.\n\t * Note that this is not the same as the number of connected sockets!\n\t * Sessions time out a few moments after sockets close, to smooth over network hiccups.\n\t *\n\t * @returns the number of active sessions\n\t */\n\tgetNumActiveSessions() {\n\t\treturn this.room.sessions.size\n\t}\n\n\t/**\n\t * Handles a new client WebSocket connection, creating a session within the room.\n\t * This should be called whenever a client establishes a WebSocket connection to join\n\t * the collaborative document.\n\t *\n\t * @param opts - Connection options\n\t * - sessionId - Unique identifier for the client session (typically from browser tab)\n\t * - socket - WebSocket-like object for client communication\n\t * - isReadonly - Whether the client can modify the document (defaults to false)\n\t * - meta - Additional session metadata (required if SessionMeta is not void)\n\t *\n\t * @example\n\t * ```ts\n\t * // Handle new WebSocket connection\n\t * room.handleSocketConnect({\n\t * sessionId: 'user-session-abc123',\n\t * socket: webSocketConnection,\n\t * isReadonly: !userHasEditPermission\n\t * })\n\t * ```\n\t *\n\t * @example\n\t * ```ts\n\t * // With session metadata\n\t * room.handleSocketConnect({\n\t * sessionId: 'session-xyz',\n\t * socket: ws,\n\t * meta: { userId: 'user-123', name: 'Alice' }\n\t * })\n\t * ```\n\t */\n\thandleSocketConnect(\n\t\topts: {\n\t\t\tsessionId: string\n\t\t\tsocket: WebSocketMinimal\n\t\t\tisReadonly?: boolean\n\t\t} & (SessionMeta extends void ? object : { meta: SessionMeta })\n\t) {\n\t\tconst { sessionId, socket, isReadonly = false } = opts\n\t\tconst handleSocketMessage = (event: MessageEvent) =>\n\t\t\tthis.handleSocketMessage(sessionId, event.data)\n\t\tconst handleSocketError = this.handleSocketError.bind(this, sessionId)\n\t\tconst handleSocketClose = this.handleSocketClose.bind(this, sessionId)\n\n\t\tthis.sessions.set(sessionId, {\n\t\t\tassembler: new JsonChunkAssembler(),\n\t\t\tsocket,\n\t\t\tunlisten: () => {\n\t\t\t\tsocket.removeEventListener?.('message', handleSocketMessage)\n\t\t\t\tsocket.removeEventListener?.('close', handleSocketClose)\n\t\t\t\tsocket.removeEventListener?.('error', handleSocketError)\n\t\t\t},\n\t\t})\n\n\t\tthis.room.handleNewSession({\n\t\t\tsessionId,\n\t\t\tisReadonly,\n\t\t\tsocket: new ServerSocketAdapter({\n\t\t\t\tws: socket,\n\t\t\t\tonBeforeSendMessage: this.opts.onBeforeSendMessage\n\t\t\t\t\t? (message, stringified) =>\n\t\t\t\t\t\t\tthis.opts.onBeforeSendMessage!({\n\t\t\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\t\t\tmessage,\n\t\t\t\t\t\t\t\tstringified,\n\t\t\t\t\t\t\t\tmeta: this.room.sessions.get(sessionId)?.meta as SessionMeta,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t: undefined,\n\t\t\t}),\n\t\t\tmeta: 'meta' in opts ? (opts.meta as any) : undefined,\n\t\t})\n\n\t\tsocket.addEventListener?.('message', handleSocketMessage)\n\t\tsocket.addEventListener?.('close', handleSocketClose)\n\t\tsocket.addEventListener?.('error', handleSocketError)\n\t}\n\n\tprivate clearSnapshotTimer(sessionId: string) {\n\t\tconst t = this.snapshotTimers.get(sessionId)\n\t\tif (t) {\n\t\t\tclearTimeout(t)\n\t\t\tthis.snapshotTimers.delete(sessionId)\n\t\t}\n\t}\n\n\tprivate scheduleDebouncedSnapshot(sessionId: string) {\n\t\tif (!this.opts.onSessionSnapshot) return\n\t\tthis.clearSnapshotTimer(sessionId)\n\t\tthis.snapshotTimers.set(\n\t\t\tsessionId,\n\t\t\tsetTimeout(() => {\n\t\t\t\tthis.snapshotTimers.delete(sessionId)\n\t\t\t\tconst snapshot = this.getSessionSnapshot(sessionId)\n\t\t\t\tif (snapshot) this.opts.onSessionSnapshot!(sessionId, snapshot)\n\t\t\t}, 5000)\n\t\t)\n\t}\n\n\t/**\n\t * Processes a message received from a client WebSocket. Use this method in server\n\t * environments where WebSocket event listeners cannot be attached directly to socket\n\t * instances (e.g., Bun.serve, Cloudflare Workers with WebSocket hibernation).\n\t *\n\t * The method handles message chunking/reassembly and forwards complete messages\n\t * to the underlying sync room for processing.\n\t *\n\t * @param sessionId - Session identifier matching the one used in handleSocketConnect\n\t * @param message - Raw message data from the client (string or binary)\n\t *\n\t * @example\n\t * ```ts\n\t * // In a Bun.serve handler\n\t * server.upgrade(req, {\n\t * data: { sessionId, room },\n\t * upgrade(res, req) {\n\t * // Connection established\n\t * },\n\t * message(ws, message) {\n\t * const { sessionId, room } = ws.data\n\t * room.handleSocketMessage(sessionId, message)\n\t * }\n\t * })\n\t * ```\n\t */\n\thandleSocketMessage(sessionId: string, message: string | AllowSharedBufferSource) {\n\t\tconst assembler = this.sessions.get(sessionId)?.assembler\n\t\tif (!assembler) {\n\t\t\tthis.log?.warn?.('Received message from unknown session', sessionId)\n\t\t\treturn\n\t\t}\n\n\t\ttry {\n\t\t\tconst messageString =\n\t\t\t\ttypeof message === 'string' ? message : new TextDecoder().decode(message)\n\t\t\tconst res = assembler.handleMessage(messageString)\n\t\t\tif (!res) {\n\t\t\t\t// not enough chunks yet\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif ('data' in res) {\n\t\t\t\t// need to do this first in case the session gets removed as a result of handling the message\n\t\t\t\tif (this.opts.onAfterReceiveMessage) {\n\t\t\t\t\tconst session = this.room.sessions.get(sessionId)\n\t\t\t\t\tif (session) {\n\t\t\t\t\t\tthis.opts.onAfterReceiveMessage({\n\t\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\t\tmessage: res.data as any,\n\t\t\t\t\t\t\tstringified: res.stringified,\n\t\t\t\t\t\t\tmeta: session.meta,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis.room.handleMessage(sessionId, res.data as any)\n\t\t\t\tthis.room.pruneSessions()\n\t\t\t\tthis.scheduleDebouncedSnapshot(sessionId)\n\t\t\t} else {\n\t\t\t\tthis.log?.error?.('Error assembling message', res.error)\n\t\t\t\t// close the socket to reset the connection\n\t\t\t\tthis.handleSocketError(sessionId)\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tthis.log?.error?.(e)\n\t\t\t// here we use rejectSession rather than removeSession to support legacy clients\n\t\t\t// that use the old incompatibility_error close event\n\t\t\tthis.room.rejectSession(sessionId, TLSyncErrorCloseEventReason.UNKNOWN_ERROR)\n\t\t}\n\t}\n\n\t/**\n\t * Handles a WebSocket error for the specified session. Use this in server environments\n\t * where socket event listeners cannot be attached directly. This will initiate cleanup\n\t * and session removal for the affected client.\n\t *\n\t * @param sessionId - Session identifier matching the one used in handleSocketConnect\n\t *\n\t * @example\n\t * ```ts\n\t * // In a custom WebSocket handler\n\t * socket.addEventListener('error', () => {\n\t * room.handleSocketError(sessionId)\n\t * })\n\t * ```\n\t */\n\thandleSocketError(sessionId: string) {\n\t\tthis.clearSnapshotTimer(sessionId)\n\t\tthis.room.handleClose(sessionId)\n\t}\n\n\t/**\n\t * Handles a WebSocket close event for the specified session. Use this in server\n\t * environments where socket event listeners cannot be attached directly. This will\n\t * initiate cleanup and session removal for the disconnected client.\n\t *\n\t * @param sessionId - Session identifier matching the one used in handleSocketConnect\n\t *\n\t * @example\n\t * ```ts\n\t * // In a custom WebSocket handler\n\t * socket.addEventListener('close', () => {\n\t * room.handleSocketClose(sessionId)\n\t * })\n\t * ```\n\t */\n\thandleSocketClose(sessionId: string) {\n\t\tthis.clearSnapshotTimer(sessionId)\n\t\tthis.room.handleClose(sessionId)\n\t}\n\n\t/**\n\t * Resumes a previously-connected session directly into `Connected` state, bypassing\n\t * the connect handshake. Use this after server hibernation (e.g., Cloudflare Durable\n\t * Object hibernation) when WebSocket connections survived but all in-memory state was lost.\n\t *\n\t * The session is restored using a {@link SessionStateSnapshot} previously obtained\n\t * via {@link TLSocketRoom.getSessionSnapshot}. The client is unaware the server restarted and\n\t * continues sending messages normally.\n\t *\n\t * Unlike {@link TLSocketRoom.handleSocketConnect}, this method does NOT attach WebSocket event\n\t * listeners. In hibernation environments, events are delivered via class methods\n\t * (e.g., `webSocketMessage`) rather than `addEventListener`.\n\t *\n\t * @param opts - Resume options\n\t * - sessionId - Unique identifier for the client session\n\t * - socket - WebSocket-like object for client communication\n\t * - snapshot - Session state snapshot from {@link TLSocketRoom.getSessionSnapshot}\n\t * - meta - Additional session metadata (required if SessionMeta is not void)\n\t *\n\t * @example\n\t * ```ts\n\t * // After Cloudflare DO hibernation wake\n\t * for (const ws of ctx.getWebSockets()) {\n\t * const data = ws.deserializeAttachment()\n\t * room.handleSocketResume({\n\t * sessionId: data.sessionId,\n\t * socket: ws,\n\t * snapshot: data.snapshot,\n\t * })\n\t * }\n\t * ```\n\t */\n\thandleSocketResume(\n\t\topts: {\n\t\t\tsessionId: string\n\t\t\tsocket: WebSocketMinimal\n\t\t\tsnapshot: SessionStateSnapshot\n\t\t} & (SessionMeta extends void ? object : { meta: SessionMeta })\n\t) {\n\t\tconst { sessionId, socket, snapshot } = opts\n\n\t\tthis.sessions.set(sessionId, {\n\t\t\tassembler: new JsonChunkAssembler(),\n\t\t\tsocket,\n\t\t\tunlisten: () => {\n\t\t\t\t// no-op: hibernation environments use class methods, not addEventListener\n\t\t\t},\n\t\t})\n\n\t\tthis.room.handleResumedSession({\n\t\t\tsessionId,\n\t\t\tisReadonly: snapshot.isReadonly,\n\t\t\tserializedSchema: snapshot.serializedSchema,\n\t\t\tpresenceId: snapshot.presenceId,\n\t\t\tpresenceRecord: snapshot.presenceRecord,\n\t\t\trequiresLegacyRejection: snapshot.requiresLegacyRejection,\n\t\t\tsupportsStringAppend: snapshot.supportsStringAppend,\n\t\t\tsocket: new ServerSocketAdapter({\n\t\t\t\tws: socket,\n\t\t\t\tonBeforeSendMessage: this.opts.onBeforeSendMessage\n\t\t\t\t\t? (message, stringified) =>\n\t\t\t\t\t\t\tthis.opts.onBeforeSendMessage!({\n\t\t\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\t\t\tmessage,\n\t\t\t\t\t\t\t\tstringified,\n\t\t\t\t\t\t\t\tmeta: this.room.sessions.get(sessionId)?.meta as SessionMeta,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t: undefined,\n\t\t\t}),\n\t\t\tmeta: 'meta' in opts ? (opts.meta as any) : undefined,\n\t\t})\n\t}\n\n\t/**\n\t * Returns a snapshot of a connected session's state that can be persisted and later\n\t * used with {@link TLSocketRoom.handleSocketResume} to restore the session after hibernation.\n\t *\n\t * Returns `null` if the session doesn't exist or isn't in the `Connected` state.\n\t *\n\t * @param sessionId - The session to snapshot\n\t *\n\t * @example\n\t * ```ts\n\t * // Store snapshot in a Cloudflare WebSocket attachment\n\t * const snapshot = room.getSessionSnapshot(sessionId)\n\t * if (snapshot) {\n\t * ws.serializeAttachment({ sessionId, snapshot })\n\t * }\n\t * ```\n\t */\n\tgetSessionSnapshot(sessionId: string): SessionStateSnapshot | null {\n\t\tconst session = this.room.sessions.get(sessionId)\n\t\tif (!session || session.state !== RoomSessionState.Connected) {\n\t\t\treturn null\n\t\t}\n\n\t\tlet presenceRecord: UnknownRecord | null = null\n\t\tif (session.presenceId) {\n\t\t\tconst record = this.room.presenceStore.get(session.presenceId)\n\t\t\tif (record) {\n\t\t\t\tpresenceRecord = stripPresenceForSnapshot(record as UnknownRecord)\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tserializedSchema: session.serializedSchema,\n\t\t\tisReadonly: session.isReadonly,\n\t\t\tpresenceId: session.presenceId,\n\t\t\tpresenceRecord,\n\t\t\trequiresLegacyRejection: session.requiresLegacyRejection,\n\t\t\tsupportsStringAppend: session.supportsStringAppend,\n\t\t}\n\t}\n\n\t/**\n\t * Returns the current document clock value. The clock is a monotonically increasing\n\t * integer that increments with each document change, providing a consistent ordering\n\t * of changes across the distributed system.\n\t *\n\t * @returns The current document clock value\n\t *\n\t * @example\n\t * ```ts\n\t * const clock = room.getCurrentDocumentClock()\n\t * console.log(`Document is at version ${clock}`)\n\t * ```\n\t */\n\tgetCurrentDocumentClock() {\n\t\treturn this.storage.getClock()\n\t}\n\n\t/**\n\t * Retrieves a deeply cloned copy of a record from the document store.\n\t * Returns undefined if the record doesn't exist. The returned record is\n\t * safe to mutate without affecting the original store data.\n\t *\n\t * @param id - Unique identifier of the record to retrieve\n\t * @returns Deep clone of the record, or undefined if not found\n\t *\n\t * @example\n\t * ```ts\n\t * const shape = room.getRecord('shape:abc123')\n\t * if (shape) {\n\t * console.log('Shape position:', shape.x, shape.y)\n\t * // Safe to modify without affecting store\n\t * shape.x = 100\n\t * }\n\t * ```\n\t */\n\tgetRecord(id: string) {\n\t\treturn this.storage.transaction((txn) => {\n\t\t\treturn structuredClone(txn.get(id)) as any\n\t\t}).result as R\n\t}\n\n\t/**\n\t * Returns information about all active sessions in the room. Each session\n\t * represents a connected client with their current connection status and metadata.\n\t *\n\t * @returns Array of session information objects containing:\n\t * - sessionId - Unique session identifier\n\t * - isConnected - Whether the session has an active WebSocket connection\n\t * - isReadonly - Whether the session can modify the document\n\t * - meta - Custom session metadata\n\t *\n\t * @example\n\t * ```ts\n\t * const sessions = room.getSessions()\n\t * console.log(`Room has ${sessions.length} active sessions`)\n\t *\n\t * for (const session of sessions) {\n\t * console.log(`${session.sessionId}: ${session.isConnected ? 'online' : 'offline'}`)\n\t * if (session.isReadonly) {\n\t * console.log(' (read-only access)')\n\t * }\n\t * }\n\t * ```\n\t */\n\tgetSessions(): Array<{\n\t\tsessionId: string\n\t\tisConnected: boolean\n\t\tisReadonly: boolean\n\t\tmeta: SessionMeta\n\t}> {\n\t\treturn [...this.room.sessions.values()].map((session) => {\n\t\t\treturn {\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tisConnected: session.state === RoomSessionState.Connected,\n\t\t\t\tisReadonly: session.isReadonly,\n\t\t\t\tmeta: session.meta,\n\t\t\t}\n\t\t})\n\t}\n\n\t/**\n\t * Creates a complete snapshot of the current document state, including all records\n\t * and synchronization metadata. This snapshot can be persisted to storage and used\n\t * to restore the room state later or revert to a previous version.\n\t *\n\t * @returns Complete room snapshot including documents, clock values, and tombstones\n\t * @deprecated if you need to do this use\n\t *\n\t * @example\n\t * ```ts\n\t * // Capture current state for persistence\n\t * const snapshot = room.getCurrentSnapshot()\n\t * await saveToDatabase(roomId, JSON.stringify(snapshot))\n\t *\n\t * // Later, restore from snapshot\n\t * const savedSnapshot = JSON.parse(await loadFromDatabase(roomId))\n\t * const newRoom = new TLSocketRoom({ initialSnapshot: savedSnapshot })\n\t * ```\n\t */\n\tgetCurrentSnapshot() {\n\t\tif (this.storage.getSnapshot) {\n\t\t\treturn this.storage.getSnapshot()\n\t\t}\n\t\tthrow new Error('getCurrentSnapshot is not supported for this storage type')\n\t}\n\n\t/**\n\t * Retrieves all presence records from the document store. Presence records\n\t * contain ephemeral user state like cursor positions and selections.\n\t *\n\t * @returns Object mapping record IDs to presence record data\n\t * @internal\n\t */\n\tgetPresenceRecords() {\n\t\tconst result = {} as Record<string, UnknownRecord>\n\t\tfor (const presence of this.room.presenceStore.values()) {\n\t\t\tresult[presence.id] = presence\n\t\t}\n\t\treturn result\n\t}\n\n\t/**\n\t * Loads a document snapshot, completely replacing the current room state.\n\t * This will disconnect all current clients and update the document to match\n\t * the provided snapshot. Use this for restoring from backups or implementing\n\t * document versioning.\n\t *\n\t * @param snapshot - Room or store snapshot to load\n\t *\n\t * @example\n\t * ```ts\n\t * // Restore from a saved snapshot\n\t * const backup = JSON.parse(await loadBackup(roomId))\n\t * room.loadSnapshot(backup)\n\t *\n\t * // All clients will be disconnected and need to reconnect\n\t * // to see the restored document state\n\t * ```\n\t */\n\tloadSnapshot(snapshot: RoomSnapshot | TLStoreSnapshot) {\n\t\tthis.storage.transaction((txn) => {\n\t\t\tloadSnapshotIntoStorage(txn, this.room.schema, snapshot)\n\t\t})\n\t}\n\n\t/**\n\t * Executes a transaction to modify the document store. Changes made within the\n\t * transaction are atomic and will be synchronized to all connected clients.\n\t * The transaction provides isolation from concurrent changes until it commits.\n\t *\n\t * @param updater - Function that receives store methods to make changes\n\t * - store.get(id) - Retrieve a record (safe to mutate, but must call put() to commit)\n\t * - store.put(record) - Save a modified record\n\t * - store.getAll() - Get all records in the store\n\t * - store.delete(id) - Remove a record from the store\n\t * @returns Promise that resolves when the transaction completes\n\t *\n\t * @example\n\t * ```ts\n\t * // Update multiple shapes in a single transaction\n\t * await room.updateStore(store => {\n\t * const shape1 = store.get('shape:abc123')\n\t * const shape2 = store.get('shape:def456')\n\t *\n\t * if (shape1) {\n\t * shape1.x = 100\n\t * store.put(shape1)\n\t * }\n\t *\n\t * if (shape2) {\n\t * shape2.meta.approved = true\n\t * store.put(shape2)\n\t * }\n\t * })\n\t * ```\n\t *\n\t * @example\n\t * ```ts\n\t * // Async transaction with external API call\n\t * await room.updateStore(async store => {\n\t * const doc = store.get('document:main')\n\t * if (doc) {\n\t * doc.lastModified = await getCurrentTimestamp()\n\t * store.put(doc)\n\t * }\n\t * })\n\t * ```\n\t * @deprecated use the storage.transaction method instead\n\t */\n\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\tasync updateStore(updater: (store: RoomStoreMethods<R>) => void | Promise<void>) {\n\t\tif (this.isClosed()) {\n\t\t\tthrow new Error('Cannot update store on a closed room')\n\t\t}\n\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\tconst ctx = new StoreUpdateContext<R>(\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tObject.fromEntries(this.getCurrentSnapshot().documents.map((d) => [d.state.id, d.state])),\n\t\t\tthis.room.schema\n\t\t)\n\t\ttry {\n\t\t\tawait updater(ctx)\n\t\t} finally {\n\t\t\tctx.close()\n\t\t}\n\t\tthis.storage.transaction((txn) => {\n\t\t\tfor (const [id, record] of Object.entries(ctx.updates.puts)) {\n\t\t\t\ttxn.set(id, record as R)\n\t\t\t}\n\t\t\tfor (const id of ctx.updates.deletes) {\n\t\t\t\ttxn.delete(id)\n\t\t\t}\n\t\t})\n\t}\n\n\t/**\n\t * Sends a custom message to a specific client session. This allows sending\n\t * application-specific data that doesn't modify the document state, such as\n\t * notifications, chat messages, or custom commands.\n\t *\n\t * @param sessionId - Target session identifier\n\t * @param data - Custom payload to send (will be JSON serialized)\n\t *\n\t * @example\n\t * ```ts\n\t * // Send a notification to a specific user\n\t * room.sendCustomMessage('session-123', {\n\t * type: 'notification',\n\t * message: 'Your changes have been saved'\n\t * })\n\t *\n\t * // Send a chat message\n\t * room.sendCustomMessage('session-456', {\n\t * type: 'chat',\n\t * from: 'Alice',\n\t * text: 'Great work on this design!'\n\t * })\n\t * ```\n\t */\n\tsendCustomMessage(sessionId: string, data: any) {\n\t\tthis.room.sendCustomMessage(sessionId, data)\n\t}\n\n\t/**\n\t * Immediately removes a session from the room and closes its WebSocket connection.\n\t * The client will attempt to reconnect automatically unless a fatal reason is provided.\n\t *\n\t * @param sessionId - Session identifier to remove\n\t * @param fatalReason - Optional fatal error reason that prevents reconnection\n\t *\n\t * @example\n\t * ```ts\n\t * // Kick a user (they can reconnect)\n\t * room.closeSession('session-troublemaker')\n\t *\n\t * // Permanently ban a user\n\t * room.closeSession('session-banned', 'PERMISSION_DENIED')\n\t *\n\t * // Close session due to inactivity\n\t * room.closeSession('session-idle', 'TIMEOUT')\n\t * ```\n\t */\n\tcloseSession(sessionId: string, fatalReason?: TLSyncErrorCloseEventReason | string) {\n\t\tthis.room.rejectSession(sessionId, fatalReason)\n\t}\n\n\t/**\n\t * Closes the room and disconnects all connected clients. This should be called\n\t * when shutting down the room permanently, such as during server shutdown or\n\t * when the room is no longer needed. Once closed, the room cannot be reopened.\n\t *\n\t * @example\n\t * ```ts\n\t * // Clean shutdown when no users remain\n\t * if (room.getNumActiveSessions() === 0) {\n\t * await persistSnapshot(room.getCurrentSnapshot())\n\t * room.close()\n\t * }\n\t *\n\t * // Server shutdown\n\t * process.on('SIGTERM', () => {\n\t * for (const room of activeRooms.values()) {\n\t * room.close()\n\t * }\n\t * })\n\t * ```\n\t */\n\tclose() {\n\t\tthis.room.close()\n\t\tfor (const sessionId of this.snapshotTimers.keys()) {\n\t\t\tthis.clearSnapshotTimer(sessionId)\n\t\t}\n\t\tthis.disposables.forEach((d) => d())\n\t\tthis.disposables.clear()\n\t}\n\n\t/**\n\t * Checks whether the room has been permanently closed. Closed rooms cannot\n\t * accept new connections or process further changes.\n\t *\n\t * @returns True if the room is closed, false if still active\n\t *\n\t * @example\n\t * ```ts\n\t * if (room.isClosed()) {\n\t * console.log('Room has been shut down')\n\t * // Create a new room or redirect users\n\t * } else {\n\t * // Room is still accepting connections\n\t * room.handleSocketConnect({ sessionId, socket })\n\t * }\n\t * ```\n\t */\n\tisClosed() {\n\t\treturn this.room.isClosed()\n\t}\n}\n\n/**\n * Utility type that removes properties with void values from an object type.\n * This is used internally to conditionally require session metadata based on\n * whether SessionMeta extends void.\n *\n * @example\n * ```ts\n * type Example = { a: string, b: void, c: number }\n * type Result = OmitVoid<Example> // { a: string, c: number }\n * ```\n *\n * @public\n */\nexport type OmitVoid<T, KS extends keyof T = keyof T> = {\n\t[K in KS extends any ? (void extends T[KS] ? never : KS) : never]: T[K]\n}\n\n/**\n * Interface for making transactional changes to room store data. Used within\n * updateStore transactions to modify documents atomically.\n *\n * @example\n * ```ts\n * await room.updateStore((store) => {\n * const shape = store.get('shape:123')\n * if (shape) {\n * store.put({ ...shape, x: shape.x + 10 })\n * }\n * store.delete('shape:456')\n * })\n * ```\n *\n * @public\n * @deprecated use the storage.transaction method instead\n */\nexport interface RoomStoreMethods<R extends UnknownRecord = UnknownRecord> {\n\t/**\n\t * Add or update a record in the store.\n\t *\n\t * @param record - The record to store\n\t */\n\tput(record: R): void\n\t/**\n\t * Delete a record from the store.\n\t *\n\t * @param recordOrId - The record or record ID to delete\n\t */\n\tdelete(recordOrId: R | string): void\n\t/**\n\t * Get a record by its ID.\n\t *\n\t * @param id - The record ID\n\t * @returns The record or null if not found\n\t */\n\tget(id: string): R | null\n\t/**\n\t * Get all records in the store.\n\t *\n\t * @returns Array of all records\n\t */\n\tgetAll(): R[]\n}\n\n/**\n * @deprecated use the storage.transaction method instead\n */\n// eslint-disable-next-line @typescript-eslint/no-deprecated\nclass StoreUpdateContext<R extends UnknownRecord> implements RoomStoreMethods<R> {\n\tconstructor(\n\t\tprivate readonly snapshot: Record<string, UnknownRecord>,\n\t\tprivate readonly schema: StoreSchema<R, any>\n\t) {}\n\treadonly updates = {\n\t\tputs: {} as Record<string, UnknownRecord>,\n\t\tdeletes: new Set<string>(),\n\t}\n\tput(record: R): void {\n\t\tif (this._isClosed) throw new Error('StoreUpdateContext is closed')\n\t\tconst recordType = getOwnProperty(this.schema.types, record.typeName)\n\t\tif (!recordType) {\n\t\t\tthrow new Error(`Missing definition for record type ${record.typeName}`)\n\t\t}\n\t\tconst recordBefore = this.snapshot[record.id] ?? undefined\n\t\trecordType.validate(record, recordBefore as R)\n\n\t\tif (record.id in this.snapshot && isEqual(this.snapshot[record.id], record)) {\n\t\t\tdelete this.updates.puts[record.id]\n\t\t} else {\n\t\t\tthis.updates.puts[record.id] = structuredClone(record)\n\t\t}\n\t\tthis.updates.deletes.delete(record.id)\n\t}\n\tdelete(recordOrId: R | string): void {\n\t\tif (this._isClosed) throw new Error('StoreUpdateContext is closed')\n\t\tconst id = typeof recordOrId === 'string' ? recordOrId : recordOrId.id\n\t\tdelete this.updates.puts[id]\n\t\tif (this.snapshot[id]) {\n\t\t\tthis.updates.deletes.add(id)\n\t\t}\n\t}\n\tget(id: string): R | null {\n\t\tif (this._isClosed) throw new Error('StoreUpdateContext is closed')\n\t\tif (hasOwnProperty(this.updates.puts, id)) {\n\t\t\treturn structuredClone(this.updates.puts[id]) as R\n\t\t}\n\t\tif (this.updates.deletes.has(id)) {\n\t\t\treturn null\n\t\t}\n\t\treturn structuredClone(this.snapshot[id] ?? null) as R\n\t}\n\n\tgetAll(): R[] {\n\t\tif (this._isClosed) throw new Error('StoreUpdateContext is closed')\n\t\tconst result = Object.values(this.updates.puts)\n\t\tfor (const [id, record] of Object.entries(this.snapshot)) {\n\t\t\tif (!this.updates.deletes.has(id) && !hasOwnProperty(this.updates.puts, id)) {\n\t\t\t\tresult.push(record)\n\t\t\t}\n\t\t}\n\t\treturn structuredClone(result) as R[]\n\t}\n\n\tprivate _isClosed = false\n\tclose() {\n\t\tthis._isClosed = true\n\t}\n}\n"],
5
- "mappings": "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",
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -49,6 +49,7 @@ class TLSyncError extends Error {
49
49
  super(message);
50
50
  this.reason = reason;
51
51
  }
52
+ reason;
52
53
  }
53
54
  const PING_INTERVAL = 5e3;
54
55
  const MAX_TIME_TO_WAIT_FOR_SERVER_INTERACTION_BEFORE_RESETTING_CONNECTION = PING_INTERVAL * 2;
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/TLSyncClient.ts"],
4
4
  "sourcesContent": ["import { Signal, react, transact } from '@tldraw/state'\nimport {\n\tRecordId,\n\tRecordsDiff,\n\tStore,\n\tUnknownRecord,\n\treverseRecordsDiff,\n\tsquashRecordDiffsMutable,\n} from '@tldraw/store'\nimport {\n\tFpsScheduler,\n\texhaustiveSwitchError,\n\tisEqual,\n\tobjectMapEntries,\n\tstructuredClone,\n\tuniqueId,\n} from '@tldraw/utils'\nimport {\n\tNetworkDiff,\n\tObjectDiff,\n\tRecordOpType,\n\tapplyObjectDiff,\n\tdiffRecord,\n\tgetNetworkDiff,\n} from './diff'\nimport { interval } from './interval'\nimport {\n\tTLPushRequest,\n\tTLSocketClientSentEvent,\n\tTLSocketServerSentDataEvent,\n\tTLSocketServerSentEvent,\n\tgetTlsyncProtocolVersion,\n} from './protocol'\n\n/**\n * Function type for subscribing to events with a callback.\n * Returns an unsubscribe function to clean up the listener.\n *\n * @param cb - Callback function that receives the event value\n * @returns Function to call when you want to unsubscribe from the events\n *\n * @public\n */\nexport type SubscribingFn<T> = (cb: (val: T) => void) => () => void\n\n/** Network sync frame rate when in solo mode (no collaborators) @internal */\nconst SOLO_MODE_FPS = 1\n\n/** Network sync frame rate when in collaborative mode (with collaborators) @internal */\nconst COLLABORATIVE_MODE_FPS = 30\n\n/**\n * WebSocket close code used by the server to signal a non-recoverable sync error.\n * This close code indicates that the connection is being terminated due to an error\n * that cannot be automatically recovered from, such as authentication failures,\n * incompatible client versions, or invalid data.\n *\n * @example\n * ```ts\n * // Server-side: Close connection with specific error reason\n * socket.close(TLSyncErrorCloseEventCode, TLSyncErrorCloseEventReason.NOT_FOUND)\n *\n * // Client-side: Handle the error in your sync error handler\n * const syncClient = new TLSyncClient({\n * // ... other config\n * onSyncError: (reason) => {\n * console.error('Sync failed:', reason) // Will receive 'NOT_FOUND'\n * }\n * })\n * ```\n *\n * @public\n */\nexport const TLSyncErrorCloseEventCode = 4099 as const\n\n/**\n * Predefined reasons for server-initiated connection closures.\n * These constants represent different error conditions that can cause\n * the sync server to terminate a WebSocket connection.\n *\n * @example\n * ```ts\n * // Server usage\n * if (!user.hasPermission(roomId)) {\n * socket.close(TLSyncErrorCloseEventCode, TLSyncErrorCloseEventReason.FORBIDDEN)\n * }\n *\n * // Client error handling\n * syncClient.onSyncError((reason) => {\n * switch (reason) {\n * case TLSyncErrorCloseEventReason.NOT_FOUND:\n * showError('Room does not exist')\n * break\n * case TLSyncErrorCloseEventReason.FORBIDDEN:\n * showError('Access denied')\n * break\n * case TLSyncErrorCloseEventReason.CLIENT_TOO_OLD:\n * showError('Please update your app')\n * break\n * }\n * })\n * ```\n *\n * @public\n */\nexport const TLSyncErrorCloseEventReason = {\n\t/** Room or resource not found */\n\tNOT_FOUND: 'NOT_FOUND',\n\t/** User lacks permission to access the room */\n\tFORBIDDEN: 'FORBIDDEN',\n\t/** User authentication required or invalid */\n\tNOT_AUTHENTICATED: 'NOT_AUTHENTICATED',\n\t/** Unexpected server error occurred */\n\tUNKNOWN_ERROR: 'UNKNOWN_ERROR',\n\t/** Client protocol version too old */\n\tCLIENT_TOO_OLD: 'CLIENT_TOO_OLD',\n\t/** Server protocol version too old */\n\tSERVER_TOO_OLD: 'SERVER_TOO_OLD',\n\t/** Client sent invalid or corrupted record data */\n\tINVALID_RECORD: 'INVALID_RECORD',\n\t/** Client exceeded rate limits */\n\tRATE_LIMITED: 'RATE_LIMITED',\n\t/** Room has reached maximum capacity */\n\tROOM_FULL: 'ROOM_FULL',\n} as const\n\n/**\n * @internal\n */\nexport class TLSyncError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic reason: TLSyncErrorCloseEventReason\n\t) {\n\t\tsuper(message)\n\t}\n}\n/**\n * Union type of all possible server connection close reasons.\n * Represents the string values that can be passed when a server closes\n * a sync connection due to an error condition.\n *\n * @public\n */\nexport type TLSyncErrorCloseEventReason =\n\t(typeof TLSyncErrorCloseEventReason)[keyof typeof TLSyncErrorCloseEventReason]\n\n/**\n * Handler function for custom application messages sent through the sync protocol.\n * These are user-defined messages that can be sent between clients via the sync server,\n * separate from the standard document synchronization messages.\n *\n * @param data - Custom message payload (application-defined structure)\n *\n * @example\n * ```ts\n * const customMessageHandler: TLCustomMessageHandler = (data) => {\n * if (data.type === 'user_joined') {\n * console.log(`${data.username} joined the session`)\n * showToast(`${data.username} is now collaborating`)\n * }\n * }\n *\n * const syncClient = new TLSyncClient({\n * // ... other config\n * onCustomMessageReceived: customMessageHandler\n * })\n * ```\n *\n * @public\n */\nexport type TLCustomMessageHandler = (this: null, data: any) => void\n\n/**\n * Event object describing changes in socket connection status.\n * Contains either a basic status change or an error with details.\n *\n * @public\n */\nexport type TLSocketStatusChangeEvent =\n\t| {\n\t\t\t/** Connection came online or went offline */\n\t\t\tstatus: 'online' | 'offline'\n\t }\n\t| {\n\t\t\t/** Connection encountered an error */\n\t\t\tstatus: 'error'\n\t\t\t/** Description of the error that occurred */\n\t\t\treason: string\n\t }\n/**\n * Callback function type for listening to socket status changes.\n *\n * @param params - Event object containing the new status and optional error details\n *\n * @internal\n */\nexport type TLSocketStatusListener = (params: TLSocketStatusChangeEvent) => void\n\n/**\n * Possible connection states for a persistent client socket.\n * Represents the current connectivity status between client and server.\n *\n * @internal\n */\nexport type TLPersistentClientSocketStatus = 'online' | 'offline' | 'error'\n\n/**\n * Mode for handling presence information in sync sessions.\n * Controls whether presence data (cursors, selections) is shared with other clients.\n *\n * @public\n */\nexport type TLPresenceMode =\n\t/** No presence sharing - client operates independently */\n\t| 'solo'\n\t/** Full presence sharing - cursors and selections visible to others */\n\t| 'full'\n/**\n * Interface for persistent WebSocket-like connections used by TLSyncClient.\n * Handles automatic reconnection and provides event-based communication with the sync server.\n * Implementations should maintain connection resilience and handle network interruptions gracefully.\n *\n * @example\n * ```ts\n * class MySocketAdapter implements TLPersistentClientSocket {\n * connectionStatus: 'offline' | 'online' | 'error' = 'offline'\n *\n * sendMessage(msg: TLSocketClientSentEvent) {\n * if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n * this.ws.send(JSON.stringify(msg))\n * }\n * }\n *\n * onReceiveMessage = (callback) => {\n * // Set up message listener and return cleanup function\n * }\n *\n * restart() {\n * this.disconnect()\n * this.connect()\n * }\n * }\n * ```\n *\n * @public\n */\nexport interface TLPersistentClientSocket<\n\tClientSentMessage extends object = object,\n\tServerSentMessage extends object = object,\n> {\n\t/** Current connection state - online means actively connected and ready */\n\tconnectionStatus: 'online' | 'offline' | 'error'\n\n\t/**\n\t * Send a protocol message to the sync server\n\t * @param msg - Message to send (connect, push, ping, etc.)\n\t */\n\tsendMessage(msg: ClientSentMessage): void\n\n\t/**\n\t * Subscribe to messages received from the server\n\t * @param callback - Function called for each received message\n\t * @returns Cleanup function to remove the listener\n\t */\n\tonReceiveMessage: SubscribingFn<ServerSentMessage>\n\n\t/**\n\t * Subscribe to connection status changes\n\t * @param callback - Function called when connection status changes\n\t * @returns Cleanup function to remove the listener\n\t */\n\tonStatusChange: SubscribingFn<TLSocketStatusChangeEvent>\n\n\t/**\n\t * Force a connection restart (disconnect then reconnect)\n\t * Used for error recovery or when connection health checks fail\n\t */\n\trestart(): void\n\n\t/**\n\t * Close the connection\n\t */\n\tclose(): void\n}\n\nconst PING_INTERVAL = 5000\nconst MAX_TIME_TO_WAIT_FOR_SERVER_INTERACTION_BEFORE_RESETTING_CONNECTION = PING_INTERVAL * 2\n\n// Should connect support chunking the response to allow for large payloads?\n\nfunction getPresenceOp<R extends UnknownRecord>(\n\tlastPushedPresenceState: R | null,\n\tnextPresence: R | null\n): [typeof RecordOpType.Patch, ObjectDiff] | [typeof RecordOpType.Put, R] | undefined {\n\tif (!lastPushedPresenceState && nextPresence) {\n\t\treturn [RecordOpType.Put, nextPresence]\n\t}\n\tif (lastPushedPresenceState && nextPresence) {\n\t\tconst diff = diffRecord(lastPushedPresenceState, nextPresence)\n\t\tif (!diff) return undefined\n\t\treturn [RecordOpType.Patch, diff]\n\t}\n\treturn undefined\n}\n\n/**\n * Main client-side synchronization engine for collaborative tldraw applications.\n *\n * TLSyncClient manages bidirectional synchronization between a local tldraw Store\n * and a remote sync server. It uses an optimistic update model where local changes\n * are immediately applied for responsive UI, then sent to the server for validation\n * and distribution to other clients.\n *\n * The synchronization follows a git-like push/pull/rebase model:\n * - **Push**: Local changes are sent to server as diff operations\n * - **Pull**: Server changes are received and applied locally\n * - **Rebase**: Conflicting changes are resolved by undoing local changes,\n * applying server changes, then re-applying local changes on top\n *\n * @example\n * ```ts\n * import { TLSyncClient, ClientWebSocketAdapter } from '@tldraw/sync-core'\n * import { createTLStore } from '@tldraw/store'\n *\n * // Create store and socket\n * const store = createTLStore({ schema: mySchema })\n * const socket = new ClientWebSocketAdapter('ws://localhost:3000/sync')\n *\n * // Create sync client\n * const syncClient = new TLSyncClient({\n * store,\n * socket,\n * presence: atom(null),\n * onLoad: () => console.log('Connected and loaded'),\n * onSyncError: (reason) => console.error('Sync failed:', reason)\n * })\n *\n * // Changes to store are now automatically synchronized\n * store.put([{ id: 'shape1', type: 'geo', x: 100, y: 100 }])\n * ```\n *\n * @example\n * ```ts\n * // Advanced usage with presence and custom messages\n * const syncClient = new TLSyncClient({\n * store,\n * socket,\n * presence: atom({ cursor: { x: 0, y: 0 }, userName: 'Alice' }),\n * presenceMode: atom('full'),\n * onCustomMessageReceived: (data) => {\n * if (data.type === 'chat') {\n * showChatMessage(data.message, data.from)\n * }\n * },\n * onAfterConnect: (client, { isReadonly }) => {\n * if (isReadonly) {\n * showNotification('Connected in read-only mode')\n * }\n * }\n * })\n * ```\n *\n * @public\n */\nexport class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>> {\n\t/** The last clock time from the most recent server update */\n\tprivate lastServerClock = -1\n\tprivate lastServerInteractionTimestamp = Date.now()\n\n\t/** The queue of in-flight push requests that have not yet been acknowledged by the server */\n\tprivate pendingPushRequests: TLPushRequest<R>[] = []\n\tprivate unsentChanges: {\n\t\tnextDiff?: RecordsDiff<R>\n\t\tnextPresence?: R | null\n\t} = { nextDiff: undefined, nextPresence: undefined }\n\n\t/**\n\t * The diff of 'unconfirmed', 'optimistic' changes that have been made locally by the user if we\n\t * take this diff, reverse it, and apply that to the store, our store will match exactly the most\n\t * recent state of the server that we know about\n\t */\n\tprivate speculativeChanges: RecordsDiff<R> = {\n\t\tadded: {} as any,\n\t\tupdated: {} as any,\n\t\tremoved: {} as any,\n\t}\n\n\tprivate disposables: Array<() => void> = []\n\n\t/** Separate scheduler instance for network sync operations */\n\tprivate readonly fpsScheduler: FpsScheduler\n\n\t/** Send any unsent push requests to the server */\n\tprivate readonly sendUnsentChanges: {\n\t\t(): void\n\t\tcancel?(): void\n\t}\n\n\t/** Schedule a rebase operation */\n\tprivate readonly scheduleRebase: {\n\t\t(): void\n\t\tcancel?(): void\n\t}\n\n\t/** @internal */\n\treadonly store: S\n\t/** @internal */\n\treadonly socket: TLPersistentClientSocket<TLSocketClientSentEvent<R>, TLSocketServerSentEvent<R>>\n\n\t/** @internal */\n\treadonly presenceState: Signal<R | null> | undefined\n\t/** @internal */\n\treadonly presenceMode: Signal<TLPresenceMode> | undefined\n\n\t// isOnline is true when we have an open socket connection and we have\n\t// established a connection with the server room (i.e. we have received a 'connect' message)\n\t/** @internal */\n\tisConnectedToRoom = false\n\n\t/**\n\t * The client clock is essentially a counter for push requests Each time a push request is created\n\t * the clock is incremented. This clock is sent with the push request to the server, and the\n\t * server returns it with the response so that we can match up the response with the request.\n\t *\n\t * The clock may also be used at one point in the future to allow the client to re-send push\n\t * requests idempotently (i.e. the server will keep track of each client's clock and not execute\n\t * requests it has already handled), but at the time of writing this is neither needed nor\n\t * implemented.\n\t */\n\tprivate clientClock = 0\n\n\t/**\n\t * Callback executed immediately after successful connection to sync room.\n\t * Use this to perform any post-connection setup required for your application,\n\t * such as initializing default content or updating UI state.\n\t *\n\t * @param self - The TLSyncClient instance that connected\n\t * @param details - Connection details\n\t * - isReadonly - Whether the connection is in read-only mode\n\t */\n\tprivate readonly onAfterConnect?: (self: this, details: { isReadonly: boolean }) => void\n\n\tprivate readonly onCustomMessageReceived?: TLCustomMessageHandler\n\n\tprivate isDebugging = false\n\tprivate debug(...args: any[]) {\n\t\tif (this.isDebugging) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.debug(...args)\n\t\t}\n\t}\n\n\tprivate readonly presenceType: R['typeName'] | null\n\n\tprivate didCancel?: () => boolean\n\n\t/**\n\t * Creates a new TLSyncClient instance to manage synchronization with a remote server.\n\t *\n\t * @param config - Configuration object for the sync client\n\t * - store - The local tldraw store to synchronize\n\t * - socket - WebSocket adapter for server communication\n\t * - presence - Reactive signal containing current user's presence data\n\t * - presenceMode - Optional signal controlling presence sharing (defaults to 'full')\n\t * - onLoad - Callback fired when initial sync completes successfully\n\t * - onSyncError - Callback fired when sync fails with error reason\n\t * - onCustomMessageReceived - Optional handler for custom messages\n\t * - onAfterConnect - Optional callback fired after successful connection\n\t * - self - The TLSyncClient instance\n\t * - details - Connection details including readonly status\n\t * - didCancel - Optional function to check if sync should be cancelled\n\t */\n\tconstructor(config: {\n\t\tstore: S\n\t\tsocket: TLPersistentClientSocket<any, any>\n\t\tpresence: Signal<R | null>\n\t\tpresenceMode?: Signal<TLPresenceMode>\n\t\tonLoad(self: TLSyncClient<R, S>): void\n\t\tonSyncError(reason: string): void\n\t\tonCustomMessageReceived?: TLCustomMessageHandler\n\t\tonAfterConnect?(self: TLSyncClient<R, S>, details: { isReadonly: boolean }): void\n\t\tdidCancel?(): boolean\n\t}) {\n\t\tthis.didCancel = config.didCancel\n\n\t\tthis.presenceType = config.store.scopedTypes.presence.values().next().value ?? null\n\n\t\t// Create a separate throttle instance for network sync operations\n\t\t// This ensures sync operations have their own queue separate from UI operations\n\t\tthis.fpsScheduler = new FpsScheduler(COLLABORATIVE_MODE_FPS)\n\n\t\t// Initialize throttled methods after throttle instance is created\n\t\tthis.sendUnsentChanges = this.fpsScheduler.fpsThrottle(() => {\n\t\t\tthis.debug('sending unsent changes', {\n\t\t\t\tisConnectedToRoom: this.isConnectedToRoom,\n\t\t\t\tunsentChanges: this.unsentChanges,\n\t\t\t})\n\t\t\tif (!this.isConnectedToRoom || this.store.isPossiblyCorrupted()) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (!this.unsentChanges.nextDiff && !this.unsentChanges.nextPresence) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst diff = this.unsentChanges.nextDiff\n\t\t\t\t? (getNetworkDiff(this.unsentChanges.nextDiff) ?? undefined)\n\t\t\t\t: undefined\n\t\t\tconst presence = this.unsentChanges.nextPresence\n\t\t\t\t? getPresenceOp<R>(this.lastPushedPresenceState, this.unsentChanges.nextPresence)\n\t\t\t\t: undefined\n\n\t\t\tif (!diff && !presence) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst pushRequest: TLPushRequest<R> = {\n\t\t\t\ttype: 'push',\n\t\t\t\tclientClock: this.clientClock,\n\t\t\t\tdiff,\n\t\t\t\tpresence,\n\t\t\t}\n\n\t\t\tthis.debug('sending push request', pushRequest)\n\t\t\tthis.socket.sendMessage(pushRequest)\n\n\t\t\tif (this.unsentChanges.nextPresence) {\n\t\t\t\tthis.lastPushedPresenceState = this.unsentChanges.nextPresence\n\t\t\t}\n\t\t\tthis.clientClock++\n\t\t\tthis.pendingPushRequests.push(pushRequest)\n\t\t\tthis.unsentChanges.nextDiff = undefined\n\t\t\tthis.unsentChanges.nextPresence = undefined\n\t\t})\n\n\t\tthis.scheduleRebase = this.fpsScheduler.fpsThrottle(this.rebase)\n\n\t\tif (typeof window !== 'undefined') {\n\t\t\t;(window as any).tlsync = this\n\t\t}\n\t\tthis.store = config.store\n\t\tthis.socket = config.socket\n\t\tthis.onAfterConnect = config.onAfterConnect\n\t\tthis.onCustomMessageReceived = config.onCustomMessageReceived\n\n\t\tlet didLoad = false\n\n\t\tthis.presenceState = config.presence\n\t\tthis.presenceMode = config.presenceMode\n\n\t\tthis.disposables.push(\n\t\t\t// when local 'user' changes are made, send them to the server\n\t\t\t// or stash them locally in offline mode\n\t\t\tthis.store.listen(\n\t\t\t\t({ changes }) => {\n\t\t\t\t\tif (this.didCancel?.()) return this.close()\n\t\t\t\t\tthis.debug('received store changes', { changes })\n\t\t\t\t\tthis.push(changes)\n\t\t\t\t},\n\t\t\t\t{ source: 'user', scope: 'document' }\n\t\t\t),\n\t\t\t// when the server sends us events, handle them\n\t\t\tthis.socket.onReceiveMessage((msg) => {\n\t\t\t\tif (this.didCancel?.()) return this.close()\n\t\t\t\tthis.debug('received message from server', msg)\n\t\t\t\tthis.handleServerEvent(msg)\n\t\t\t\t// the first time we receive a message from the server, we should trigger\n\n\t\t\t\t// one of the load callbacks\n\t\t\t\tif (!didLoad) {\n\t\t\t\t\tdidLoad = true\n\t\t\t\t\tconfig.onLoad(this)\n\t\t\t\t}\n\t\t\t}),\n\t\t\t// handle switching between online and offline\n\t\t\tthis.socket.onStatusChange((ev) => {\n\t\t\t\tif (this.didCancel?.()) return this.close()\n\t\t\t\tthis.debug('socket status changed', ev.status)\n\t\t\t\tif (ev.status === 'online') {\n\t\t\t\t\tthis.sendConnectMessage()\n\t\t\t\t} else {\n\t\t\t\t\tthis.resetConnection()\n\t\t\t\t\tif (ev.status === 'error') {\n\t\t\t\t\t\tdidLoad = true\n\t\t\t\t\t\tconfig.onSyncError(ev.reason)\n\t\t\t\t\t\tthis.close()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}),\n\t\t\t// Send a ping every PING_INTERVAL ms while online\n\t\t\tinterval(() => {\n\t\t\t\tif (this.didCancel?.()) return this.close()\n\t\t\t\tthis.debug('ping loop', { isConnectedToRoom: this.isConnectedToRoom })\n\t\t\t\tif (!this.isConnectedToRoom) return\n\t\t\t\ttry {\n\t\t\t\t\tthis.socket.sendMessage({ type: 'ping' })\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.warn('ping failed, resetting', error)\n\t\t\t\t\tthis.resetConnection()\n\t\t\t\t}\n\t\t\t}, PING_INTERVAL),\n\t\t\t// Check the server connection health, reset the connection if needed\n\t\t\tinterval(() => {\n\t\t\t\tif (this.didCancel?.()) return this.close()\n\t\t\t\tthis.debug('health check loop', { isConnectedToRoom: this.isConnectedToRoom })\n\t\t\t\tif (!this.isConnectedToRoom) return\n\t\t\t\tconst timeSinceLastServerInteraction = Date.now() - this.lastServerInteractionTimestamp\n\n\t\t\t\tif (\n\t\t\t\t\ttimeSinceLastServerInteraction <\n\t\t\t\t\tMAX_TIME_TO_WAIT_FOR_SERVER_INTERACTION_BEFORE_RESETTING_CONNECTION\n\t\t\t\t) {\n\t\t\t\t\tthis.debug('health check passed', { timeSinceLastServerInteraction })\n\t\t\t\t\t// last ping was recent, so no need to take any action\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconsole.warn(`Haven't heard from the server in a while, resetting connection...`)\n\t\t\t\tthis.resetConnection()\n\t\t\t}, PING_INTERVAL * 2)\n\t\t)\n\n\t\tif (this.presenceState) {\n\t\t\tthis.disposables.push(\n\t\t\t\treact('pushPresence', () => {\n\t\t\t\t\tif (this.didCancel?.()) return this.close()\n\t\t\t\t\tconst mode = this.presenceMode?.get()\n\t\t\t\t\tthis.fpsScheduler.updateTargetFps(this.getSyncFps())\n\t\t\t\t\tif (mode !== 'full') return\n\t\t\t\t\tthis.pushPresence(this.presenceState!.get())\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\n\t\t// if the socket is already online before this client was instantiated\n\t\t// then we should send a connect message right away\n\t\tif (this.socket.connectionStatus === 'online') {\n\t\t\tthis.sendConnectMessage()\n\t\t}\n\t}\n\n\t/** @internal */\n\tlatestConnectRequestId: string | null = null\n\n\t/**\n\t * This is the first message that is sent over a newly established socket connection. And we need\n\t * to wait for the response before this client can be used.\n\t */\n\tprivate sendConnectMessage() {\n\t\tif (this.isConnectedToRoom) {\n\t\t\tconsole.error('sendConnectMessage called while already connected')\n\t\t\treturn\n\t\t}\n\t\tthis.debug('sending connect message')\n\t\tthis.latestConnectRequestId = uniqueId()\n\t\tthis.socket.sendMessage({\n\t\t\ttype: 'connect',\n\t\t\tconnectRequestId: this.latestConnectRequestId,\n\t\t\tschema: this.store.schema.serialize(),\n\t\t\tprotocolVersion: getTlsyncProtocolVersion(),\n\t\t\tlastServerClock: this.lastServerClock,\n\t\t})\n\t}\n\n\t/** Switch to offline mode */\n\tprivate resetConnection(hard = false) {\n\t\tthis.debug('resetting connection')\n\t\tif (hard) {\n\t\t\tthis.lastServerClock = 0\n\t\t}\n\t\t// kill all presence state\n\t\tconst keys = Object.keys(this.store.serialize('presence')) as any\n\t\tif (keys.length > 0) {\n\t\t\tthis.store.mergeRemoteChanges(() => {\n\t\t\t\tthis.store.remove(keys)\n\t\t\t})\n\t\t}\n\t\tthis.lastPushedPresenceState = null\n\t\tthis.isConnectedToRoom = false\n\t\tthis.pendingPushRequests = []\n\t\tthis.incomingDiffBuffer = []\n\t\tthis.unsentChanges.nextDiff = undefined\n\t\tthis.unsentChanges.nextPresence = undefined\n\t\tif (this.socket.connectionStatus === 'online') {\n\t\t\tthis.socket.restart()\n\t\t}\n\t}\n\n\t/**\n\t * Invoked when the socket connection comes online, either for the first time or as the result of\n\t * a reconnect. The goal is to rebase on the server's state and fire off a new push request for\n\t * any local changes that were made while offline.\n\t */\n\tprivate didReconnect(event: Extract<TLSocketServerSentEvent<R>, { type: 'connect' }>) {\n\t\tthis.debug('did reconnect', event)\n\t\tif (event.connectRequestId !== this.latestConnectRequestId) {\n\t\t\t// ignore connect events for old connect requests\n\t\t\treturn\n\t\t}\n\t\tthis.latestConnectRequestId = null\n\n\t\tif (this.isConnectedToRoom) {\n\t\t\tconsole.error('didReconnect called while already connected')\n\t\t\tthis.resetConnection(true)\n\t\t\treturn\n\t\t}\n\t\tif (this.pendingPushRequests.length > 0) {\n\t\t\tconsole.error('pendingPushRequests should already be empty when we reconnect')\n\t\t\tthis.resetConnection(true)\n\t\t\treturn\n\t\t}\n\t\t// at the end of this process we want to have at most one pending push request\n\t\t// based on anything inside this.speculativeChanges\n\t\ttransact(() => {\n\t\t\t// Now our goal is to rebase on the server's state.\n\t\t\t// This means wiping away any peer presence data, which the server will replace in full on every connect.\n\t\t\t// If the server does not have enough history to give us a partial document state hydration we will\n\t\t\t// also need to wipe away all of our document state before hydrating with the server's state from scratch.\n\t\t\tconst stashedChanges = this.speculativeChanges\n\t\t\tthis.speculativeChanges = { added: {} as any, updated: {} as any, removed: {} as any }\n\n\t\t\tthis.store.mergeRemoteChanges(() => {\n\t\t\t\t// gather records to delete in a NetworkDiff\n\t\t\t\tconst wipeDiff: NetworkDiff<R> = {}\n\t\t\t\tconst wipeAll = event.hydrationType === 'wipe_all'\n\t\t\t\tif (!wipeAll) {\n\t\t\t\t\t// if we're only wiping presence data, undo the speculative changes first\n\t\t\t\t\tthis.store.applyDiff(reverseRecordsDiff(stashedChanges), { runCallbacks: false })\n\t\t\t\t}\n\n\t\t\t\t// now wipe all presence data and, if needed, all document data\n\t\t\t\tfor (const [id, record] of objectMapEntries(this.store.serialize('all'))) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t(wipeAll && this.store.scopedTypes.document.has(record.typeName)) ||\n\t\t\t\t\t\trecord.typeName === this.presenceType\n\t\t\t\t\t) {\n\t\t\t\t\t\twipeDiff[id] = [RecordOpType.Remove]\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// then apply the upstream changes\n\t\t\t\tthis.applyNetworkDiff({ ...wipeDiff, ...event.diff }, true)\n\n\t\t\t\tthis.isConnectedToRoom = true\n\n\t\t\t\t// now re-apply the speculative changes creating a new push request with the\n\t\t\t\t// appropriate diff\n\t\t\t\tconst networkDiff = getNetworkDiff(stashedChanges)\n\t\t\t\tif (!networkDiff) return\n\t\t\t\tconst speculativeChanges = this.store.filterChangesByScope(\n\t\t\t\t\tthis.store.extractingChanges(() => {\n\t\t\t\t\t\tthis.applyNetworkDiff(networkDiff, true)\n\t\t\t\t\t}),\n\t\t\t\t\t'document'\n\t\t\t\t)\n\t\t\t\tif (speculativeChanges) this.push(speculativeChanges)\n\t\t\t})\n\n\t\t\t// this.isConnectedToRoom = true\n\t\t\t// this.store.applyDiff(stashedChanges, false)\n\n\t\t\tthis.onAfterConnect?.(this, { isReadonly: event.isReadonly })\n\t\t\tconst presence = this.presenceState?.get()\n\t\t\tif (presence) {\n\t\t\t\tthis.pushPresence(presence)\n\t\t\t}\n\t\t})\n\n\t\tthis.lastServerClock = event.serverClock\n\t}\n\n\tprivate incomingDiffBuffer: TLSocketServerSentDataEvent<R>[] = []\n\n\t/** Handle events received from the server */\n\tprivate handleServerEvent(event: TLSocketServerSentEvent<R>) {\n\t\tthis.debug('received server event', event)\n\t\tthis.lastServerInteractionTimestamp = Date.now()\n\t\t// always update the lastServerClock when it is present\n\t\tswitch (event.type) {\n\t\t\tcase 'connect':\n\t\t\t\tthis.didReconnect(event)\n\t\t\t\tbreak\n\t\t\t// legacy v4 events\n\t\t\tcase 'patch':\n\t\t\tcase 'push_result':\n\t\t\t\tif (!this.isConnectedToRoom) break\n\t\t\t\tthis.incomingDiffBuffer.push(event)\n\t\t\t\tthis.scheduleRebase()\n\t\t\t\tbreak\n\t\t\tcase 'data':\n\t\t\t\t// wait for a connect to succeed before processing more events\n\t\t\t\tif (!this.isConnectedToRoom) break\n\t\t\t\tthis.incomingDiffBuffer.push(...event.data)\n\t\t\t\tthis.scheduleRebase()\n\t\t\t\tbreak\n\t\t\tcase 'incompatibility_error':\n\t\t\t\t// legacy unrecoverable errors\n\t\t\t\tconsole.error('incompatibility error is legacy and should no longer be sent by the server')\n\t\t\t\tbreak\n\t\t\tcase 'pong':\n\t\t\t\t// noop, we only use ping/pong to set lastSeverInteractionTimestamp\n\t\t\t\tbreak\n\t\t\tcase 'custom':\n\t\t\t\tthis.onCustomMessageReceived?.call(null, event.data)\n\t\t\t\tbreak\n\n\t\t\tdefault:\n\t\t\t\texhaustiveSwitchError(event)\n\t\t}\n\t}\n\n\t/**\n\t * Closes the sync client and cleans up all resources.\n\t *\n\t * Call this method when you no longer need the sync client to prevent\n\t * memory leaks and close the WebSocket connection. After calling close(),\n\t * the client cannot be reused.\n\t *\n\t * @example\n\t * ```ts\n\t * // Clean shutdown\n\t * syncClient.close()\n\t * ```\n\t */\n\tclose() {\n\t\tthis.debug('closing')\n\t\tthis.disposables.forEach((dispose) => dispose())\n\t\tthis.sendUnsentChanges.cancel?.()\n\t\tthis.scheduleRebase.cancel?.()\n\t}\n\n\tprivate lastPushedPresenceState: R | null = null\n\n\tprivate pushPresence(nextPresence: R | null) {\n\t\t// make sure we push any document changes first\n\t\tthis.store._flushHistory()\n\n\t\tif (!this.isConnectedToRoom) {\n\t\t\t// if we're offline, don't do anything\n\t\t\treturn\n\t\t}\n\n\t\tthis.unsentChanges.nextPresence = nextPresence\n\t\tthis.sendUnsentChanges()\n\t}\n\n\t/** Push a change to the server, or stash it locally if we're offline */\n\tprivate push(change: RecordsDiff<any>) {\n\t\tthis.debug('push', change)\n\t\tsquashRecordDiffsMutable(this.speculativeChanges, [change])\n\t\t// in offline mode, we only accumulate in speculativeChanges\n\t\tif (!this.isConnectedToRoom) return\n\t\tif (!this.unsentChanges.nextDiff) {\n\t\t\tthis.unsentChanges.nextDiff = structuredClone(change)\n\t\t} else {\n\t\t\tsquashRecordDiffsMutable(this.unsentChanges.nextDiff, [change])\n\t\t}\n\t\tthis.sendUnsentChanges()\n\t}\n\n\t/** Get the target FPS for network operations based on presence mode */\n\tprivate getSyncFps(): number {\n\t\treturn this.presenceMode?.get() === 'solo' ? SOLO_MODE_FPS : COLLABORATIVE_MODE_FPS\n\t}\n\n\t/**\n\t * Applies a 'network' diff to the store this does value-based equality checking so that if the\n\t * data is the same (as opposed to merely identical with ===), then no change is made and no\n\t * changes will be propagated back to store listeners\n\t */\n\tprivate applyNetworkDiff(diff: NetworkDiff<R>, runCallbacks: boolean) {\n\t\tthis.debug('applyNetworkDiff', diff)\n\t\tconst changes: RecordsDiff<R> = { added: {} as any, updated: {} as any, removed: {} as any }\n\t\ttype k = keyof typeof changes.updated\n\t\tlet hasChanges = false\n\t\tfor (const [id, op] of objectMapEntries(diff)) {\n\t\t\tif (op[0] === RecordOpType.Put) {\n\t\t\t\tconst existing = this.store.get(id as RecordId<any>)\n\t\t\t\tif (existing && !isEqual(existing, op[1])) {\n\t\t\t\t\thasChanges = true\n\t\t\t\t\tchanges.updated[id as k] = [existing, op[1]]\n\t\t\t\t} else {\n\t\t\t\t\thasChanges = true\n\t\t\t\t\tchanges.added[id as k] = op[1]\n\t\t\t\t}\n\t\t\t} else if (op[0] === RecordOpType.Patch) {\n\t\t\t\tconst record = this.store.get(id as RecordId<any>)\n\t\t\t\tif (!record) {\n\t\t\t\t\t// the record was removed upstream\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst patched = applyObjectDiff(record, op[1])\n\t\t\t\thasChanges = true\n\t\t\t\tchanges.updated[id as k] = [record, patched]\n\t\t\t} else if (op[0] === RecordOpType.Remove) {\n\t\t\t\tif (this.store.has(id as RecordId<any>)) {\n\t\t\t\t\thasChanges = true\n\t\t\t\t\tchanges.removed[id as k] = this.store.get(id as RecordId<any>)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (hasChanges) {\n\t\t\tthis.store.applyDiff(changes, { runCallbacks })\n\t\t}\n\t}\n\n\t// eslint-disable-next-line tldraw/prefer-class-methods\n\tprivate rebase = () => {\n\t\t// need to make sure that our speculative changes are in sync with the actual store instance before\n\t\t// proceeding, to avoid inconsistency bugs.\n\t\tthis.store._flushHistory()\n\t\tif (this.incomingDiffBuffer.length === 0) return\n\n\t\tconst diffs = this.incomingDiffBuffer\n\t\tthis.incomingDiffBuffer = []\n\n\t\ttry {\n\t\t\tthis.store.mergeRemoteChanges(() => {\n\t\t\t\t// first undo speculative changes\n\t\t\t\tthis.store.applyDiff(reverseRecordsDiff(this.speculativeChanges), { runCallbacks: false })\n\n\t\t\t\t// then apply network diffs on top of known-to-be-synced data\n\t\t\t\tfor (const diff of diffs) {\n\t\t\t\t\tif (diff.type === 'patch') {\n\t\t\t\t\t\tthis.applyNetworkDiff(diff.diff, true)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\t// handling push_result\n\t\t\t\t\tif (this.pendingPushRequests.length === 0) {\n\t\t\t\t\t\tthrow new Error('Received push_result but there are no pending push requests')\n\t\t\t\t\t}\n\t\t\t\t\tif (this.pendingPushRequests[0].clientClock !== diff.clientClock) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t'Received push_result for a push request that is not at the front of the queue'\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\tif (diff.action === 'discard') {\n\t\t\t\t\t\tthis.pendingPushRequests.shift()\n\t\t\t\t\t} else if (diff.action === 'commit') {\n\t\t\t\t\t\tconst request = this.pendingPushRequests.shift()!\n\t\t\t\t\t\tif ('diff' in request && request.diff) {\n\t\t\t\t\t\t\tthis.applyNetworkDiff(request.diff, true)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.applyNetworkDiff(diff.action.rebaseWithDiff, true)\n\t\t\t\t\t\tthis.pendingPushRequests.shift()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// update the speculative diff while re-applying pending changes\n\t\t\t\ttry {\n\t\t\t\t\tthis.speculativeChanges = this.store.extractingChanges(() => {\n\t\t\t\t\t\tfor (const request of this.pendingPushRequests) {\n\t\t\t\t\t\t\tif (!('diff' in request) || !request.diff) continue\n\t\t\t\t\t\t\tthis.applyNetworkDiff(request.diff, true)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!this.unsentChanges.nextDiff) return\n\t\t\t\t\t\tconst diff = getNetworkDiff(this.unsentChanges.nextDiff)\n\t\t\t\t\t\tif (!diff) return\n\t\t\t\t\t\tthis.applyNetworkDiff(diff, true)\n\t\t\t\t\t})\n\t\t\t\t} catch (e) {\n\t\t\t\t\tconsole.error(e)\n\t\t\t\t\t// throw away the speculative changes and start over\n\t\t\t\t\tthis.speculativeChanges = { added: {} as any, updated: {} as any, removed: {} as any }\n\t\t\t\t\tthis.resetConnection()\n\t\t\t\t}\n\t\t\t})\n\t\t\tthis.lastServerClock = diffs.at(-1)?.serverClock ?? this.lastServerClock\n\t\t} catch (e) {\n\t\t\tconsole.error(e)\n\t\t\tthis.store.ensureStoreIsUsable()\n\t\t\tthis.resetConnection()\n\t\t}\n\t}\n}\n"],
5
- "mappings": "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",
5
+ "mappings": "AAAA,SAAiB,OAAO,gBAAgB;AACxC;AAAA,EAKC;AAAA,EACA;AAAA,OACM;AACP;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP;AAAA,EAGC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,gBAAgB;AACzB;AAAA,EAKC;AAAA,OACM;AAcP,MAAM,gBAAgB;AAGtB,MAAM,yBAAyB;AAwBxB,MAAM,4BAA4B;AAgClC,MAAM,8BAA8B;AAAA;AAAA,EAE1C,WAAW;AAAA;AAAA,EAEX,WAAW;AAAA;AAAA,EAEX,mBAAmB;AAAA;AAAA,EAEnB,eAAe;AAAA;AAAA,EAEf,gBAAgB;AAAA;AAAA,EAEhB,gBAAgB;AAAA;AAAA,EAEhB,gBAAgB;AAAA;AAAA,EAEhB,cAAc;AAAA;AAAA,EAEd,WAAW;AACZ;AAKO,MAAM,oBAAoB,MAAM;AAAA,EACtC,YACC,SACO,QACN;AACD,UAAM,OAAO;AAFN;AAAA,EAGR;AAAA,EAHQ;AAIT;AAsJA,MAAM,gBAAgB;AACtB,MAAM,sEAAsE,gBAAgB;AAI5F,SAAS,cACR,yBACA,cACqF;AACrF,MAAI,CAAC,2BAA2B,cAAc;AAC7C,WAAO,CAAC,aAAa,KAAK,YAAY;AAAA,EACvC;AACA,MAAI,2BAA2B,cAAc;AAC5C,UAAM,OAAO,WAAW,yBAAyB,YAAY;AAC7D,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO,CAAC,aAAa,OAAO,IAAI;AAAA,EACjC;AACA,SAAO;AACR;AA6DO,MAAM,aAAqE;AAAA;AAAA,EAEzE,kBAAkB;AAAA,EAClB,iCAAiC,KAAK,IAAI;AAAA;AAAA,EAG1C,sBAA0C,CAAC;AAAA,EAC3C,gBAGJ,EAAE,UAAU,QAAW,cAAc,OAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO3C,qBAAqC;AAAA,IAC5C,OAAO,CAAC;AAAA,IACR,SAAS,CAAC;AAAA,IACV,SAAS,CAAC;AAAA,EACX;AAAA,EAEQ,cAAiC,CAAC;AAAA;AAAA,EAGzB;AAAA;AAAA,EAGA;AAAA;AAAA,EAMA;AAAA;AAAA,EAMR;AAAA;AAAA,EAEA;AAAA;AAAA,EAGA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA,EAKT,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYZ,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWL;AAAA,EAEA;AAAA,EAET,cAAc;AAAA,EACd,SAAS,MAAa;AAC7B,QAAI,KAAK,aAAa;AAErB,cAAQ,MAAM,GAAG,IAAI;AAAA,IACtB;AAAA,EACD;AAAA,EAEiB;AAAA,EAET;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBR,YAAY,QAUT;AACF,SAAK,YAAY,OAAO;AAExB,SAAK,eAAe,OAAO,MAAM,YAAY,SAAS,OAAO,EAAE,KAAK,EAAE,SAAS;AAI/E,SAAK,eAAe,IAAI,aAAa,sBAAsB;AAG3D,SAAK,oBAAoB,KAAK,aAAa,YAAY,MAAM;AAC5D,WAAK,MAAM,0BAA0B;AAAA,QACpC,mBAAmB,KAAK;AAAA,QACxB,eAAe,KAAK;AAAA,MACrB,CAAC;AACD,UAAI,CAAC,KAAK,qBAAqB,KAAK,MAAM,oBAAoB,GAAG;AAChE;AAAA,MACD;AACA,UAAI,CAAC,KAAK,cAAc,YAAY,CAAC,KAAK,cAAc,cAAc;AACrE;AAAA,MACD;AACA,YAAM,OAAO,KAAK,cAAc,WAC5B,eAAe,KAAK,cAAc,QAAQ,KAAK,SAChD;AACH,YAAM,WAAW,KAAK,cAAc,eACjC,cAAiB,KAAK,yBAAyB,KAAK,cAAc,YAAY,IAC9E;AAEH,UAAI,CAAC,QAAQ,CAAC,UAAU;AACvB;AAAA,MACD;AAEA,YAAM,cAAgC;AAAA,QACrC,MAAM;AAAA,QACN,aAAa,KAAK;AAAA,QAClB;AAAA,QACA;AAAA,MACD;AAEA,WAAK,MAAM,wBAAwB,WAAW;AAC9C,WAAK,OAAO,YAAY,WAAW;AAEnC,UAAI,KAAK,cAAc,cAAc;AACpC,aAAK,0BAA0B,KAAK,cAAc;AAAA,MACnD;AACA,WAAK;AACL,WAAK,oBAAoB,KAAK,WAAW;AACzC,WAAK,cAAc,WAAW;AAC9B,WAAK,cAAc,eAAe;AAAA,IACnC,CAAC;AAED,SAAK,iBAAiB,KAAK,aAAa,YAAY,KAAK,MAAM;AAE/D,QAAI,OAAO,WAAW,aAAa;AAClC;AAAC,MAAC,OAAe,SAAS;AAAA,IAC3B;AACA,SAAK,QAAQ,OAAO;AACpB,SAAK,SAAS,OAAO;AACrB,SAAK,iBAAiB,OAAO;AAC7B,SAAK,0BAA0B,OAAO;AAEtC,QAAI,UAAU;AAEd,SAAK,gBAAgB,OAAO;AAC5B,SAAK,eAAe,OAAO;AAE3B,SAAK,YAAY;AAAA;AAAA;AAAA,MAGhB,KAAK,MAAM;AAAA,QACV,CAAC,EAAE,QAAQ,MAAM;AAChB,cAAI,KAAK,YAAY,EAAG,QAAO,KAAK,MAAM;AAC1C,eAAK,MAAM,0BAA0B,EAAE,QAAQ,CAAC;AAChD,eAAK,KAAK,OAAO;AAAA,QAClB;AAAA,QACA,EAAE,QAAQ,QAAQ,OAAO,WAAW;AAAA,MACrC;AAAA;AAAA,MAEA,KAAK,OAAO,iBAAiB,CAAC,QAAQ;AACrC,YAAI,KAAK,YAAY,EAAG,QAAO,KAAK,MAAM;AAC1C,aAAK,MAAM,gCAAgC,GAAG;AAC9C,aAAK,kBAAkB,GAAG;AAI1B,YAAI,CAAC,SAAS;AACb,oBAAU;AACV,iBAAO,OAAO,IAAI;AAAA,QACnB;AAAA,MACD,CAAC;AAAA;AAAA,MAED,KAAK,OAAO,eAAe,CAAC,OAAO;AAClC,YAAI,KAAK,YAAY,EAAG,QAAO,KAAK,MAAM;AAC1C,aAAK,MAAM,yBAAyB,GAAG,MAAM;AAC7C,YAAI,GAAG,WAAW,UAAU;AAC3B,eAAK,mBAAmB;AAAA,QACzB,OAAO;AACN,eAAK,gBAAgB;AACrB,cAAI,GAAG,WAAW,SAAS;AAC1B,sBAAU;AACV,mBAAO,YAAY,GAAG,MAAM;AAC5B,iBAAK,MAAM;AAAA,UACZ;AAAA,QACD;AAAA,MACD,CAAC;AAAA;AAAA,MAED,SAAS,MAAM;AACd,YAAI,KAAK,YAAY,EAAG,QAAO,KAAK,MAAM;AAC1C,aAAK,MAAM,aAAa,EAAE,mBAAmB,KAAK,kBAAkB,CAAC;AACrE,YAAI,CAAC,KAAK,kBAAmB;AAC7B,YAAI;AACH,eAAK,OAAO,YAAY,EAAE,MAAM,OAAO,CAAC;AAAA,QACzC,SAAS,OAAO;AACf,kBAAQ,KAAK,0BAA0B,KAAK;AAC5C,eAAK,gBAAgB;AAAA,QACtB;AAAA,MACD,GAAG,aAAa;AAAA;AAAA,MAEhB,SAAS,MAAM;AACd,YAAI,KAAK,YAAY,EAAG,QAAO,KAAK,MAAM;AAC1C,aAAK,MAAM,qBAAqB,EAAE,mBAAmB,KAAK,kBAAkB,CAAC;AAC7E,YAAI,CAAC,KAAK,kBAAmB;AAC7B,cAAM,iCAAiC,KAAK,IAAI,IAAI,KAAK;AAEzD,YACC,iCACA,qEACC;AACD,eAAK,MAAM,uBAAuB,EAAE,+BAA+B,CAAC;AAEpE;AAAA,QACD;AAEA,gBAAQ,KAAK,mEAAmE;AAChF,aAAK,gBAAgB;AAAA,MACtB,GAAG,gBAAgB,CAAC;AAAA,IACrB;AAEA,QAAI,KAAK,eAAe;AACvB,WAAK,YAAY;AAAA,QAChB,MAAM,gBAAgB,MAAM;AAC3B,cAAI,KAAK,YAAY,EAAG,QAAO,KAAK,MAAM;AAC1C,gBAAM,OAAO,KAAK,cAAc,IAAI;AACpC,eAAK,aAAa,gBAAgB,KAAK,WAAW,CAAC;AACnD,cAAI,SAAS,OAAQ;AACrB,eAAK,aAAa,KAAK,cAAe,IAAI,CAAC;AAAA,QAC5C,CAAC;AAAA,MACF;AAAA,IACD;AAIA,QAAI,KAAK,OAAO,qBAAqB,UAAU;AAC9C,WAAK,mBAAmB;AAAA,IACzB;AAAA,EACD;AAAA;AAAA,EAGA,yBAAwC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhC,qBAAqB;AAC5B,QAAI,KAAK,mBAAmB;AAC3B,cAAQ,MAAM,mDAAmD;AACjE;AAAA,IACD;AACA,SAAK,MAAM,yBAAyB;AACpC,SAAK,yBAAyB,SAAS;AACvC,SAAK,OAAO,YAAY;AAAA,MACvB,MAAM;AAAA,MACN,kBAAkB,KAAK;AAAA,MACvB,QAAQ,KAAK,MAAM,OAAO,UAAU;AAAA,MACpC,iBAAiB,yBAAyB;AAAA,MAC1C,iBAAiB,KAAK;AAAA,IACvB,CAAC;AAAA,EACF;AAAA;AAAA,EAGQ,gBAAgB,OAAO,OAAO;AACrC,SAAK,MAAM,sBAAsB;AACjC,QAAI,MAAM;AACT,WAAK,kBAAkB;AAAA,IACxB;AAEA,UAAM,OAAO,OAAO,KAAK,KAAK,MAAM,UAAU,UAAU,CAAC;AACzD,QAAI,KAAK,SAAS,GAAG;AACpB,WAAK,MAAM,mBAAmB,MAAM;AACnC,aAAK,MAAM,OAAO,IAAI;AAAA,MACvB,CAAC;AAAA,IACF;AACA,SAAK,0BAA0B;AAC/B,SAAK,oBAAoB;AACzB,SAAK,sBAAsB,CAAC;AAC5B,SAAK,qBAAqB,CAAC;AAC3B,SAAK,cAAc,WAAW;AAC9B,SAAK,cAAc,eAAe;AAClC,QAAI,KAAK,OAAO,qBAAqB,UAAU;AAC9C,WAAK,OAAO,QAAQ;AAAA,IACrB;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,aAAa,OAAiE;AACrF,SAAK,MAAM,iBAAiB,KAAK;AACjC,QAAI,MAAM,qBAAqB,KAAK,wBAAwB;AAE3D;AAAA,IACD;AACA,SAAK,yBAAyB;AAE9B,QAAI,KAAK,mBAAmB;AAC3B,cAAQ,MAAM,6CAA6C;AAC3D,WAAK,gBAAgB,IAAI;AACzB;AAAA,IACD;AACA,QAAI,KAAK,oBAAoB,SAAS,GAAG;AACxC,cAAQ,MAAM,+DAA+D;AAC7E,WAAK,gBAAgB,IAAI;AACzB;AAAA,IACD;AAGA,aAAS,MAAM;AAKd,YAAM,iBAAiB,KAAK;AAC5B,WAAK,qBAAqB,EAAE,OAAO,CAAC,GAAU,SAAS,CAAC,GAAU,SAAS,CAAC,EAAS;AAErF,WAAK,MAAM,mBAAmB,MAAM;AAEnC,cAAM,WAA2B,CAAC;AAClC,cAAM,UAAU,MAAM,kBAAkB;AACxC,YAAI,CAAC,SAAS;AAEb,eAAK,MAAM,UAAU,mBAAmB,cAAc,GAAG,EAAE,cAAc,MAAM,CAAC;AAAA,QACjF;AAGA,mBAAW,CAAC,IAAI,MAAM,KAAK,iBAAiB,KAAK,MAAM,UAAU,KAAK,CAAC,GAAG;AACzE,cACE,WAAW,KAAK,MAAM,YAAY,SAAS,IAAI,OAAO,QAAQ,KAC/D,OAAO,aAAa,KAAK,cACxB;AACD,qBAAS,EAAE,IAAI,CAAC,aAAa,MAAM;AAAA,UACpC;AAAA,QACD;AAGA,aAAK,iBAAiB,EAAE,GAAG,UAAU,GAAG,MAAM,KAAK,GAAG,IAAI;AAE1D,aAAK,oBAAoB;AAIzB,cAAM,cAAc,eAAe,cAAc;AACjD,YAAI,CAAC,YAAa;AAClB,cAAM,qBAAqB,KAAK,MAAM;AAAA,UACrC,KAAK,MAAM,kBAAkB,MAAM;AAClC,iBAAK,iBAAiB,aAAa,IAAI;AAAA,UACxC,CAAC;AAAA,UACD;AAAA,QACD;AACA,YAAI,mBAAoB,MAAK,KAAK,kBAAkB;AAAA,MACrD,CAAC;AAKD,WAAK,iBAAiB,MAAM,EAAE,YAAY,MAAM,WAAW,CAAC;AAC5D,YAAM,WAAW,KAAK,eAAe,IAAI;AACzC,UAAI,UAAU;AACb,aAAK,aAAa,QAAQ;AAAA,MAC3B;AAAA,IACD,CAAC;AAED,SAAK,kBAAkB,MAAM;AAAA,EAC9B;AAAA,EAEQ,qBAAuD,CAAC;AAAA;AAAA,EAGxD,kBAAkB,OAAmC;AAC5D,SAAK,MAAM,yBAAyB,KAAK;AACzC,SAAK,iCAAiC,KAAK,IAAI;AAE/C,YAAQ,MAAM,MAAM;AAAA,MACnB,KAAK;AACJ,aAAK,aAAa,KAAK;AACvB;AAAA;AAAA,MAED,KAAK;AAAA,MACL,KAAK;AACJ,YAAI,CAAC,KAAK,kBAAmB;AAC7B,aAAK,mBAAmB,KAAK,KAAK;AAClC,aAAK,eAAe;AACpB;AAAA,MACD,KAAK;AAEJ,YAAI,CAAC,KAAK,kBAAmB;AAC7B,aAAK,mBAAmB,KAAK,GAAG,MAAM,IAAI;AAC1C,aAAK,eAAe;AACpB;AAAA,MACD,KAAK;AAEJ,gBAAQ,MAAM,4EAA4E;AAC1F;AAAA,MACD,KAAK;AAEJ;AAAA,MACD,KAAK;AACJ,aAAK,yBAAyB,KAAK,MAAM,MAAM,IAAI;AACnD;AAAA,MAED;AACC,8BAAsB,KAAK;AAAA,IAC7B;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,QAAQ;AACP,SAAK,MAAM,SAAS;AACpB,SAAK,YAAY,QAAQ,CAAC,YAAY,QAAQ,CAAC;AAC/C,SAAK,kBAAkB,SAAS;AAChC,SAAK,eAAe,SAAS;AAAA,EAC9B;AAAA,EAEQ,0BAAoC;AAAA,EAEpC,aAAa,cAAwB;AAE5C,SAAK,MAAM,cAAc;AAEzB,QAAI,CAAC,KAAK,mBAAmB;AAE5B;AAAA,IACD;AAEA,SAAK,cAAc,eAAe;AAClC,SAAK,kBAAkB;AAAA,EACxB;AAAA;AAAA,EAGQ,KAAK,QAA0B;AACtC,SAAK,MAAM,QAAQ,MAAM;AACzB,6BAAyB,KAAK,oBAAoB,CAAC,MAAM,CAAC;AAE1D,QAAI,CAAC,KAAK,kBAAmB;AAC7B,QAAI,CAAC,KAAK,cAAc,UAAU;AACjC,WAAK,cAAc,WAAW,gBAAgB,MAAM;AAAA,IACrD,OAAO;AACN,+BAAyB,KAAK,cAAc,UAAU,CAAC,MAAM,CAAC;AAAA,IAC/D;AACA,SAAK,kBAAkB;AAAA,EACxB;AAAA;AAAA,EAGQ,aAAqB;AAC5B,WAAO,KAAK,cAAc,IAAI,MAAM,SAAS,gBAAgB;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,iBAAiB,MAAsB,cAAuB;AACrE,SAAK,MAAM,oBAAoB,IAAI;AACnC,UAAM,UAA0B,EAAE,OAAO,CAAC,GAAU,SAAS,CAAC,GAAU,SAAS,CAAC,EAAS;AAE3F,QAAI,aAAa;AACjB,eAAW,CAAC,IAAI,EAAE,KAAK,iBAAiB,IAAI,GAAG;AAC9C,UAAI,GAAG,CAAC,MAAM,aAAa,KAAK;AAC/B,cAAM,WAAW,KAAK,MAAM,IAAI,EAAmB;AACnD,YAAI,YAAY,CAAC,QAAQ,UAAU,GAAG,CAAC,CAAC,GAAG;AAC1C,uBAAa;AACb,kBAAQ,QAAQ,EAAO,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;AAAA,QAC5C,OAAO;AACN,uBAAa;AACb,kBAAQ,MAAM,EAAO,IAAI,GAAG,CAAC;AAAA,QAC9B;AAAA,MACD,WAAW,GAAG,CAAC,MAAM,aAAa,OAAO;AACxC,cAAM,SAAS,KAAK,MAAM,IAAI,EAAmB;AACjD,YAAI,CAAC,QAAQ;AAEZ;AAAA,QACD;AACA,cAAM,UAAU,gBAAgB,QAAQ,GAAG,CAAC,CAAC;AAC7C,qBAAa;AACb,gBAAQ,QAAQ,EAAO,IAAI,CAAC,QAAQ,OAAO;AAAA,MAC5C,WAAW,GAAG,CAAC,MAAM,aAAa,QAAQ;AACzC,YAAI,KAAK,MAAM,IAAI,EAAmB,GAAG;AACxC,uBAAa;AACb,kBAAQ,QAAQ,EAAO,IAAI,KAAK,MAAM,IAAI,EAAmB;AAAA,QAC9D;AAAA,MACD;AAAA,IACD;AACA,QAAI,YAAY;AACf,WAAK,MAAM,UAAU,SAAS,EAAE,aAAa,CAAC;AAAA,IAC/C;AAAA,EACD;AAAA;AAAA,EAGQ,SAAS,MAAM;AAGtB,SAAK,MAAM,cAAc;AACzB,QAAI,KAAK,mBAAmB,WAAW,EAAG;AAE1C,UAAM,QAAQ,KAAK;AACnB,SAAK,qBAAqB,CAAC;AAE3B,QAAI;AACH,WAAK,MAAM,mBAAmB,MAAM;AAEnC,aAAK,MAAM,UAAU,mBAAmB,KAAK,kBAAkB,GAAG,EAAE,cAAc,MAAM,CAAC;AAGzF,mBAAW,QAAQ,OAAO;AACzB,cAAI,KAAK,SAAS,SAAS;AAC1B,iBAAK,iBAAiB,KAAK,MAAM,IAAI;AACrC;AAAA,UACD;AAEA,cAAI,KAAK,oBAAoB,WAAW,GAAG;AAC1C,kBAAM,IAAI,MAAM,6DAA6D;AAAA,UAC9E;AACA,cAAI,KAAK,oBAAoB,CAAC,EAAE,gBAAgB,KAAK,aAAa;AACjE,kBAAM,IAAI;AAAA,cACT;AAAA,YACD;AAAA,UACD;AACA,cAAI,KAAK,WAAW,WAAW;AAC9B,iBAAK,oBAAoB,MAAM;AAAA,UAChC,WAAW,KAAK,WAAW,UAAU;AACpC,kBAAM,UAAU,KAAK,oBAAoB,MAAM;AAC/C,gBAAI,UAAU,WAAW,QAAQ,MAAM;AACtC,mBAAK,iBAAiB,QAAQ,MAAM,IAAI;AAAA,YACzC;AAAA,UACD,OAAO;AACN,iBAAK,iBAAiB,KAAK,OAAO,gBAAgB,IAAI;AACtD,iBAAK,oBAAoB,MAAM;AAAA,UAChC;AAAA,QACD;AAEA,YAAI;AACH,eAAK,qBAAqB,KAAK,MAAM,kBAAkB,MAAM;AAC5D,uBAAW,WAAW,KAAK,qBAAqB;AAC/C,kBAAI,EAAE,UAAU,YAAY,CAAC,QAAQ,KAAM;AAC3C,mBAAK,iBAAiB,QAAQ,MAAM,IAAI;AAAA,YACzC;AACA,gBAAI,CAAC,KAAK,cAAc,SAAU;AAClC,kBAAM,OAAO,eAAe,KAAK,cAAc,QAAQ;AACvD,gBAAI,CAAC,KAAM;AACX,iBAAK,iBAAiB,MAAM,IAAI;AAAA,UACjC,CAAC;AAAA,QACF,SAAS,GAAG;AACX,kBAAQ,MAAM,CAAC;AAEf,eAAK,qBAAqB,EAAE,OAAO,CAAC,GAAU,SAAS,CAAC,GAAU,SAAS,CAAC,EAAS;AACrF,eAAK,gBAAgB;AAAA,QACtB;AAAA,MACD,CAAC;AACD,WAAK,kBAAkB,MAAM,GAAG,EAAE,GAAG,eAAe,KAAK;AAAA,IAC1D,SAAS,GAAG;AACX,cAAQ,MAAM,CAAC;AACf,WAAK,MAAM,oBAAoB;AAC/B,WAAK,gBAAgB;AAAA,IACtB;AAAA,EACD;AACD;",
6
6
  "names": []
7
7
  }