tldraw/packages/tlstore/api-report.md
David Sheldrick 731da1bc77
derived presence state (#1204)
This PR adds

- A new `TLInstancePresence` record type, to collect info about the
presence state in a particular instance of the editor. This will
eventually be used to sync presence data instead of sending
instance-only state across the wire.
- **Record Scopes**

`RecordType` now has a `scope` property which can be one of three
things:
- `document`: the record belongs to the document and should be synced
and persisted freely. Currently: `TLDocument`, `TLPage`, `TLShape`, and
`TLAsset`
- `instance`: the record belongs to a single instance of the store and
should not be synced at all. It should not be persisted directly in most
cases, but rather compiled into a kind of 'instance configuration' to
store alongside the local document data so that when reopening the
associated document it can remember some of the previous instance state.
Currently: `TLInstance`, `TLInstancePageState`, `TLCamera`, `TLUser`,
`TLUserDocument`, `TLUserPresence`
- `presence`: the record belongs to a single instance of the store and
should not be persisted, but may be synced using the special presence
sync protocol. Currently just `TLInstancePresence`

This sets us up for the following changes, which are gonna be pretty
high-impact in terms of integrating tldraw into existing systems:

- Removing `instanceId` as a config option. Each instance gets a
randomly generated ID.
- We'd replace it with an `instanceConfig` option that has stuff like
selectedIds, camera positions, and so on. Then it's up to library users
to get and reinstate the instance config at persistence boundaries.
- Removing `userId` as config option, and removing the `TLUser` type
altogether.
- We might need to revisit when doing auth-enabled features like locking
shapes, but I suspect that will be separate.
2023-04-27 18:03:19 +00:00

10 KiB

API Report File for "@tldraw/tlstore"

Do not edit this file. It is a report generated by API Extractor.


import { Atom } from 'signia';
import { Computed } from 'signia';
import { Signal } from 'signia';

// @public
export type AllRecords<T extends Store<any>> = ExtractR<ExtractRecordType<T>>;

// @public
export function assertIdType<R extends BaseRecord>(id: string | undefined, type: RecordType<R, any>): asserts id is ID<R>;

// @public
export interface BaseRecord<TypeName extends string = string> {
    // (undocumented)
    readonly id: ID<this>;
    // (undocumented)
    readonly typeName: TypeName;
}

// @public
export type CollectionDiff<T> = {
    added?: Set<T>;
    removed?: Set<T>;
};

// @public (undocumented)
export function compareRecordVersions(a: RecordVersion, b: RecordVersion): -1 | 0 | 1;

// @public (undocumented)
export const compareSchemas: (a: SerializedSchema, b: SerializedSchema) => -1 | 0 | 1;

// @public
export type ComputedCache<Data, R extends BaseRecord> = {
    get(id: ID<R>): Data | undefined;
};

// @public
export function createRecordType<R extends BaseRecord>(typeName: R['typeName'], config: {
    migrations?: Migrations;
    validator: StoreValidator<R>;
    scope: Scope;
}): RecordType<R, keyof Omit<R, 'id' | 'typeName'>>;

// @public (undocumented)
export function defineMigrations<FirstVersion extends number, CurrentVersion extends number>({ firstVersion, currentVersion, migrators, subTypeKey, subTypeMigrations, }: {
    firstVersion: FirstVersion;
    currentVersion: CurrentVersion;
    migrators: {
        [version in Exclude<Range_2<FirstVersion, CurrentVersion>, FirstVersion>]: Migration;
    };
    subTypeKey?: string;
    subTypeMigrations?: Record<string, BaseMigrationsInfo>;
}): Migrations;

// @public
export function devFreeze<T>(object: T): T;

// @public (undocumented)
export function getRecordVersion(record: BaseRecord, serializedSchema: SerializedSchema): RecordVersion;

// @public
export type HistoryEntry<R extends BaseRecord = BaseRecord> = {
    changes: RecordsDiff<R>;
    source: 'remote' | 'user';
};

// @public (undocumented)
export type ID<R extends BaseRecord = BaseRecord> = string & {
    __type__: R;
};

// @internal
export class IncrementalSetConstructor<T> {
    constructor(
    previousValue: Set<T>);
    // @public
    add(item: T): void;
    // @public
    get(): {
        value: Set<T>;
        diff: CollectionDiff<T>;
    } | undefined;
    // @public
    remove(item: T): void;
}

// @public (undocumented)
export function migrate<T>({ value, migrations, fromVersion, toVersion, }: {
    value: unknown;
    migrations: Migrations;
    fromVersion: number;
    toVersion: number;
}): MigrationResult<T>;

// @public (undocumented)
export function migrateRecord<R extends BaseRecord>({ record, migrations, fromVersion, toVersion, }: {
    record: unknown;
    migrations: Migrations;
    fromVersion: number;
    toVersion: number;
}): MigrationResult<R>;

// @public (undocumented)
export type Migration<T = any> = {
    up: (oldState: T) => T;
    down: (newState: T) => T;
};

// @public (undocumented)
export enum MigrationFailureReason {
    // (undocumented)
    IncompatibleSubtype = "incompatible-subtype",
    // (undocumented)
    MigrationError = "migration-error",
    // (undocumented)
    TargetVersionTooNew = "target-version-too-new",
    // (undocumented)
    TargetVersionTooOld = "target-version-too-old",
    // (undocumented)
    UnknownType = "unknown-type",
    // (undocumented)
    UnrecognizedSubtype = "unrecognized-subtype"
}

// @public (undocumented)
export type MigrationResult<T> = {
    type: 'error';
    reason: MigrationFailureReason;
} | {
    type: 'success';
    value: T;
};

// @public (undocumented)
export interface Migrations extends BaseMigrationsInfo {
    // (undocumented)
    subTypeKey?: string;
    // (undocumented)
    subTypeMigrations?: Record<string, BaseMigrationsInfo>;
}

// @public
export type RecordsDiff<R extends BaseRecord> = {
    added: Record<string, R>;
    updated: Record<string, [from: R, to: R]>;
    removed: Record<string, R>;
};

// @public
export class RecordType<R extends BaseRecord, RequiredProperties extends keyof Omit<R, 'id' | 'typeName'>> {
    constructor(
    typeName: R['typeName'], config: {
        readonly createDefaultProperties: () => Exclude<OmitMeta<R>, RequiredProperties>;
        readonly migrations: Migrations;
        readonly validator?: {
            validate: (r: unknown) => R;
        } | StoreValidator<R>;
        readonly scope?: Scope;
    });
    clone(record: R): R;
    create(properties: Pick<R, RequiredProperties> & Omit<Partial<R>, RequiredProperties>): R;
    createCustomId(id: string): ID<R>;
    // (undocumented)
    readonly createDefaultProperties: () => Exclude<OmitMeta<R>, RequiredProperties>;
    createId(): ID<R>;
    isId(id?: string): id is ID<R>;
    isInstance: (record?: BaseRecord) => record is R;
    // (undocumented)
    readonly migrations: Migrations;
    parseId(id: string): ID<R>;
    // (undocumented)
    readonly scope: Scope;
    readonly typeName: R['typeName'];
    validate(record: unknown): R;
    // (undocumented)
    readonly validator: {
        validate: (r: unknown) => R;
    } | StoreValidator<R>;
    withDefaultProperties<DefaultProps extends Omit<Partial<R>, 'id' | 'typeName'>>(createDefaultProperties: () => DefaultProps): RecordType<R, Exclude<RequiredProperties, keyof DefaultProps>>;
}

// @public (undocumented)
export type RecordVersion = {
    rootVersion: number;
    subTypeVersion?: number;
};

// @public (undocumented)
export function reverseRecordsDiff(diff: RecordsDiff<any>): RecordsDiff<any>;

// @public (undocumented)
export interface SerializedSchema {
    recordVersions: Record<string, {
        version: number;
        subTypeVersions: Record<string, number>;
        subTypeKey: string;
    } | {
        version: number;
    }>;
    schemaVersion: number;
    storeVersion: number;
}

// @public
export function squashRecordDiffs<T extends BaseRecord>(diffs: RecordsDiff<T>[]): RecordsDiff<T>;

// @public
export class Store<R extends BaseRecord = BaseRecord, Props = unknown> {
    constructor(config: {
        initialData?: StoreSnapshot<R>;
        schema: StoreSchema<R, Props>;
        props: Props;
    });
    allRecords: () => R[];
    // (undocumented)
    applyDiff(diff: RecordsDiff<R>, runCallbacks?: boolean): void;
    clear: () => void;
    createComputedCache: <T, V extends R = R>(name: string, derive: (record: V) => T | undefined) => ComputedCache<T, V>;
    createSelectedComputedCache: <T, J, V extends R = R>(name: string, selector: (record: V) => T | undefined, derive: (input: T) => J | undefined) => ComputedCache<J, V>;
    deserialize: (snapshot: StoreSnapshot<R>) => void;
    // @internal (undocumented)
    ensureStoreIsUsable(): void;
    // (undocumented)
    extractingChanges(fn: () => void): RecordsDiff<R>;
    // (undocumented)
    _flushHistory(): void;
    get: <K extends ID<R>>(id: K) => RecFromId<K> | undefined;
    has: <K extends ID<R>>(id: K) => boolean;
    readonly history: Atom<number, RecordsDiff<R>>;
    // @internal (undocumented)
    isPossiblyCorrupted(): boolean;
    listen: (listener: StoreListener<R>) => () => void;
    // @internal (undocumented)
    markAsPossiblyCorrupted(): void;
    mergeRemoteChanges: (fn: () => void) => void;
    onAfterChange?: (prev: R, next: R) => void;
    onAfterCreate?: (record: R) => void;
    onAfterDelete?: (prev: R) => void;
    onBeforeDelete?: (prev: R) => void;
    // (undocumented)
    readonly props: Props;
    put: (records: R[], phaseOverride?: 'initialize') => void;
    readonly query: StoreQueries<R>;
    remove: (ids: ID<R>[]) => void;
    // (undocumented)
    readonly schema: StoreSchema<R, Props>;
    serialize: (filter?: ((record: R) => boolean) | undefined) => StoreSnapshot<R>;
    unsafeGetWithoutCapture: <K extends ID<R>>(id: K) => RecFromId<K> | undefined;
    update: <K extends ID<R>>(id: K, updater: (record: RecFromId<K>) => RecFromId<K>) => void;
    // (undocumented)
    validate(phase: 'createRecord' | 'initialize' | 'tests' | 'updateRecord'): void;
}

// @public (undocumented)
export type StoreError = {
    error: Error;
    phase: 'createRecord' | 'initialize' | 'tests' | 'updateRecord';
    recordBefore?: unknown;
    recordAfter: unknown;
    isExistingValidationIssue: boolean;
};

// @public
export type StoreListener<R extends BaseRecord> = (entry: HistoryEntry<R>) => void;

// @public (undocumented)
export class StoreSchema<R extends BaseRecord, P = unknown> {
    // (undocumented)
    static create<R extends BaseRecord, P = unknown>(types: {
        [TypeName in R['typeName']]: {
            createId: any;
        };
    }, options?: StoreSchemaOptions<R, P>): StoreSchema<R, P>;
    // (undocumented)
    get currentStoreVersion(): number;
    // @internal (undocumented)
    derivePresenceState(store: Store<R, P>): Signal<null | R> | undefined;
    // @internal (undocumented)
    ensureStoreIsUsable(store: Store<R, P>): void;
    // (undocumented)
    migratePersistedRecord(record: R, persistedSchema: SerializedSchema, direction?: 'down' | 'up'): MigrationResult<R>;
    // (undocumented)
    migrateStoreSnapshot(storeSnapshot: StoreSnapshot<R>, persistedSchema: SerializedSchema): MigrationResult<StoreSnapshot<R>>;
    // (undocumented)
    serialize(): SerializedSchema;
    // (undocumented)
    serializeEarliestVersion(): SerializedSchema;
    // (undocumented)
    readonly types: {
        [Record in R as Record['typeName']]: RecordType<R, any>;
    };
    // (undocumented)
    validateRecord(store: Store<R>, record: R, phase: 'createRecord' | 'initialize' | 'tests' | 'updateRecord', recordBefore: null | R): R;
}

// @public (undocumented)
export type StoreSchemaOptions<R extends BaseRecord, P> = {
    snapshotMigrations?: Migrations;
    onValidationFailure?: (data: {
        error: unknown;
        store: Store<R>;
        record: R;
        phase: 'createRecord' | 'initialize' | 'tests' | 'updateRecord';
        recordBefore: null | R;
    }) => R;
    ensureStoreIsUsable?: (store: Store<R, P>) => void;
    derivePresenceState?: (store: Store<R, P>) => Signal<null | R>;
};

// @public
export type StoreSnapshot<R extends BaseRecord> = Record<string, R>;

// @public (undocumented)
export type StoreValidator<R extends BaseRecord> = {
    validate: (record: unknown) => R;
};

// @public (undocumented)
export type StoreValidators<R extends BaseRecord> = {
    [K in R['typeName']]: StoreValidator<Extract<R, {
        typeName: K;
    }>>;
};

// (No @packageDocumentation comment for this package)