da35f2bd75
First draft of the new bindings API. We'll follow this up with some API refinements, tests, documentation, and examples. Bindings are a new record type for establishing relationships between two shapes so they can update at the same time. ### Change Type - [x] `sdk` — Changes the tldraw SDK - [x] `feature` — New feature ### Release Notes #### Breaking changes - The `start` and `end` properties on `TLArrowShape` no longer have `type: point | binding`. Instead, they're always a point, which may be out of date if a binding exists. To check for & retrieve arrow bindings, use `getArrowBindings(editor, shape)` instead. - `getArrowTerminalsInArrowSpace` must be passed a `TLArrowBindings` as a third argument: `getArrowTerminalsInArrowSpace(editor, shape, getArrowBindings(editor, shape))` - The following types have been renamed: - `ShapeProps` -> `RecordProps` - `ShapePropsType` -> `RecordPropsType` - `TLShapePropsMigrations` -> `TLPropsMigrations` - `SchemaShapeInfo` -> `SchemaPropsInfo` --------- Co-authored-by: David Sheldrick <d.j.sheldrick@gmail.com>
14 KiB
14 KiB
API Report File for "@tldraw/store"
Do not edit this file. It is a report generated by API Extractor.
import { Atom } from '@tldraw/state';
import { Computed } from '@tldraw/state';
import { Result } from '@tldraw/utils';
// @public
export type AllRecords<T extends Store<any>> = ExtractR<ExtractRecordType<T>>;
// @public
export function assertIdType<R extends UnknownRecord>(id: string | undefined, type: RecordType<R, any>): asserts id is IdOf<R>;
// @public
export interface BaseRecord<TypeName extends string, Id extends RecordId<UnknownRecord>> {
// (undocumented)
readonly id: Id;
// (undocumented)
readonly typeName: TypeName;
}
// @public
export type CollectionDiff<T> = {
added?: Set<T>;
removed?: Set<T>;
};
// @public
export type ComputedCache<Data, R extends UnknownRecord> = {
get(id: IdOf<R>): Data | undefined;
};
// @internal (undocumented)
export function createEmptyRecordsDiff<R extends UnknownRecord>(): RecordsDiff<R>;
// @public
export function createMigrationIds<const ID extends string, const Versions extends Record<string, number>>(sequenceId: ID, versions: Versions): {
[K in keyof Versions]: `${ID}/${Versions[K]}`;
};
// @public
export function createMigrationSequence({ sequence, sequenceId, retroactive, }: {
retroactive?: boolean;
sequence: Array<Migration | StandaloneDependsOn>;
sequenceId: string;
}): MigrationSequence;
// @internal (undocumented)
export function createRecordMigrationSequence(opts: {
filter?: (record: UnknownRecord) => boolean;
recordType: string;
retroactive?: boolean;
sequence: Omit<Extract<Migration, {
scope: 'record';
}>, 'scope'>[];
sequenceId: string;
}): MigrationSequence;
// @public
export function createRecordType<R extends UnknownRecord>(typeName: R['typeName'], config: {
ephemeralKeys?: {
readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean;
};
scope: RecordScope;
validator?: StoreValidator<R>;
}): RecordType<R, keyof Omit<R, 'id' | 'typeName'>>;
// @public @deprecated (undocumented)
export function defineMigrations(opts: {
currentVersion?: number;
firstVersion?: number;
migrators?: Record<number, LegacyMigration>;
subTypeKey?: string;
subTypeMigrations?: Record<string, LegacyBaseMigrationsInfo>;
}): LegacyMigrations;
// @public
export function devFreeze<T>(object: T): T;
// @public
export type HistoryEntry<R extends UnknownRecord = UnknownRecord> = {
changes: RecordsDiff<R>;
source: ChangeSource;
};
// @public (undocumented)
export type IdOf<R extends UnknownRecord> = R['id'];
// @internal
export class IncrementalSetConstructor<T> {
constructor(
previousValue: Set<T>);
// @public
add(item: T): void;
// @public
get(): {
diff: CollectionDiff<T>;
value: Set<T>;
} | undefined;
// @public
remove(item: T): void;
}
// @internal
export function isRecordsDiffEmpty<T extends UnknownRecord>(diff: RecordsDiff<T>): boolean;
// @public (undocumented)
export type LegacyMigration<Before = any, After = any> = {
down: (newState: After) => Before;
up: (oldState: Before) => After;
};
// @public (undocumented)
export interface LegacyMigrations extends LegacyBaseMigrationsInfo {
// (undocumented)
subTypeKey?: string;
// (undocumented)
subTypeMigrations?: Record<string, LegacyBaseMigrationsInfo>;
}
// @public (undocumented)
export type Migration = {
readonly dependsOn?: readonly MigrationId[] | undefined;
readonly id: MigrationId;
} & ({
readonly down?: (newState: SerializedStore<UnknownRecord>) => SerializedStore<UnknownRecord> | void;
readonly scope: 'store';
readonly up: (oldState: SerializedStore<UnknownRecord>) => SerializedStore<UnknownRecord> | void;
} | {
readonly down?: (newState: UnknownRecord) => UnknownRecord | void;
readonly filter?: (record: UnknownRecord) => boolean;
readonly scope: 'record';
readonly up: (oldState: UnknownRecord) => UnknownRecord | void;
});
// @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 MigrationId = `${string}/${number}`;
// @public (undocumented)
export type MigrationResult<T> = {
reason: MigrationFailureReason;
type: 'error';
} | {
type: 'success';
value: T;
};
// @public (undocumented)
export interface MigrationSequence {
retroactive: boolean;
// (undocumented)
sequence: Migration[];
// (undocumented)
sequenceId: string;
}
// @internal (undocumented)
export function parseMigrationId(id: MigrationId): {
sequenceId: string;
version: number;
};
// @public (undocumented)
export type RecordId<R extends UnknownRecord> = string & {
__type__: R;
};
// @public
export type RecordsDiff<R extends UnknownRecord> = {
added: Record<IdOf<R>, R>;
removed: Record<IdOf<R>, R>;
updated: Record<IdOf<R>, [from: R, to: R]>;
};
// @public
export class RecordType<R extends UnknownRecord, RequiredProperties extends keyof Omit<R, 'id' | 'typeName'>> {
constructor(
typeName: R['typeName'], config: {
readonly createDefaultProperties: () => Exclude<OmitMeta<R>, RequiredProperties>;
readonly ephemeralKeys?: {
readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean;
};
readonly scope?: RecordScope;
readonly validator?: StoreValidator<R>;
});
clone(record: R): R;
create(properties: Pick<R, RequiredProperties> & Omit<Partial<R>, RequiredProperties>): R;
// @deprecated
createCustomId(id: string): IdOf<R>;
// (undocumented)
readonly createDefaultProperties: () => Exclude<OmitMeta<R>, RequiredProperties>;
createId(customUniquePart?: string): IdOf<R>;
// (undocumented)
readonly ephemeralKeys?: {
readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean;
};
// (undocumented)
readonly ephemeralKeySet: ReadonlySet<string>;
isId(id?: string): id is IdOf<R>;
isInstance: (record?: UnknownRecord) => record is R;
parseId(id: IdOf<R>): string;
// (undocumented)
readonly scope: RecordScope;
readonly typeName: R['typeName'];
validate(record: unknown, recordBefore?: R): R;
// (undocumented)
readonly validator: StoreValidator<R>;
withDefaultProperties<DefaultProps extends Omit<Partial<R>, 'id' | 'typeName'>>(createDefaultProperties: () => DefaultProps): RecordType<R, Exclude<RequiredProperties, keyof DefaultProps>>;
}
// @public (undocumented)
export function reverseRecordsDiff(diff: RecordsDiff<any>): RecordsDiff<any>;
// @public (undocumented)
export type SerializedSchema = SerializedSchemaV1 | SerializedSchemaV2;
// @public (undocumented)
export interface SerializedSchemaV1 {
recordVersions: Record<string, {
subTypeKey: string;
subTypeVersions: Record<string, number>;
version: number;
} | {
version: number;
}>;
schemaVersion: 1;
storeVersion: number;
}
// @public (undocumented)
export interface SerializedSchemaV2 {
// (undocumented)
schemaVersion: 2;
// (undocumented)
sequences: {
[sequenceId: string]: number;
};
}
// @public
export type SerializedStore<R extends UnknownRecord> = Record<IdOf<R>, R>;
// @public
export function squashRecordDiffs<T extends UnknownRecord>(diffs: RecordsDiff<T>[]): RecordsDiff<T>;
// @internal
export function squashRecordDiffsMutable<T extends UnknownRecord>(target: RecordsDiff<T>, diffs: RecordsDiff<T>[]): void;
// @public (undocumented)
export type StandaloneDependsOn = {
readonly dependsOn: readonly MigrationId[];
};
// @public
export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
constructor(config: {
schema: StoreSchema<R, Props>;
initialData?: SerializedStore<R>;
id?: string;
props: Props;
});
// @internal (undocumented)
addHistoryInterceptor(fn: (entry: HistoryEntry<R>, source: ChangeSource) => void): () => void;
allRecords: () => R[];
// (undocumented)
applyDiff(diff: RecordsDiff<R>, { runCallbacks, ignoreEphemeralKeys, }?: {
ignoreEphemeralKeys?: boolean;
runCallbacks?: boolean;
}): void;
// @internal (undocumented)
atomic<T>(fn: () => T, runCallbacks?: boolean): T;
clear: () => void;
createComputedCache: <T, V extends R = R>(name: string, derive: (record: V) => T | undefined, isEqual?: ((a: V, b: V) => boolean) | 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>;
// @internal (undocumented)
ensureStoreIsUsable(): void;
extractingChanges(fn: () => void): RecordsDiff<R>;
filterChangesByScope(change: RecordsDiff<R>, scope: RecordScope): {
added: { [K in IdOf<R>]: R; };
removed: { [K in IdOf<R>]: R; };
updated: { [K_1 in IdOf<R>]: [from: R, to: R]; };
} | null;
// (undocumented)
_flushHistory(): void;
get: <K extends IdOf<R>>(id: K) => RecFromId<K> | undefined;
getSnapshot(scope?: 'all' | RecordScope): StoreSnapshot<R>;
has: <K extends IdOf<R>>(id: K) => boolean;
readonly history: Atom<number, RecordsDiff<R>>;
readonly id: string;
// @internal (undocumented)
isPossiblyCorrupted(): boolean;
listen: (onHistory: StoreListener<R>, filters?: Partial<StoreListenerFilters>) => () => void;
loadSnapshot(snapshot: StoreSnapshot<R>): void;
// @internal (undocumented)
markAsPossiblyCorrupted(): void;
mergeRemoteChanges: (fn: () => void) => void;
migrateSnapshot(snapshot: StoreSnapshot<R>): StoreSnapshot<R>;
onAfterChange?: (prev: R, next: R, source: 'remote' | 'user') => void;
onAfterCreate?: (record: R, source: 'remote' | 'user') => void;
onAfterDelete?: (prev: R, source: 'remote' | 'user') => void;
onBeforeChange?: (prev: R, next: R, source: 'remote' | 'user') => R;
onBeforeCreate?: (next: R, source: 'remote' | 'user') => R;
onBeforeDelete?: (prev: R, source: 'remote' | 'user') => false | void;
// (undocumented)
readonly props: Props;
put: (records: R[], phaseOverride?: 'initialize') => void;
readonly query: StoreQueries<R>;
remove: (ids: IdOf<R>[]) => void;
// (undocumented)
readonly schema: StoreSchema<R, Props>;
// (undocumented)
readonly scopedTypes: {
readonly [K in RecordScope]: ReadonlySet<R['typeName']>;
};
serialize: (scope?: 'all' | RecordScope) => SerializedStore<R>;
unsafeGetWithoutCapture: <K extends IdOf<R>>(id: K) => RecFromId<K> | undefined;
update: <K extends IdOf<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;
isExistingValidationIssue: boolean;
phase: 'createRecord' | 'initialize' | 'tests' | 'updateRecord';
recordAfter: unknown;
recordBefore?: unknown;
};
// @public
export type StoreListener<R extends UnknownRecord> = (entry: HistoryEntry<R>) => void;
// @public (undocumented)
export class StoreSchema<R extends UnknownRecord, P = unknown> {
// (undocumented)
static create<R extends UnknownRecord, P = unknown>(types: {
[TypeName in R['typeName']]: {
createId: any;
};
}, options?: StoreSchemaOptions<R, P>): StoreSchema<R, P>;
// @internal (undocumented)
createIntegrityChecker(store: Store<R, P>): (() => void) | undefined;
// (undocumented)
getMigrationsSince(persistedSchema: SerializedSchema): Result<Migration[], string>;
// @internal (undocumented)
getType(typeName: string): RecordType<R, any>;
// (undocumented)
migratePersistedRecord(record: R, persistedSchema: SerializedSchema, direction?: 'down' | 'up'): MigrationResult<R>;
// (undocumented)
migrateStoreSnapshot(snapshot: StoreSnapshot<R>): MigrationResult<SerializedStore<R>>;
// (undocumented)
readonly migrations: Record<string, MigrationSequence>;
// (undocumented)
serialize(): SerializedSchemaV2;
// @deprecated (undocumented)
serializeEarliestVersion(): SerializedSchema;
// (undocumented)
readonly sortedMigrations: readonly Migration[];
// (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 UnknownRecord, P> = {
createIntegrityChecker?: (store: Store<R, P>) => void;
onValidationFailure?: (data: {
error: unknown;
phase: 'createRecord' | 'initialize' | 'tests' | 'updateRecord';
record: R;
recordBefore: null | R;
store: Store<R>;
}) => R;
migrations?: MigrationSequence[];
};
// @public (undocumented)
export type StoreSnapshot<R extends UnknownRecord> = {
schema: SerializedSchema;
store: SerializedStore<R>;
};
// @public (undocumented)
export type StoreValidator<R extends UnknownRecord> = {
validate: (record: unknown) => R;
validateUsingKnownGoodVersion?: (knownGoodVersion: R, record: unknown) => R;
};
// @public (undocumented)
export type StoreValidators<R extends UnknownRecord> = {
[K in R['typeName']]: StoreValidator<Extract<R, {
typeName: K;
}>>;
};
// @public (undocumented)
export type UnknownRecord = BaseRecord<string, RecordId<UnknownRecord>>;
// (No @packageDocumentation comment for this package)