[improvement] store snapshot types (#1657)

This PR improves the types for the Store.

- renames `StoreSnapshot` to `SerializedStore`, which is the return type
of `Store.serialize`
- creates `StoreSnapshot` as a type for the return type of
`Store.getSnapshot` / the argument type for `Store.loadSnapshot`
- creates `TLStoreSnapshot` as the type used for the `TLStore`.

This came out of a session I had with a user. This should prevent
needing to import types from `@tldraw/store` directly.

### Change Type

- [x] `major` — Breaking change

### Test Plan

- [x] Unit Tests

### Release Notes

- [dev] Rename `StoreSnapshot` to `SerializedStore`
- [dev] Create new `StoreSnapshot` as type related to
`getSnapshot`/`loadSnapshot`
This commit is contained in:
Steve Ruiz 2023-06-27 13:25:55 +01:00 committed by GitHub
parent faecd88220
commit ed8d4d9e05
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 71 additions and 57 deletions

View file

@ -34,10 +34,10 @@ import { SelectionCorner } from '@tldraw/primitives';
import { SelectionEdge } from '@tldraw/primitives'; import { SelectionEdge } from '@tldraw/primitives';
import { SelectionHandle } from '@tldraw/primitives'; import { SelectionHandle } from '@tldraw/primitives';
import { SerializedSchema } from '@tldraw/store'; import { SerializedSchema } from '@tldraw/store';
import { SerializedStore } from '@tldraw/store';
import { ShapeProps } from '@tldraw/tlschema'; import { ShapeProps } from '@tldraw/tlschema';
import { Signal } from '@tldraw/state'; import { Signal } from '@tldraw/state';
import { StoreSchema } from '@tldraw/store'; import { StoreSchema } from '@tldraw/store';
import { StoreSnapshot } from '@tldraw/store';
import { StrokePoint } from '@tldraw/primitives'; import { StrokePoint } from '@tldraw/primitives';
import { StyleProp } from '@tldraw/tlschema'; import { StyleProp } from '@tldraw/tlschema';
import { TLArrowShape } from '@tldraw/tlschema'; import { TLArrowShape } from '@tldraw/tlschema';
@ -2228,7 +2228,7 @@ export type TldrawEditorProps = {
store: TLStore | TLStoreWithStatus; store: TLStore | TLStoreWithStatus;
} | { } | {
store?: undefined; store?: undefined;
initialData?: StoreSnapshot<TLRecord>; initialData?: SerializedStore<TLRecord>;
persistenceKey?: string; persistenceKey?: string;
sessionId?: string; sessionId?: string;
defaultName?: string; defaultName?: string;
@ -2661,7 +2661,7 @@ export type TLStoreEventInfo = HistoryEntry<TLRecord>;
// @public (undocumented) // @public (undocumented)
export type TLStoreOptions = { export type TLStoreOptions = {
initialData?: StoreSnapshot<TLRecord>; initialData?: SerializedStore<TLRecord>;
defaultName?: string; defaultName?: string;
} & ({ } & ({
schema: StoreSchema<TLRecord, TLStoreProps>; schema: StoreSchema<TLRecord, TLStoreProps>;

View file

@ -1,4 +1,4 @@
import { Store, StoreSnapshot } from '@tldraw/store' import { SerializedStore, Store } from '@tldraw/store'
import { TLRecord, TLStore } from '@tldraw/tlschema' import { TLRecord, TLStore } from '@tldraw/tlschema'
import { RecursivePartial, Required, annotateError } from '@tldraw/utils' import { RecursivePartial, Required, annotateError } from '@tldraw/utils'
import React, { import React, {
@ -70,7 +70,7 @@ export type TldrawEditorProps = {
/** /**
* The editor's initial data. * The editor's initial data.
*/ */
initialData?: StoreSnapshot<TLRecord> initialData?: SerializedStore<TLRecord>
/** /**
* The id under which to sync and persist the editor's data. If none is given tldraw will not sync or persist * The id under which to sync and persist the editor's data. If none is given tldraw will not sync or persist
* the editor's data. * the editor's data.

View file

@ -1,11 +1,11 @@
import { HistoryEntry, Store, StoreSchema, StoreSnapshot } from '@tldraw/store' import { HistoryEntry, SerializedStore, Store, StoreSchema } from '@tldraw/store'
import { TLRecord, TLStore, TLStoreProps, createTLSchema } from '@tldraw/tlschema' import { TLRecord, TLStore, TLStoreProps, createTLSchema } from '@tldraw/tlschema'
import { checkShapesAndAddCore } from './defaultShapes' import { checkShapesAndAddCore } from './defaultShapes'
import { AnyTLShapeInfo, TLShapeInfo } from './defineShape' import { AnyTLShapeInfo, TLShapeInfo } from './defineShape'
/** @public */ /** @public */
export type TLStoreOptions = { export type TLStoreOptions = {
initialData?: StoreSnapshot<TLRecord> initialData?: SerializedStore<TLRecord>
defaultName?: string defaultName?: string
} & ({ shapes: readonly AnyTLShapeInfo[] } | { schema: StoreSchema<TLRecord, TLStoreProps> }) } & ({ shapes: readonly AnyTLShapeInfo[] } | { schema: StoreSchema<TLRecord, TLStoreProps> })

View file

@ -1,4 +1,4 @@
import { RecordsDiff, SerializedSchema, StoreSnapshot } from '@tldraw/store' import { RecordsDiff, SerializedSchema, SerializedStore } from '@tldraw/store'
import { TLRecord, TLStoreSchema } from '@tldraw/tlschema' import { TLRecord, TLStoreSchema } from '@tldraw/tlschema'
import { IDBPDatabase, openDB } from 'idb' import { IDBPDatabase, openDB } from 'idb'
import { TLSessionStateSnapshot } from '../../config/TLSessionStateSnapshot' import { TLSessionStateSnapshot } from '../../config/TLSessionStateSnapshot'
@ -156,7 +156,7 @@ export async function storeSnapshotInIndexedDb({
}: { }: {
persistenceKey: string persistenceKey: string
schema: TLStoreSchema schema: TLStoreSchema
snapshot: StoreSnapshot<any> snapshot: SerializedStore<any>
sessionId?: string | null sessionId?: string | null
sessionStateSnapshot?: TLSessionStateSnapshot | null sessionStateSnapshot?: TLSessionStateSnapshot | null
didCancel?: () => boolean didCancel?: () => boolean

View file

@ -13,7 +13,7 @@ import {
MigrationResult, MigrationResult,
RecordId, RecordId,
SerializedSchema, SerializedSchema,
StoreSnapshot, SerializedStore,
UnknownRecord, UnknownRecord,
} from '@tldraw/store' } from '@tldraw/store'
import { TLUiToastsContextType, TLUiTranslationKey } from '@tldraw/ui' import { TLUiToastsContextType, TLUiTranslationKey } from '@tldraw/ui'
@ -119,7 +119,7 @@ export function parseTldrawJsonFile({
// even if the file version is up to date, it might contain old-format // even if the file version is up to date, it might contain old-format
// records. lets create a store with the records and migrate it to the // records. lets create a store with the records and migrate it to the
// latest version // latest version
let migrationResult: MigrationResult<StoreSnapshot<TLRecord>> let migrationResult: MigrationResult<SerializedStore<TLRecord>>
try { try {
const storeSnapshot = Object.fromEntries(data.records.map((r) => [r.id, r as TLRecord])) const storeSnapshot = Object.fromEntries(data.records.map((r) => [r.id, r as TLRecord]))
migrationResult = schema.migrateStoreSnapshot(storeSnapshot, data.schema) migrationResult = schema.migrateStoreSnapshot(storeSnapshot, data.schema)

View file

@ -213,13 +213,16 @@ export interface SerializedSchema {
storeVersion: number; storeVersion: number;
} }
// @public
export type SerializedStore<R extends UnknownRecord> = Record<IdOf<R>, R>;
// @public // @public
export function squashRecordDiffs<T extends UnknownRecord>(diffs: RecordsDiff<T>[]): RecordsDiff<T>; export function squashRecordDiffs<T extends UnknownRecord>(diffs: RecordsDiff<T>[]): RecordsDiff<T>;
// @public // @public
export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> { export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
constructor(config: { constructor(config: {
initialData?: StoreSnapshot<R>; initialData?: SerializedStore<R>;
schema: StoreSchema<R, Props>; schema: StoreSchema<R, Props>;
props: Props; props: Props;
}); });
@ -241,20 +244,14 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
// (undocumented) // (undocumented)
_flushHistory(): void; _flushHistory(): void;
get: <K extends IdOf<R>>(id: K) => RecFromId<K> | undefined; get: <K extends IdOf<R>>(id: K) => RecFromId<K> | undefined;
getSnapshot(scope?: 'all' | RecordScope): { getSnapshot(scope?: 'all' | RecordScope): StoreSnapshot<R>;
store: StoreSnapshot<R>;
schema: SerializedSchema;
};
has: <K extends IdOf<R>>(id: K) => boolean; has: <K extends IdOf<R>>(id: K) => boolean;
readonly history: Atom<number, RecordsDiff<R>>; readonly history: Atom<number, RecordsDiff<R>>;
readonly id: string; readonly id: string;
// @internal (undocumented) // @internal (undocumented)
isPossiblyCorrupted(): boolean; isPossiblyCorrupted(): boolean;
listen: (onHistory: StoreListener<R>, filters?: Partial<StoreListenerFilters>) => () => void; listen: (onHistory: StoreListener<R>, filters?: Partial<StoreListenerFilters>) => () => void;
loadSnapshot(snapshot: { loadSnapshot(snapshot: StoreSnapshot<R>): void;
store: StoreSnapshot<R>;
schema: SerializedSchema;
}): void;
// @internal (undocumented) // @internal (undocumented)
markAsPossiblyCorrupted(): void; markAsPossiblyCorrupted(): void;
mergeRemoteChanges: (fn: () => void) => void; mergeRemoteChanges: (fn: () => void) => void;
@ -273,7 +270,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
readonly scopedTypes: { readonly scopedTypes: {
readonly [K in RecordScope]: ReadonlySet<R['typeName']>; readonly [K in RecordScope]: ReadonlySet<R['typeName']>;
}; };
serialize: (scope?: 'all' | RecordScope) => StoreSnapshot<R>; serialize: (scope?: 'all' | RecordScope) => SerializedStore<R>;
unsafeGetWithoutCapture: <K extends IdOf<R>>(id: K) => RecFromId<K> | undefined; unsafeGetWithoutCapture: <K extends IdOf<R>>(id: K) => RecFromId<K> | undefined;
update: <K extends IdOf<R>>(id: K, updater: (record: RecFromId<K>) => RecFromId<K>) => void; update: <K extends IdOf<R>>(id: K, updater: (record: RecFromId<K>) => RecFromId<K>) => void;
// (undocumented) // (undocumented)
@ -307,7 +304,7 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
// (undocumented) // (undocumented)
migratePersistedRecord(record: R, persistedSchema: SerializedSchema, direction?: 'down' | 'up'): MigrationResult<R>; migratePersistedRecord(record: R, persistedSchema: SerializedSchema, direction?: 'down' | 'up'): MigrationResult<R>;
// (undocumented) // (undocumented)
migrateStoreSnapshot(storeSnapshot: StoreSnapshot<R>, persistedSchema: SerializedSchema): MigrationResult<StoreSnapshot<R>>; migrateStoreSnapshot(storeSnapshot: SerializedStore<R>, persistedSchema: SerializedSchema): MigrationResult<SerializedStore<R>>;
// (undocumented) // (undocumented)
serialize(): SerializedSchema; serialize(): SerializedSchema;
// (undocumented) // (undocumented)
@ -333,8 +330,11 @@ export type StoreSchemaOptions<R extends UnknownRecord, P> = {
createIntegrityChecker?: (store: Store<R, P>) => void; createIntegrityChecker?: (store: Store<R, P>) => void;
}; };
// @public // @public (undocumented)
export type StoreSnapshot<R extends UnknownRecord> = Record<IdOf<R>, R>; export type StoreSnapshot<R extends UnknownRecord> = {
store: SerializedStore<R>;
schema: SerializedSchema;
};
// @public (undocumented) // @public (undocumented)
export type StoreValidator<R extends UnknownRecord> = { export type StoreValidator<R extends UnknownRecord> = {

View file

@ -7,6 +7,7 @@ export type {
ComputedCache, ComputedCache,
HistoryEntry, HistoryEntry,
RecordsDiff, RecordsDiff,
SerializedStore,
StoreError, StoreError,
StoreListener, StoreListener,
StoreSnapshot, StoreSnapshot,

View file

@ -73,7 +73,13 @@ export type ComputedCache<Data, R extends UnknownRecord> = {
* *
* @public * @public
*/ */
export type StoreSnapshot<R extends UnknownRecord> = Record<IdOf<R>, R> export type SerializedStore<R extends UnknownRecord> = Record<IdOf<R>, R>
/** @public */
export type StoreSnapshot<R extends UnknownRecord> = {
store: SerializedStore<R>
schema: SerializedSchema
}
/** @public */ /** @public */
export type StoreValidator<R extends UnknownRecord> = { export type StoreValidator<R extends UnknownRecord> = {
@ -163,7 +169,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
constructor(config: { constructor(config: {
/** The store's initial data. */ /** The store's initial data. */
initialData?: StoreSnapshot<R> initialData?: SerializedStore<R>
/** /**
* A map of validators for each record type. A record's validator will be called when the record * A map of validators for each record type. A record's validator will be called when the record
* is created or updated. It should throw an error if the record is invalid. * is created or updated. It should throw an error if the record is invalid.
@ -503,8 +509,8 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
* @param scope - The scope of records to serialize. Defaults to 'document'. * @param scope - The scope of records to serialize. Defaults to 'document'.
* @returns The record store snapshot as a JSON payload. * @returns The record store snapshot as a JSON payload.
*/ */
serialize = (scope: RecordScope | 'all' = 'document'): StoreSnapshot<R> => { serialize = (scope: RecordScope | 'all' = 'document'): SerializedStore<R> => {
const result = {} as StoreSnapshot<R> const result = {} as SerializedStore<R>
for (const [id, atom] of objectMapEntries(this.atoms.value)) { for (const [id, atom] of objectMapEntries(this.atoms.value)) {
const record = atom.value const record = atom.value
if (scope === 'all' || this.scopedTypes[scope].has(record.typeName)) { if (scope === 'all' || this.scopedTypes[scope].has(record.typeName)) {
@ -525,7 +531,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
* @param scope - The scope of records to serialize. Defaults to 'document'. * @param scope - The scope of records to serialize. Defaults to 'document'.
* @public * @public
*/ */
getSnapshot(scope: RecordScope | 'all' = 'document') { getSnapshot(scope: RecordScope | 'all' = 'document'): StoreSnapshot<R> {
return { return {
store: this.serialize(scope), store: this.serialize(scope),
schema: this.schema.serialize(), schema: this.schema.serialize(),
@ -544,7 +550,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
* *
* @public * @public
*/ */
loadSnapshot(snapshot: { store: StoreSnapshot<R>; schema: SerializedSchema }): void { loadSnapshot(snapshot: StoreSnapshot<R>): void {
const migrationResult = this.schema.migrateStoreSnapshot(snapshot.store, snapshot.schema) const migrationResult = this.schema.migrateStoreSnapshot(snapshot.store, snapshot.schema)
if (migrationResult.type === 'error') { if (migrationResult.type === 'error') {

View file

@ -1,7 +1,7 @@
import { getOwnProperty, objectMapValues } from '@tldraw/utils' import { getOwnProperty, objectMapValues } from '@tldraw/utils'
import { IdOf, UnknownRecord } from './BaseRecord' import { IdOf, UnknownRecord } from './BaseRecord'
import { RecordType } from './RecordType' import { RecordType } from './RecordType'
import { Store, StoreSnapshot } from './Store' import { SerializedStore, Store } from './Store'
import { import {
MigrationFailureReason, MigrationFailureReason,
MigrationResult, MigrationResult,
@ -189,9 +189,9 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
} }
migrateStoreSnapshot( migrateStoreSnapshot(
storeSnapshot: StoreSnapshot<R>, storeSnapshot: SerializedStore<R>,
persistedSchema: SerializedSchema persistedSchema: SerializedSchema
): MigrationResult<StoreSnapshot<R>> { ): MigrationResult<SerializedStore<R>> {
const migrations = this.options.snapshotMigrations const migrations = this.options.snapshotMigrations
if (!migrations) { if (!migrations) {
return { type: 'success', value: storeSnapshot } return { type: 'success', value: storeSnapshot }
@ -205,7 +205,7 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
} }
if (ourStoreVersion > persistedStoreVersion) { if (ourStoreVersion > persistedStoreVersion) {
const result = migrate<StoreSnapshot<R>>({ const result = migrate<SerializedStore<R>>({
value: storeSnapshot, value: storeSnapshot,
migrations, migrations,
fromVersion: persistedStoreVersion, fromVersion: persistedStoreVersion,

View file

@ -1,5 +1,5 @@
import { MigrationFailureReason } from '../migrate' import { MigrationFailureReason } from '../migrate'
import { StoreSnapshot } from '../Store' import { SerializedStore } from '../Store'
import { testSchemaV0 } from './testSchema.v0' import { testSchemaV0 } from './testSchema.v0'
import { testSchemaV1 } from './testSchema.v1' import { testSchemaV1 } from './testSchema.v1'
@ -305,7 +305,7 @@ test('subtype versions in the future fail', () => {
}) })
test('migrating a whole store snapshot works', () => { test('migrating a whole store snapshot works', () => {
const snapshot: StoreSnapshot<any> = { const snapshot: SerializedStore<any> = {
'user-1': { 'user-1': {
id: 'user-1', id: 'user-1',
typeName: 'user', typeName: 'user',

View file

@ -1,7 +1,7 @@
import { assert } from '@tldraw/utils' import { assert } from '@tldraw/utils'
import { BaseRecord, RecordId } from '../BaseRecord' import { BaseRecord, RecordId } from '../BaseRecord'
import { createRecordType } from '../RecordType' import { createRecordType } from '../RecordType'
import { StoreSnapshot } from '../Store' import { SerializedStore } from '../Store'
import { StoreSchema } from '../StoreSchema' import { StoreSchema } from '../StoreSchema'
import { defineMigrations } from '../migrate' import { defineMigrations } from '../migrate'
@ -203,10 +203,10 @@ const snapshotMigrations = defineMigrations({
currentVersion: StoreVersions.RemoveOrg, currentVersion: StoreVersions.RemoveOrg,
migrators: { migrators: {
[StoreVersions.RemoveOrg]: { [StoreVersions.RemoveOrg]: {
up: (store: StoreSnapshot<any>) => { up: (store: SerializedStore<any>) => {
return Object.fromEntries(Object.entries(store).filter(([_, r]) => r.typeName !== 'org')) return Object.fromEntries(Object.entries(store).filter(([_, r]) => r.typeName !== 'org'))
}, },
down: (store: StoreSnapshot<any>) => { down: (store: SerializedStore<any>) => {
// noop // noop
return store return store
}, },

View file

@ -1,6 +1,6 @@
import { BaseRecord, IdOf, RecordId } from '../BaseRecord' import { BaseRecord, IdOf, RecordId } from '../BaseRecord'
import { createRecordType } from '../RecordType' import { createRecordType } from '../RecordType'
import { Store, StoreSnapshot } from '../Store' import { SerializedStore, Store } from '../Store'
import { StoreSchema } from '../StoreSchema' import { StoreSchema } from '../StoreSchema'
interface Book extends BaseRecord<'book', RecordId<Book>> { interface Book extends BaseRecord<'book', RecordId<Book>> {
@ -90,7 +90,7 @@ describe('Store with validation', () => {
}) })
describe('Validating initial data', () => { describe('Validating initial data', () => {
let snapshot: StoreSnapshot<Book | Author> let snapshot: SerializedStore<Book | Author>
beforeEach(() => { beforeEach(() => {
const authorId = Author.createId('tolkein') const authorId = Author.createId('tolkein')

View file

@ -9,10 +9,10 @@ import { Expand } from '@tldraw/utils';
import { Migrations } from '@tldraw/store'; import { Migrations } from '@tldraw/store';
import { RecordId } from '@tldraw/store'; import { RecordId } from '@tldraw/store';
import { RecordType } from '@tldraw/store'; import { RecordType } from '@tldraw/store';
import { SerializedStore } from '@tldraw/store';
import { Signal } from '@tldraw/state'; import { Signal } from '@tldraw/state';
import { Store } from '@tldraw/store'; import { Store } from '@tldraw/store';
import { StoreSchema } from '@tldraw/store'; import { StoreSchema } from '@tldraw/store';
import { StoreSnapshot } from '@tldraw/store';
import { T } from '@tldraw/validate'; import { T } from '@tldraw/validate';
import { UnknownRecord } from '@tldraw/store'; import { UnknownRecord } from '@tldraw/store';
@ -110,7 +110,7 @@ export const CameraRecordType: RecordType<TLCamera, never>;
export const canvasUiColorTypeValidator: T.Validator<"accent" | "black" | "laser" | "muted-1" | "selection-fill" | "selection-stroke" | "white">; export const canvasUiColorTypeValidator: T.Validator<"accent" | "black" | "laser" | "muted-1" | "selection-fill" | "selection-stroke" | "white">;
// @internal (undocumented) // @internal (undocumented)
export function CLIENT_FIXUP_SCRIPT(persistedStore: StoreSnapshot<TLRecord>): StoreSnapshot<TLRecord>; export function CLIENT_FIXUP_SCRIPT(persistedStore: SerializedStore<TLRecord>): SerializedStore<TLRecord>;
// @public // @public
export function createAssetValidator<Type extends string, Props extends object>(type: Type, props: T.Validator<Props>): T.ObjectValidator<{ export function createAssetValidator<Type extends string, Props extends object>(type: Type, props: T.Validator<Props>): T.ObjectValidator<{
@ -1131,6 +1131,9 @@ export type TLScribble = {
delay: number; delay: number;
}; };
// @public (undocumented)
export type TLSerializedStore = SerializedStore<TLRecord>;
// @public // @public
export type TLShape = TLDefaultShape | TLUnknownShape; export type TLShape = TLDefaultShape | TLUnknownShape;
@ -1162,7 +1165,7 @@ export type TLStoreProps = {
export type TLStoreSchema = StoreSchema<TLRecord, TLStoreProps>; export type TLStoreSchema = StoreSchema<TLRecord, TLStoreProps>;
// @public (undocumented) // @public (undocumented)
export type TLStoreSnapshot = StoreSnapshot<TLRecord>; export type TLStoreSnapshot = SerializedStore<TLRecord>;
// @public (undocumented) // @public (undocumented)
export type TLTextShape = TLBaseShape<'text', TLTextShapeProps>; export type TLTextShape = TLBaseShape<'text', TLTextShapeProps>;

View file

@ -1,4 +1,4 @@
import { Store, StoreSchema, StoreSchemaOptions, StoreSnapshot } from '@tldraw/store' import { SerializedStore, Store, StoreSchema, StoreSchemaOptions } from '@tldraw/store'
import { annotateError, structuredClone } from '@tldraw/utils' import { annotateError, structuredClone } from '@tldraw/utils'
import { CameraRecordType, TLCameraId } from './records/TLCamera' import { CameraRecordType, TLCameraId } from './records/TLCamera'
import { DocumentRecordType, TLDOCUMENT_ID } from './records/TLDocument' import { DocumentRecordType, TLDOCUMENT_ID } from './records/TLDocument'
@ -33,7 +33,10 @@ function redactRecordForErrorReporting(record: any) {
export type TLStoreSchema = StoreSchema<TLRecord, TLStoreProps> export type TLStoreSchema = StoreSchema<TLRecord, TLStoreProps>
/** @public */ /** @public */
export type TLStoreSnapshot = StoreSnapshot<TLRecord> export type TLSerializedStore = SerializedStore<TLRecord>
/** @public */
export type TLStoreSnapshot = SerializedStore<TLRecord>
/** @public */ /** @public */
export type TLStoreProps = { export type TLStoreProps = {

View file

@ -1,9 +1,9 @@
import { StoreSnapshot } from '@tldraw/store' import { SerializedStore } from '@tldraw/store'
import { Vec2dModel } from './misc/geometry-types' import { Vec2dModel } from './misc/geometry-types'
import { TLRecord } from './records/TLRecord' import { TLRecord } from './records/TLRecord'
/** @internal */ /** @internal */
export function CLIENT_FIXUP_SCRIPT(persistedStore: StoreSnapshot<TLRecord>) { export function CLIENT_FIXUP_SCRIPT(persistedStore: SerializedStore<TLRecord>) {
const records = Object.values(persistedStore) const records = Object.values(persistedStore)
for (let i = 0; i < records.length; i++) { for (let i = 0; i < records.length; i++) {

View file

@ -1,4 +1,5 @@
export { export {
type TLSerializedStore,
type TLStore, type TLStore,
type TLStoreProps, type TLStoreProps,
type TLStoreSchema, type TLStoreSchema,

View file

@ -1,4 +1,4 @@
import { defineMigrations, StoreSnapshot } from '@tldraw/store' import { defineMigrations, SerializedStore } from '@tldraw/store'
import { TLRecord } from './records/TLRecord' import { TLRecord } from './records/TLRecord'
const Versions = { const Versions = {
@ -15,47 +15,47 @@ export const storeMigrations = defineMigrations({
currentVersion: Versions.RemoveUserDocument, currentVersion: Versions.RemoveUserDocument,
migrators: { migrators: {
[Versions.RemoveCodeAndIconShapeTypes]: { [Versions.RemoveCodeAndIconShapeTypes]: {
up: (store: StoreSnapshot<TLRecord>) => { up: (store: SerializedStore<TLRecord>) => {
return Object.fromEntries( return Object.fromEntries(
Object.entries(store).filter( Object.entries(store).filter(
([_, v]) => v.typeName !== 'shape' || (v.type !== 'icon' && v.type !== 'code') ([_, v]) => v.typeName !== 'shape' || (v.type !== 'icon' && v.type !== 'code')
) )
) )
}, },
down: (store: StoreSnapshot<TLRecord>) => { down: (store: SerializedStore<TLRecord>) => {
// noop // noop
return store return store
}, },
}, },
[Versions.AddInstancePresenceType]: { [Versions.AddInstancePresenceType]: {
up: (store: StoreSnapshot<TLRecord>) => { up: (store: SerializedStore<TLRecord>) => {
return store return store
}, },
down: (store: StoreSnapshot<TLRecord>) => { down: (store: SerializedStore<TLRecord>) => {
return Object.fromEntries( return Object.fromEntries(
Object.entries(store).filter(([_, v]) => v.typeName !== 'instance_presence') Object.entries(store).filter(([_, v]) => v.typeName !== 'instance_presence')
) )
}, },
}, },
[Versions.RemoveTLUserAndPresenceAndAddPointer]: { [Versions.RemoveTLUserAndPresenceAndAddPointer]: {
up: (store: StoreSnapshot<TLRecord>) => { up: (store: SerializedStore<TLRecord>) => {
return Object.fromEntries( return Object.fromEntries(
Object.entries(store).filter(([_, v]) => !v.typeName.match(/^(user|user_presence)$/)) Object.entries(store).filter(([_, v]) => !v.typeName.match(/^(user|user_presence)$/))
) )
}, },
down: (store: StoreSnapshot<TLRecord>) => { down: (store: SerializedStore<TLRecord>) => {
return Object.fromEntries( return Object.fromEntries(
Object.entries(store).filter(([_, v]) => v.typeName !== 'pointer') Object.entries(store).filter(([_, v]) => v.typeName !== 'pointer')
) )
}, },
}, },
[Versions.RemoveUserDocument]: { [Versions.RemoveUserDocument]: {
up: (store: StoreSnapshot<TLRecord>) => { up: (store: SerializedStore<TLRecord>) => {
return Object.fromEntries( return Object.fromEntries(
Object.entries(store).filter(([_, v]) => !v.typeName.match('user_document')) Object.entries(store).filter(([_, v]) => !v.typeName.match('user_document'))
) )
}, },
down: (store: StoreSnapshot<TLRecord>) => { down: (store: SerializedStore<TLRecord>) => {
return store return store
}, },
}, },