@tldraw/editor
Version:
tldraw infinite canvas SDK (editor).
8 lines (7 loc) • 16.7 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../../../src/lib/utils/sync/LocalIndexedDb.ts"],
"sourcesContent": ["import { RecordsDiff, SerializedSchema, SerializedStore } from '@tldraw/store'\nimport { TLRecord, TLStoreSchema } from '@tldraw/tlschema'\nimport { assert, getFromLocalStorage, noop, setInLocalStorage } from '@tldraw/utils'\nimport { IDBPDatabase, IDBPTransaction, deleteDB, openDB } from 'idb'\nimport { TLSessionStateSnapshot } from '../../config/TLSessionStateSnapshot'\n\n// DO NOT CHANGE THESE WITHOUT ADDING MIGRATION LOGIC. DOING SO WOULD WIPE ALL EXISTING DATA.\nconst STORE_PREFIX = 'TLDRAW_DOCUMENT_v2'\nconst LEGACY_ASSET_STORE_PREFIX = 'TLDRAW_ASSET_STORE_v1'\nconst dbNameIndexKey = 'TLDRAW_DB_NAME_INDEX_v2'\n\n/** @internal */\nexport const Table = {\n\tRecords: 'records',\n\tSchema: 'schema',\n\tSessionState: 'session_state',\n\tAssets: 'assets',\n} as const\n\n/** @internal */\nexport type StoreName = (typeof Table)[keyof typeof Table]\n\nasync function openLocalDb(persistenceKey: string) {\n\tconst storeId = STORE_PREFIX + persistenceKey\n\n\taddDbName(storeId)\n\n\treturn await openDB<StoreName>(storeId, 4, {\n\t\tupgrade(database) {\n\t\t\tif (!database.objectStoreNames.contains(Table.Records)) {\n\t\t\t\tdatabase.createObjectStore(Table.Records)\n\t\t\t}\n\t\t\tif (!database.objectStoreNames.contains(Table.Schema)) {\n\t\t\t\tdatabase.createObjectStore(Table.Schema)\n\t\t\t}\n\t\t\tif (!database.objectStoreNames.contains(Table.SessionState)) {\n\t\t\t\tdatabase.createObjectStore(Table.SessionState)\n\t\t\t}\n\t\t\tif (!database.objectStoreNames.contains(Table.Assets)) {\n\t\t\t\tdatabase.createObjectStore(Table.Assets)\n\t\t\t}\n\t\t},\n\t})\n}\n\nasync function migrateLegacyAssetDbIfNeeded(persistenceKey: string) {\n\tconst databases = window.indexedDB.databases\n\t\t? (await window.indexedDB.databases()).map((db) => db.name)\n\t\t: getAllIndexDbNames()\n\tconst oldStoreId = LEGACY_ASSET_STORE_PREFIX + persistenceKey\n\tconst existing = databases.find((dbName) => dbName === oldStoreId)\n\tif (!existing) return\n\n\tconst oldAssetDb = await openDB<StoreName>(oldStoreId, 1, {\n\t\tupgrade(database) {\n\t\t\tif (!database.objectStoreNames.contains('assets')) {\n\t\t\t\tdatabase.createObjectStore('assets')\n\t\t\t}\n\t\t},\n\t})\n\tif (!oldAssetDb.objectStoreNames.contains('assets')) return\n\n\tconst oldTx = oldAssetDb.transaction(['assets'], 'readonly')\n\tconst oldAssetStore = oldTx.objectStore('assets')\n\tconst oldAssetsKeys = await oldAssetStore.getAllKeys()\n\tconst oldAssets = await Promise.all(\n\t\toldAssetsKeys.map(async (key) => [key, await oldAssetStore.get(key)] as const)\n\t)\n\tawait oldTx.done\n\n\tconst newDb = await openLocalDb(persistenceKey)\n\tconst newTx = newDb.transaction([Table.Assets], 'readwrite')\n\tconst newAssetTable = newTx.objectStore(Table.Assets)\n\tfor (const [key, value] of oldAssets) {\n\t\tnewAssetTable.put(value, key)\n\t}\n\tawait newTx.done\n\n\toldAssetDb.close()\n\tnewDb.close()\n\n\tawait deleteDB(oldStoreId)\n}\n\ninterface LoadResult {\n\trecords: TLRecord[]\n\tschema?: SerializedSchema\n\tsessionStateSnapshot?: TLSessionStateSnapshot | null\n}\n\ninterface SessionStateSnapshotRow {\n\tid: string\n\tsnapshot: TLSessionStateSnapshot\n\tupdatedAt: number\n}\n\n/** @internal */\nexport class LocalIndexedDb {\n\tprivate getDbPromise: Promise<IDBPDatabase<StoreName>>\n\tprivate isClosed = false\n\tprivate pendingTransactionSet = new Set<Promise<unknown>>()\n\n\t/** @internal */\n\tstatic connectedInstances = new Set<LocalIndexedDb>()\n\n\tconstructor(persistenceKey: string) {\n\t\tLocalIndexedDb.connectedInstances.add(this)\n\t\tthis.getDbPromise = (async () => {\n\t\t\tawait migrateLegacyAssetDbIfNeeded(persistenceKey)\n\t\t\treturn await openLocalDb(persistenceKey)\n\t\t})()\n\t}\n\n\tprivate getDb() {\n\t\treturn this.getDbPromise\n\t}\n\n\t/**\n\t * Wait for any pending transactions to be completed. Useful for tests.\n\t *\n\t * @internal\n\t */\n\tpending(): Promise<void> {\n\t\treturn Promise.allSettled([this.getDbPromise, ...this.pendingTransactionSet]).then(noop)\n\t}\n\n\tasync close() {\n\t\tif (this.isClosed) return\n\t\tthis.isClosed = true\n\t\tawait this.pending()\n\t\t;(await this.getDb()).close()\n\t\tLocalIndexedDb.connectedInstances.delete(this)\n\t}\n\n\tprivate tx<Names extends StoreName[], Mode extends IDBTransactionMode, T>(\n\t\tmode: Mode,\n\t\tnames: Names,\n\t\tcb: (tx: IDBPTransaction<StoreName, Names, Mode>) => Promise<T>\n\t): Promise<T> {\n\t\tconst txPromise = (async () => {\n\t\t\tassert(!this.isClosed, 'db is closed')\n\t\t\tconst db = await this.getDb()\n\t\t\tconst tx = db.transaction(names, mode)\n\t\t\t// need to add a catch here early to prevent unhandled promise rejection\n\t\t\t// during react-strict-mode where this tx.done promise can be rejected\n\t\t\t// before we have a chance to await on it\n\t\t\tconst done = tx.done.catch((e: unknown) => {\n\t\t\t\tif (!this.isClosed) {\n\t\t\t\t\tthrow e\n\t\t\t\t}\n\t\t\t})\n\t\t\ttry {\n\t\t\t\treturn await cb(tx)\n\t\t\t} finally {\n\t\t\t\tif (!this.isClosed) {\n\t\t\t\t\tawait done\n\t\t\t\t} else {\n\t\t\t\t\ttx.abort()\n\t\t\t\t}\n\t\t\t}\n\t\t})()\n\t\tthis.pendingTransactionSet.add(txPromise)\n\t\ttxPromise.finally(() => this.pendingTransactionSet.delete(txPromise))\n\t\treturn txPromise\n\t}\n\n\tasync load({ sessionId }: { sessionId?: string } = {}) {\n\t\treturn await this.tx(\n\t\t\t'readonly',\n\t\t\t[Table.Records, Table.Schema, Table.SessionState],\n\t\t\tasync (tx) => {\n\t\t\t\tconst recordsStore = tx.objectStore(Table.Records)\n\t\t\t\tconst schemaStore = tx.objectStore(Table.Schema)\n\t\t\t\tconst sessionStateStore = tx.objectStore(Table.SessionState)\n\t\t\t\tlet sessionStateSnapshot = sessionId\n\t\t\t\t\t? ((await sessionStateStore.get(sessionId)) as SessionStateSnapshotRow | undefined)\n\t\t\t\t\t\t\t?.snapshot\n\t\t\t\t\t: null\n\t\t\t\tif (!sessionStateSnapshot) {\n\t\t\t\t\t// get the most recent session state\n\t\t\t\t\tconst all = (await sessionStateStore.getAll()) as SessionStateSnapshotRow[]\n\t\t\t\t\tsessionStateSnapshot = all.sort((a, b) => a.updatedAt - b.updatedAt).pop()?.snapshot\n\t\t\t\t}\n\t\t\t\tconst result = {\n\t\t\t\t\trecords: await recordsStore.getAll(),\n\t\t\t\t\tschema: await schemaStore.get(Table.Schema),\n\t\t\t\t\tsessionStateSnapshot,\n\t\t\t\t} satisfies LoadResult\n\n\t\t\t\treturn result\n\t\t\t}\n\t\t)\n\t}\n\n\tasync storeChanges({\n\t\tschema,\n\t\tchanges,\n\t\tsessionId,\n\t\tsessionStateSnapshot,\n\t}: {\n\t\tschema: TLStoreSchema\n\t\tchanges: RecordsDiff<any>\n\t\tsessionId?: string | null\n\t\tsessionStateSnapshot?: TLSessionStateSnapshot | null\n\t}) {\n\t\tawait this.tx('readwrite', [Table.Records, Table.Schema, Table.SessionState], async (tx) => {\n\t\t\tconst recordsStore = tx.objectStore(Table.Records)\n\t\t\tconst schemaStore = tx.objectStore(Table.Schema)\n\t\t\tconst sessionStateStore = tx.objectStore(Table.SessionState)\n\n\t\t\tfor (const [id, record] of Object.entries(changes.added)) {\n\t\t\t\tawait recordsStore.put(record, id)\n\t\t\t}\n\n\t\t\tfor (const [_prev, updated] of Object.values(changes.updated)) {\n\t\t\t\tawait recordsStore.put(updated, updated.id)\n\t\t\t}\n\n\t\t\tfor (const id of Object.keys(changes.removed)) {\n\t\t\t\tawait recordsStore.delete(id)\n\t\t\t}\n\n\t\t\tschemaStore.put(schema.serialize(), Table.Schema)\n\t\t\tif (sessionStateSnapshot && sessionId) {\n\t\t\t\tsessionStateStore.put(\n\t\t\t\t\t{\n\t\t\t\t\t\tsnapshot: sessionStateSnapshot,\n\t\t\t\t\t\tupdatedAt: Date.now(),\n\t\t\t\t\t\tid: sessionId,\n\t\t\t\t\t} satisfies SessionStateSnapshotRow,\n\t\t\t\t\tsessionId\n\t\t\t\t)\n\t\t\t} else if (sessionStateSnapshot || sessionId) {\n\t\t\t\tconsole.error('sessionStateSnapshot and instanceId must be provided together')\n\t\t\t}\n\t\t})\n\t}\n\n\tasync storeSnapshot({\n\t\tschema,\n\t\tsnapshot,\n\t\tsessionId,\n\t\tsessionStateSnapshot,\n\t}: {\n\t\tschema: TLStoreSchema\n\t\tsnapshot: SerializedStore<any>\n\t\tsessionId?: string | null\n\t\tsessionStateSnapshot?: TLSessionStateSnapshot | null\n\t}) {\n\t\tawait this.tx('readwrite', [Table.Records, Table.Schema, Table.SessionState], async (tx) => {\n\t\t\tconst recordsStore = tx.objectStore(Table.Records)\n\t\t\tconst schemaStore = tx.objectStore(Table.Schema)\n\t\t\tconst sessionStateStore = tx.objectStore(Table.SessionState)\n\n\t\t\tawait recordsStore.clear()\n\n\t\t\tfor (const [id, record] of Object.entries(snapshot)) {\n\t\t\t\tawait recordsStore.put(record, id)\n\t\t\t}\n\n\t\t\tschemaStore.put(schema.serialize(), Table.Schema)\n\n\t\t\tif (sessionStateSnapshot && sessionId) {\n\t\t\t\tsessionStateStore.put(\n\t\t\t\t\t{\n\t\t\t\t\t\tsnapshot: sessionStateSnapshot,\n\t\t\t\t\t\tupdatedAt: Date.now(),\n\t\t\t\t\t\tid: sessionId,\n\t\t\t\t\t} satisfies SessionStateSnapshotRow,\n\t\t\t\t\tsessionId\n\t\t\t\t)\n\t\t\t} else if (sessionStateSnapshot || sessionId) {\n\t\t\t\tconsole.error('sessionStateSnapshot and instanceId must be provided together')\n\t\t\t}\n\t\t})\n\t}\n\n\tasync pruneSessions() {\n\t\tawait this.tx('readwrite', [Table.SessionState], async (tx) => {\n\t\t\tconst sessionStateStore = tx.objectStore(Table.SessionState)\n\t\t\tconst all = (await sessionStateStore.getAll()).sort((a, b) => a.updatedAt - b.updatedAt)\n\t\t\tif (all.length < 10) {\n\t\t\t\tawait tx.done\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst toDelete = all.slice(0, all.length - 10)\n\t\t\tfor (const { id } of toDelete) {\n\t\t\t\tawait sessionStateStore.delete(id)\n\t\t\t}\n\t\t})\n\t}\n\n\tasync getAsset(assetId: string): Promise<File | undefined> {\n\t\treturn await this.tx('readonly', [Table.Assets], async (tx) => {\n\t\t\tconst assetsStore = tx.objectStore(Table.Assets)\n\t\t\treturn await assetsStore.get(assetId)\n\t\t})\n\t}\n\n\tasync storeAsset(assetId: string, blob: File) {\n\t\tawait this.tx('readwrite', [Table.Assets], async (tx) => {\n\t\t\tconst assetsStore = tx.objectStore(Table.Assets)\n\t\t\tawait assetsStore.put(blob, assetId)\n\t\t})\n\t}\n\n\tasync removeAssets(assetId: string[]) {\n\t\tawait this.tx('readwrite', [Table.Assets], async (tx) => {\n\t\t\tconst assetsStore = tx.objectStore(Table.Assets)\n\t\t\tfor (const id of assetId) {\n\t\t\t\tawait assetsStore.delete(id)\n\t\t\t}\n\t\t})\n\t}\n}\n\n/** @internal */\nexport function getAllIndexDbNames(): string[] {\n\tconst result = JSON.parse(getFromLocalStorage(dbNameIndexKey) || '[]') ?? []\n\tif (!Array.isArray(result)) {\n\t\treturn []\n\t}\n\treturn result\n}\n\nfunction addDbName(name: string) {\n\tconst all = new Set(getAllIndexDbNames())\n\tall.add(name)\n\tsetInLocalStorage(dbNameIndexKey, JSON.stringify([...all]))\n}\n"],
"mappings": "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",
"names": []
}