import { Atom } from '@tldraw/state';
import { Computed } from '@tldraw/state';
import { Expand } from '@tldraw/utils';
import { Result } from '@tldraw/utils';
import { Signal } from '@tldraw/state';
import { UNINITIALIZED } from '@tldraw/state';

/**
 * Assert whether an id correspond to a record type.
 *
 * @example
 *
 * ```ts
 * assertIdType(myId, "shape")
 * ```
 *
 * @param id - The id to check.
 * @param type - The type of the record.
 * @public
 */
export declare function assertIdType<R extends UnknownRecord>(id: string | undefined, type: RecordType<R, any>): asserts id is IdOf<R>;

/**
 * A drop-in replacement for Map that stores values in atoms and can be used in reactive contexts.
 * @public
 */
export declare class AtomMap<K, V> implements Map<K, V> {
    private readonly name;
    private atoms;
    constructor(name: string, entries?: Iterable<[K, V]>);
    /* Excluded from this release type: getAtom */
    get(key: K): undefined | V;
    __unsafe__getWithoutCapture(key: K): undefined | V;
    has(key: K): boolean;
    __unsafe__hasWithoutCapture(key: K): boolean;
    set(key: K, value: V): this;
    update(key: K, updater: (value: V) => V): void;
    delete(key: K): boolean;
    deleteMany(keys: Iterable<K>): [K, V][];
    clear(): void;
    entries(): Generator<[K, V], undefined, unknown>;
    keys(): Generator<K, undefined, unknown>;
    values(): Generator<V, undefined, unknown>;
    get size(): number;
    forEach(callbackfn: (value: V, key: K, map: AtomMap<K, V>) => void, thisArg?: any): void;
    [Symbol.iterator](): Generator<[K, V], undefined, unknown>;
    [Symbol.toStringTag]: string;
}

/**
 * The base record that all records must extend.
 *
 * @public
 */
export declare interface BaseRecord<TypeName extends string, Id extends RecordId<UnknownRecord>> {
    readonly id: Id;
    readonly typeName: TypeName;
}

/** @public */
export declare type ChangeSource = 'remote' | 'user';

/**
 * A diff describing the changes to a collection.
 *
 * @public
 */
export declare interface CollectionDiff<T> {
    added?: Set<T>;
    removed?: Set<T>;
}

/**
 * A record store is a collection of records of different types.
 *
 * @public
 */
export declare interface ComputedCache<Data, R extends UnknownRecord> {
    get(id: IdOf<R>): Data | undefined;
}

/**
 * Free version of {@link Store.createComputedCache}.
 *
 * @example
 * ```ts
 * const myCache = createComputedCache('myCache', (editor: Editor, shape: TLShape) => {
 *     return editor.getSomethingExpensive(shape)
 * })
 *
 * myCache.get(editor, shape.id)
 * ```
 *
 * @public
 */
export declare function createComputedCache<Context extends StoreObject<any>, Result, Record extends StoreObjectRecordType<Context> = StoreObjectRecordType<Context>>(name: string, derive: (context: Context, record: Record) => Result | undefined, opts?: CreateComputedCacheOpts<Result, Record>): {
    get(context: Context, id: IdOf<Record>): Result | undefined;
};

/** @public */
export declare interface CreateComputedCacheOpts<Data, R extends UnknownRecord> {
    areRecordsEqual?(a: R, b: R): boolean;
    areResultsEqual?(a: Data, b: Data): boolean;
}

/* Excluded from this release type: createEmptyRecordsDiff */

/**
 * Creates a named set of migration ids given a named set of version numbers and a sequence id.
 *
 * See the [migration guide](https://tldraw.dev/docs/persistence#Migrations) for more info on how to use this API.
 * @public
 * @public
 */
export declare function createMigrationIds<const ID extends string, const Versions extends Record<string, number>>(sequenceId: ID, versions: Versions): {
    [K in keyof Versions]: `${ID}/${Versions[K]}`;
};

/**
 * Creates a migration sequence.
 * See the [migration guide](https://tldraw.dev/docs/persistence#Migrations) for more info on how to use this API.
 * @public
 */
export declare function createMigrationSequence({ sequence, sequenceId, retroactive, }: {
    retroactive?: boolean;
    sequence: Array<Migration | StandaloneDependsOn>;
    sequenceId: string;
}): MigrationSequence;

/* Excluded from this release type: createRecordMigrationSequence */

/**
 * Create a record type.
 *
 * @example
 *
 * ```ts
 * const Book = createRecordType<Book>('book')
 * ```
 *
 * @param typeName - The name of the type to create.
 * @public
 */
export declare 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 use `createShapePropsMigrationSequence` instead. See [the docs](https://tldraw.dev/docs/persistence#Updating-legacy-shape-migrations-defineMigrations) for how to migrate.
 */
export declare function defineMigrations(opts: {
    currentVersion?: number;
    firstVersion?: number;
    migrators?: Record<number, LegacyMigration>;
    subTypeKey?: string;
    subTypeMigrations?: Record<string, LegacyBaseMigrationsInfo>;
}): LegacyMigrations;

/**
 * Freeze an object when in development mode. Copied from
 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
 *
 * @example
 *
 * ```ts
 * const frozen = devFreeze({ a: 1 })
 * ```
 *
 * @param object - The object to freeze.
 * @returns The frozen object when in development mode, or else the object when in other modes.
 * @public
 */
export declare function devFreeze<T>(object: T): T;

/**
 * An entry containing changes that originated either by user actions or remote changes.
 *
 * @public
 */
export declare interface HistoryEntry<R extends UnknownRecord = UnknownRecord> {
    changes: RecordsDiff<R>;
    source: ChangeSource;
}

/** @public */
export declare type IdOf<R extends UnknownRecord> = R['id'];

/* Excluded from this release type: IncrementalSetConstructor */

/* Excluded from this release type: isRecordsDiffEmpty */

/** @public */
export declare interface LegacyBaseMigrationsInfo {
    firstVersion: number;
    currentVersion: number;
    migrators: {
        [version: number]: LegacyMigration;
    };
}

/** @public */
export declare interface LegacyMigration<Before = any, After = any> {
    up: (oldState: Before) => After;
    down: (newState: After) => Before;
}

/** @public */
export declare interface LegacyMigrations extends LegacyBaseMigrationsInfo {
    subTypeKey?: string;
    subTypeMigrations?: Record<string, LegacyBaseMigrationsInfo>;
}

/** @public */
export declare 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 */
export declare enum MigrationFailureReason {
    IncompatibleSubtype = "incompatible-subtype",
    UnknownType = "unknown-type",
    TargetVersionTooNew = "target-version-too-new",
    TargetVersionTooOld = "target-version-too-old",
    MigrationError = "migration-error",
    UnrecognizedSubtype = "unrecognized-subtype"
}

/** @public */
export declare type MigrationId = `${string}/${number}`;

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

/** @public */
export declare interface MigrationSequence {
    sequenceId: string;
    /**
     * retroactive should be true if the migrations should be applied to snapshots that were created before
     * this migration sequence was added to the schema.
     *
     * In general:
     *
     * - retroactive should be true when app developers create their own new migration sequences.
     * - retroactive should be false when library developers ship a migration sequence. When you install a library for the first time, any migrations that were added in the library before that point should generally _not_ be applied to your existing data.
     */
    retroactive: boolean;
    sequence: Migration[];
}

/* Excluded from this release type: parseMigrationId */

/** @public */
export declare type QueryExpression<R extends object> = {
    [k in keyof R & string]?: QueryValueMatcher<R[k]>;
};

/** @public */
export declare type QueryValueMatcher<T> = {
    eq: T;
} | {
    gt: number;
} | {
    neq: T;
};

/** @public */
export declare type RecordFromId<K extends RecordId<UnknownRecord>> = K extends RecordId<infer R> ? R : never;

/** @public */
export declare type RecordId<R extends UnknownRecord> = string & {
    __type__: R;
};

/**
 * Defines the scope of the record
 *
 * session: The record belongs to a single instance of the store. It should not be synced, and any persistence logic should 'de-instance-ize' the record before persisting it, and apply the reverse when rehydrating.
 * document: The record is persisted and synced. It is available to all store instances.
 * presence: The record belongs to a single instance of the store. It may be synced to other instances, but other instances should not make changes to it. It should not be persisted.
 *
 * @public
 * */
export declare type RecordScope = 'document' | 'presence' | 'session';

/**
 * A diff describing the changes to a record.
 *
 * @public
 */
export declare interface RecordsDiff<R extends UnknownRecord> {
    added: Record<IdOf<R>, R>;
    updated: Record<IdOf<R>, [from: R, to: R]>;
    removed: Record<IdOf<R>, R>;
}

/**
 * A record type is a type that can be stored in a record store. It is created with
 * `createRecordType`.
 *
 * @public
 */
export declare class RecordType<R extends UnknownRecord, RequiredProperties extends keyof Omit<R, 'id' | 'typeName'>> {
    /**
     * The unique type associated with this record.
     *
     * @public
     * @readonly
     */
    readonly typeName: R['typeName'];
    readonly createDefaultProperties: () => Exclude<Omit<R, 'id' | 'typeName'>, RequiredProperties>;
    readonly validator: StoreValidator<R>;
    readonly ephemeralKeys?: {
        readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean;
    };
    readonly ephemeralKeySet: ReadonlySet<string>;
    readonly scope: RecordScope;
    constructor(
    /**
     * The unique type associated with this record.
     *
     * @public
     * @readonly
     */
    typeName: R['typeName'], config: {
        readonly createDefaultProperties: () => Exclude<Omit<R, 'id' | 'typeName'>, RequiredProperties>;
        readonly ephemeralKeys?: {
            readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean;
        };
        readonly scope?: RecordScope;
        readonly validator?: StoreValidator<R>;
    });
    /**
     * Create a new record of this type.
     *
     * @param properties - The properties of the record.
     * @returns The new record.
     */
    create(properties: Expand<Pick<R, RequiredProperties> & Omit<Partial<R>, RequiredProperties>>): R;
    /**
     * Clone a record of this type.
     *
     * @param record - The record to clone.
     * @returns The cloned record.
     * @public
     */
    clone(record: R): R;
    /**
     * Create a new ID for this record type.
     *
     * @example
     *
     * ```ts
     * const id = recordType.createId()
     * ```
     *
     * @returns The new ID.
     * @public
     */
    createId(customUniquePart?: string): IdOf<R>;
    /**
     * Create a new ID for this record type based on the given ID.
     *
     * @example
     *
     * ```ts
     * const id = recordType.createCustomId('myId')
     * ```
     *
     * @deprecated - Use `createId` instead.
     * @param id - The ID to base the new ID on.
     * @returns The new ID.
     */
    createCustomId(id: string): IdOf<R>;
    /**
     * Takes an id like `user:123` and returns the part after the colon `123`
     *
     * @param id - The id
     * @returns
     */
    parseId(id: IdOf<R>): string;
    /**
     * Check whether a record is an instance of this record type.
     *
     * @example
     *
     * ```ts
     * const result = recordType.isInstance(someRecord)
     * ```
     *
     * @param record - The record to check.
     * @returns Whether the record is an instance of this record type.
     */
    isInstance(record?: UnknownRecord): record is R;
    /**
     * Check whether an id is an id of this type.
     *
     * @example
     *
     * ```ts
     * const result = recordType.isIn('someId')
     * ```
     *
     * @param id - The id to check.
     * @returns Whether the id is an id of this type.
     */
    isId(id?: string): id is IdOf<R>;
    /**
     * Create a new RecordType that has the same type name as this RecordType and includes the given
     * default properties.
     *
     * @example
     *
     * ```ts
     * const authorType = createRecordType('author', () => ({ living: true }))
     * const deadAuthorType = authorType.withDefaultProperties({ living: false })
     * ```
     *
     * @param createDefaultProperties - A function that returns the default properties of the new RecordType.
     * @returns The new RecordType.
     */
    withDefaultProperties<DefaultProps extends Omit<Partial<R>, 'id' | 'typeName'>>(createDefaultProperties: () => DefaultProps): RecordType<R, Exclude<RequiredProperties, keyof DefaultProps>>;
    /**
     * Check that the passed in record passes the validations for this type. Returns its input
     * correctly typed if it does, but throws an error otherwise.
     */
    validate(record: unknown, recordBefore?: R): R;
}

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

/** @public */
export declare type RSIndex<R extends UnknownRecord, Property extends string & keyof R = string & keyof R> = Computed<RSIndexMap<R, Property>, RSIndexDiff<R, Property>>;

/** @public */
export declare type RSIndexDiff<R extends UnknownRecord, Property extends string & keyof R = string & keyof R> = Map<R[Property], CollectionDiff<IdOf<R>>>;

/** @public */
export declare type RSIndexMap<R extends UnknownRecord, Property extends string & keyof R = string & keyof R> = Map<R[Property], Set<IdOf<R>>>;

/** @public */
export declare type SerializedSchema = SerializedSchemaV1 | SerializedSchemaV2;

/** @public */
export declare interface SerializedSchemaV1 {
    /** Schema version is the version for this type you're looking at right now */
    schemaVersion: 1;
    /**
     * Store version is the version for the structure of the store. e.g. higher level structure like
     * removing or renaming a record type.
     */
    storeVersion: number;
    /** Record versions are the versions for each record type. e.g. adding a new field to a record */
    recordVersions: Record<string, {
        subTypeKey: string;
        subTypeVersions: Record<string, number>;
        version: number;
    } | {
        version: number;
    }>;
}

/** @public */
export declare interface SerializedSchemaV2 {
    schemaVersion: 2;
    sequences: {
        [sequenceId: string]: number;
    };
}

/**
 * A serialized snapshot of the record store's values.
 *
 * @public
 */
export declare type SerializedStore<R extends UnknownRecord> = Record<IdOf<R>, R>;

/**
 * Squash a collection of diffs into a single diff.
 *
 * @param diffs - An array of diffs to squash.
 * @returns A single diff that represents the squashed diffs.
 * @public
 */
export declare function squashRecordDiffs<T extends UnknownRecord>(diffs: RecordsDiff<T>[]): RecordsDiff<T>;

/* Excluded from this release type: squashRecordDiffsMutable */

/** @public */
export declare interface StandaloneDependsOn {
    readonly dependsOn: readonly MigrationId[];
}

/**
 * A store of records.
 *
 * @public
 */
export declare class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
    /**
     * The random id of the store.
     */
    readonly id: string;
    /* Excluded from this release type: records */
    /**
     * An atom containing the store's history.
     *
     * @public
     * @readonly
     */
    readonly history: Atom<number, RecordsDiff<R>>;
    /**
     * A StoreQueries instance for this store.
     *
     * @public
     * @readonly
     */
    readonly query: StoreQueries<R>;
    /* Excluded from this release type: listeners */
    /* Excluded from this release type: historyAccumulator */
    /* Excluded from this release type: historyReactor */
    /* Excluded from this release type: cancelHistoryReactor */
    readonly schema: StoreSchema<R, Props>;
    readonly props: Props;
    readonly scopedTypes: {
        readonly [K in RecordScope]: ReadonlySet<R['typeName']>;
    };
    readonly sideEffects: StoreSideEffects<R>;
    constructor(config: {
        /**
         * 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.
         */
        schema: StoreSchema<R, Props>;
        /** The store's initial data. */
        initialData?: SerializedStore<R>;
        id?: string;
        props: Props;
    });
    _flushHistory(): void;
    dispose(): void;
    /**
     * Filters out non-document changes from a diff. Returns null if there are no changes left.
     * @param change - the records diff
     * @param scope - the records scope
     * @returns
     */
    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;
    /**
     * Update the history with a diff of changes.
     *
     * @param changes - The changes to add to the history.
     */
    private updateHistory;
    validate(phase: 'createRecord' | 'initialize' | 'tests' | 'updateRecord'): void;
    /**
     * Add some records to the store. It's an error if they already exist.
     *
     * @param records - The records to add.
     * @param phaseOverride - The phase override.
     * @public
     */
    put(records: R[], phaseOverride?: 'initialize'): void;
    /**
     * Remove some records from the store via their ids.
     *
     * @param ids - The ids of the records to remove.
     * @public
     */
    remove(ids: IdOf<R>[]): void;
    /**
     * Get the value of a store record by its id.
     *
     * @param id - The id of the record to get.
     * @public
     */
    get<K extends IdOf<R>>(id: K): RecordFromId<K> | undefined;
    /**
     * Get the value of a store record by its id without updating its epoch.
     *
     * @param id - The id of the record to get.
     * @public
     */
    unsafeGetWithoutCapture<K extends IdOf<R>>(id: K): RecordFromId<K> | undefined;
    /**
     * Creates a JSON payload from the record store.
     *
     * @param scope - The scope of records to serialize. Defaults to 'document'.
     * @returns The record store snapshot as a JSON payload.
     */
    serialize(scope?: 'all' | RecordScope): SerializedStore<R>;
    /**
     * Get a serialized snapshot of the store and its schema.
     *
     * ```ts
     * const snapshot = store.getStoreSnapshot()
     * store.loadStoreSnapshot(snapshot)
     * ```
     *
     * @param scope - The scope of records to serialize. Defaults to 'document'.
     *
     * @public
     */
    getStoreSnapshot(scope?: 'all' | RecordScope): StoreSnapshot<R>;
    /**
     * @deprecated use `getSnapshot` from the 'tldraw' package instead.
     */
    getSnapshot(scope?: 'all' | RecordScope): StoreSnapshot<R>;
    /**
     * Migrate a serialized snapshot of the store and its schema.
     *
     * ```ts
     * const snapshot = store.getSnapshot()
     * store.migrateSnapshot(snapshot)
     * ```
     *
     * @param snapshot - The snapshot to load.
     * @public
     */
    migrateSnapshot(snapshot: StoreSnapshot<R>): StoreSnapshot<R>;
    /**
     * Load a serialized snapshot.
     *
     * ```ts
     * const snapshot = store.getStoreSnapshot()
     * store.loadStoreSnapshot(snapshot)
     * ```
     *
     * @param snapshot - The snapshot to load.
     * @public
     */
    loadStoreSnapshot(snapshot: StoreSnapshot<R>): void;
    /**
     * @public
     * @deprecated use `loadSnapshot` from the 'tldraw' package instead.
     */
    loadSnapshot(snapshot: StoreSnapshot<R>): void;
    /**
     * Get an array of all values in the store.
     *
     * @returns An array of all values in the store.
     * @public
     */
    allRecords(): R[];
    /**
     * Removes all records from the store.
     *
     * @public
     */
    clear(): void;
    /**
     * Update a record. To update multiple records at once, use the `update` method of the
     * `TypedStore` class.
     *
     * @param id - The id of the record to update.
     * @param updater - A function that updates the record.
     */
    update<K extends IdOf<R>>(id: K, updater: (record: RecordFromId<K>) => RecordFromId<K>): void;
    /**
     * Get whether the record store has a id.
     *
     * @param id - The id of the record to check.
     * @public
     */
    has<K extends IdOf<R>>(id: K): boolean;
    /**
     * Add a new listener to the store.
     *
     * @param onHistory - The listener to call when the store updates.
     * @param filters - Filters to apply to the listener.
     * @returns A function to remove the listener.
     */
    listen(onHistory: StoreListener<R>, filters?: Partial<StoreListenerFilters>): () => void;
    private isMergingRemoteChanges;
    /**
     * Merge changes from a remote source without triggering listeners.
     *
     * @param fn - A function that merges the external changes.
     * @public
     */
    mergeRemoteChanges(fn: () => void): void;
    /**
     * Run `fn` and return a {@link RecordsDiff} of the changes that occurred as a result.
     */
    extractingChanges(fn: () => void): RecordsDiff<R>;
    applyDiff(diff: RecordsDiff<R>, { runCallbacks, ignoreEphemeralKeys, }?: {
        ignoreEphemeralKeys?: boolean;
        runCallbacks?: boolean;
    }): void;
    /**
     * Create a cache based on values in the store. Pass in a function that takes and ID and a
     * signal for the underlying record. Return a signal (usually a computed) for the cached value.
     * For simple derivations, use {@link Store.createComputedCache}. This function is useful if you
     * need more precise control over intermediate values.
     */
    createCache<Result, Record extends R = R>(create: (id: IdOf<Record>, recordSignal: Signal<R>) => Signal<Result>): {
        get: (id: IdOf<Record>) => Result | undefined;
    };
    /**
     * Create a computed cache.
     *
     * @param name - The name of the derivation cache.
     * @param derive - A function used to derive the value of the cache.
     * @param opts - Options for the computed cache.
     * @public
     */
    createComputedCache<Result, Record extends R = R>(name: string, derive: (record: Record) => Result | undefined, opts?: CreateComputedCacheOpts<Result, Record>): ComputedCache<Result, Record>;
    private _integrityChecker?;
    /* Excluded from this release type: ensureStoreIsUsable */
    private _isPossiblyCorrupted;
    /* Excluded from this release type: markAsPossiblyCorrupted */
    /* Excluded from this release type: isPossiblyCorrupted */
    private pendingAfterEvents;
    private addDiffForAfterEvent;
    private flushAtomicCallbacks;
    private _isInAtomicOp;
    /* Excluded from this release type: atomic */
    /* Excluded from this release type: addHistoryInterceptor */
}

/** @public */
export declare type StoreAfterChangeHandler<R extends UnknownRecord> = (prev: R, next: R, source: 'remote' | 'user') => void;

/** @public */
export declare type StoreAfterCreateHandler<R extends UnknownRecord> = (record: R, source: 'remote' | 'user') => void;

/** @public */
export declare type StoreAfterDeleteHandler<R extends UnknownRecord> = (record: R, source: 'remote' | 'user') => void;

/** @public */
export declare type StoreBeforeChangeHandler<R extends UnknownRecord> = (prev: R, next: R, source: 'remote' | 'user') => R;

/** @public */
export declare type StoreBeforeCreateHandler<R extends UnknownRecord> = (record: R, source: 'remote' | 'user') => R;

/** @public */
export declare type StoreBeforeDeleteHandler<R extends UnknownRecord> = (record: R, source: 'remote' | 'user') => false | void;

/** @public */
export declare interface StoreError {
    error: Error;
    phase: 'createRecord' | 'initialize' | 'tests' | 'updateRecord';
    recordBefore?: unknown;
    recordAfter: unknown;
    isExistingValidationIssue: boolean;
}

/**
 * A function that will be called when the history changes.
 *
 * @public
 */
export declare type StoreListener<R extends UnknownRecord> = (entry: HistoryEntry<R>) => void;

/** @public */
export declare interface StoreListenerFilters {
    source: 'all' | ChangeSource;
    scope: 'all' | RecordScope;
}

/** @public */
export declare type StoreObject<R extends UnknownRecord> = {
    store: Store<R>;
} | Store<R>;

/** @public */
export declare type StoreObjectRecordType<Context extends StoreObject<any>> = Context extends Store<infer R> ? R : Context extends {
    store: Store<infer R>;
} ? R : never;

/** @public */
export declare type StoreOperationCompleteHandler = (source: 'remote' | 'user') => void;

/**
 * A class that provides a 'namespace' for the various kinds of indexes one may wish to derive from
 * the record store.
 * @public
 */
export declare class StoreQueries<R extends UnknownRecord> {
    private readonly recordMap;
    private readonly history;
    constructor(recordMap: AtomMap<IdOf<R>, R>, history: Atom<number, RecordsDiff<R>>);
    /* Excluded from this release type: indexCache */
    /* Excluded from this release type: historyCache */
    /**
     * Create a derivation that contains the history for a given type
     *
     * @param typeName - The name of the type to filter by.
     * @returns A derivation that returns the ids of all records of the given type.
     * @public
     */
    filterHistory<TypeName extends R['typeName']>(typeName: TypeName): Computed<number, RecordsDiff<Extract<R, {
        typeName: TypeName;
    }>>>;
    /**
     * Create a derivation that returns an index on a property for the given type.
     *
     * @param typeName - The name of the type.
     * @param property - The name of the property.
     * @public
     */
    index<TypeName extends R['typeName'], Property extends string & keyof Extract<R, {
        typeName: TypeName;
    }>>(typeName: TypeName, property: Property): RSIndex<Extract<R, {
        typeName: TypeName;
    }>, Property>;
    /* Excluded from this release type: __uncached_createIndex */
    /**
     * Create a derivation that will return a signle record matching the given query.
     *
     * It will return undefined if there is no matching record
     *
     * @param typeName - The name of the type?
     * @param queryCreator - A function that returns the query expression.
     * @param name - (optional) The name of the query.
     */
    record<TypeName extends R['typeName']>(typeName: TypeName, queryCreator?: () => QueryExpression<Extract<R, {
        typeName: TypeName;
    }>>, name?: string): Computed<Extract<R, {
        typeName: TypeName;
    }> | undefined>;
    /**
     * Create a derivation that will return an array of records matching the given query
     *
     * @param typeName - The name of the type?
     * @param queryCreator - A function that returns the query expression.
     * @param name - (optinal) The name of the query.
     */
    records<TypeName extends R['typeName']>(typeName: TypeName, queryCreator?: () => QueryExpression<Extract<R, {
        typeName: TypeName;
    }>>, name?: string): Computed<Array<Extract<R, {
        typeName: TypeName;
    }>>>;
    /**
     * Create a derivation that will return the ids of all records of the given type.
     *
     * @param typeName - The name of the type.
     * @param queryCreator - A function that returns the query expression.
     * @param name - (optinal) The name of the query.
     */
    ids<TypeName extends R['typeName']>(typeName: TypeName, queryCreator?: () => QueryExpression<Extract<R, {
        typeName: TypeName;
    }>>, name?: string): Computed<Set<IdOf<Extract<R, {
        typeName: TypeName;
    }>>>, CollectionDiff<IdOf<Extract<R, {
        typeName: TypeName;
    }>>>>;
    exec<TypeName extends R['typeName']>(typeName: TypeName, query: QueryExpression<Extract<R, {
        typeName: TypeName;
    }>>): Array<Extract<R, {
        typeName: TypeName;
    }>>;
}

/* Excluded from this release type: StoreRecord */

/** @public */
export declare class StoreSchema<R extends UnknownRecord, P = unknown> {
    readonly types: {
        [Record in R as Record['typeName']]: RecordType<R, any>;
    };
    private readonly options;
    static create<R extends UnknownRecord, P = unknown>(types: {
        [TypeName in R['typeName']]: {
            createId: any;
        };
    }, options?: StoreSchemaOptions<R, P>): StoreSchema<R, P>;
    readonly migrations: Record<string, MigrationSequence>;
    readonly sortedMigrations: readonly Migration[];
    private constructor();
    validateRecord(store: Store<R>, record: R, phase: 'createRecord' | 'initialize' | 'tests' | 'updateRecord', recordBefore: null | R): R;
    getMigrationsSince(persistedSchema: SerializedSchema): Result<Migration[], string>;
    migratePersistedRecord(record: R, persistedSchema: SerializedSchema, direction?: 'down' | 'up'): MigrationResult<R>;
    migrateStoreSnapshot(snapshot: StoreSnapshot<R>): MigrationResult<SerializedStore<R>>;
    /* Excluded from this release type: createIntegrityChecker */
    serialize(): SerializedSchemaV2;
    /**
     * @deprecated This is only here for legacy reasons, don't use it unless you have david's blessing!
     */
    serializeEarliestVersion(): SerializedSchema;
    /* Excluded from this release type: getType */
}

/** @public */
export declare interface StoreSchemaOptions<R extends UnknownRecord, P> {
    migrations?: MigrationSequence[];
    /** @public */
    onValidationFailure?(data: StoreValidationFailure<R>): R;
    /* Excluded from this release type: createIntegrityChecker */
}

/**
 * The side effect manager (aka a "correct state enforcer") is responsible
 * for making sure that the editor's state is always correct. This includes
 * things like: deleting a shape if its parent is deleted; unbinding
 * arrows when their binding target is deleted; etc.
 *
 * @public
 */
export declare class StoreSideEffects<R extends UnknownRecord> {
    private readonly store;
    constructor(store: Store<R>);
    private _beforeCreateHandlers;
    private _afterCreateHandlers;
    private _beforeChangeHandlers;
    private _afterChangeHandlers;
    private _beforeDeleteHandlers;
    private _afterDeleteHandlers;
    private _operationCompleteHandlers;
    private _isEnabled;
    /* Excluded from this release type: isEnabled */
    /* Excluded from this release type: setIsEnabled */
    /* Excluded from this release type: handleBeforeCreate */
    /* Excluded from this release type: handleAfterCreate */
    /* Excluded from this release type: handleBeforeChange */
    /* Excluded from this release type: handleAfterChange */
    /* Excluded from this release type: handleBeforeDelete */
    /* Excluded from this release type: handleAfterDelete */
    /* Excluded from this release type: handleOperationComplete */
    /* Excluded from this release type: register */
    /**
     * Register a handler to be called before a record of a certain type is created. Return a
     * modified record from the handler to change the record that will be created.
     *
     * Use this handle only to modify the creation of the record itself. If you want to trigger a
     * side-effect on a different record (for example, moving one shape when another is created),
     * use {@link StoreSideEffects.registerAfterCreateHandler} instead.
     *
     * @example
     * ```ts
     * editor.sideEffects.registerBeforeCreateHandler('shape', (shape, source) => {
     *     // only modify shapes created by the user
     *     if (source !== 'user') return shape
     *
     *     //by default, arrow shapes have no label. Let's make sure they always have a label.
     *     if (shape.type === 'arrow') {
     *         return {...shape, props: {...shape.props, text: 'an arrow'}}
     *     }
     *
     *     // other shapes get returned unmodified
     *     return shape
     * })
     * ```
     *
     * @param typeName - The type of record to listen for
     * @param handler - The handler to call
     *
     * @returns A callback that removes the handler.
     */
    registerBeforeCreateHandler<T extends R['typeName']>(typeName: T, handler: StoreBeforeCreateHandler<R & {
        typeName: T;
    }>): () => void;
    /**
     * Register a handler to be called after a record is created. This is useful for side-effects
     * that would update _other_ records. If you want to modify the record being created use
     * {@link StoreSideEffects.registerBeforeCreateHandler} instead.
     *
     * @example
     * ```ts
     * editor.sideEffects.registerAfterCreateHandler('page', (page, source) => {
     *     // Automatically create a shape when a page is created
     *     editor.createShape<TLTextShape>({
     *         id: createShapeId(),
     *         type: 'text',
     *         props: { richText: toRichText(page.name) },
     *     })
     * })
     * ```
     *
     * @param typeName - The type of record to listen for
     * @param handler - The handler to call
     *
     * @returns A callback that removes the handler.
     */
    registerAfterCreateHandler<T extends R['typeName']>(typeName: T, handler: StoreAfterCreateHandler<R & {
        typeName: T;
    }>): () => void;
    /**
     * Register a handler to be called before a record is changed. The handler is given the old and
     * new record - you can return a modified record to apply a different update, or the old record
     * to block the update entirely.
     *
     * Use this handler only for intercepting updates to the record itself. If you want to update
     * other records in response to a change, use
     * {@link StoreSideEffects.registerAfterChangeHandler} instead.
     *
     * @example
     * ```ts
     * editor.sideEffects.registerBeforeChangeHandler('shape', (prev, next, source) => {
     *     if (next.isLocked && !prev.isLocked) {
     *         // prevent shapes from ever being locked:
     *         return prev
     *     }
     *     // other types of change are allowed
     *     return next
     * })
     * ```
     *
     * @param typeName - The type of record to listen for
     * @param handler - The handler to call
     *
     * @returns A callback that removes the handler.
     */
    registerBeforeChangeHandler<T extends R['typeName']>(typeName: T, handler: StoreBeforeChangeHandler<R & {
        typeName: T;
    }>): () => void;
    /**
     * Register a handler to be called after a record is changed. This is useful for side-effects
     * that would update _other_ records - if you want to modify the record being changed, use
     * {@link StoreSideEffects.registerBeforeChangeHandler} instead.
     *
     * @example
     * ```ts
     * editor.sideEffects.registerAfterChangeHandler('shape', (prev, next, source) => {
     *     if (next.props.color === 'red') {
     *         // there can only be one red shape at a time:
     *         const otherRedShapes = editor.getCurrentPageShapes().filter(s => s.props.color === 'red' && s.id !== next.id)
     *         editor.updateShapes(otherRedShapes.map(s => ({...s, props: {...s.props, color: 'blue'}})))
     *     }
     * })
     * ```
     *
     * @param typeName - The type of record to listen for
     * @param handler - The handler to call
     *
     * @returns A callback that removes the handler.
     */
    registerAfterChangeHandler<T extends R['typeName']>(typeName: T, handler: StoreAfterChangeHandler<R & {
        typeName: T;
    }>): () => void;
    /**
     * Register a handler to be called before a record is deleted. The handler can return `false` to
     * prevent the deletion.
     *
     * Use this handler only for intercepting deletions of the record itself. If you want to do
     * something to other records in response to a deletion, use
     * {@link StoreSideEffects.registerAfterDeleteHandler} instead.
     *
     * @example
     * ```ts
     * editor.sideEffects.registerBeforeDeleteHandler('shape', (shape, source) => {
     *     if (shape.props.color === 'red') {
     *         // prevent red shapes from being deleted
     * 	       return false
     *     }
     * })
     * ```
     *
     * @param typeName - The type of record to listen for
     * @param handler - The handler to call
     *
     * @returns A callback that removes the handler.
     */
    registerBeforeDeleteHandler<T extends R['typeName']>(typeName: T, handler: StoreBeforeDeleteHandler<R & {
        typeName: T;
    }>): () => void;
    /**
     * Register a handler to be called after a record is deleted. This is useful for side-effects
     * that would update _other_ records - if you want to block the deletion of the record itself,
     * use {@link StoreSideEffects.registerBeforeDeleteHandler} instead.
     *
     * @example
     * ```ts
     * editor.sideEffects.registerAfterDeleteHandler('shape', (shape, source) => {
     *     // if the last shape in a frame is deleted, delete the frame too:
     *     const parentFrame = editor.getShape(shape.parentId)
     *     if (!parentFrame || parentFrame.type !== 'frame') return
     *
     *     const siblings = editor.getSortedChildIdsForParent(parentFrame)
     *     if (siblings.length === 0) {
     *         editor.deleteShape(parentFrame.id)
     *     }
     * })
     * ```
     *
     * @param typeName - The type of record to listen for
     * @param handler - The handler to call
     *
     * @returns A callback that removes the handler.
     */
    registerAfterDeleteHandler<T extends R['typeName']>(typeName: T, handler: StoreAfterDeleteHandler<R & {
        typeName: T;
    }>): () => void;
    /**
     * Register a handler to be called when a store completes an atomic operation.
     *
     * @example
     * ```ts
     * let count = 0
     *
     * editor.sideEffects.registerOperationCompleteHandler(() => count++)
     *
     * editor.selectAll()
     * expect(count).toBe(1)
     *
     * editor.store.atomic(() => {
     *	editor.selectNone()
     * 	editor.selectAll()
     * })
     *
     * expect(count).toBe(2)
     * ```
     *
     * @param handler - The handler to call
     *
     * @returns A callback that removes the handler.
     *
     * @public
     */
    registerOperationCompleteHandler(handler: StoreOperationCompleteHandler): () => void;
}

/** @public */
export declare interface StoreSnapshot<R extends UnknownRecord> {
    store: SerializedStore<R>;
    schema: SerializedSchema;
}

/** @public */
export declare interface StoreValidationFailure<R extends UnknownRecord> {
    error: unknown;
    store: Store<R>;
    record: R;
    phase: 'createRecord' | 'initialize' | 'tests' | 'updateRecord';
    recordBefore: null | R;
}

/** @public */
export declare interface StoreValidator<R extends UnknownRecord> {
    validate(record: unknown): R;
    validateUsingKnownGoodVersion?(knownGoodVersion: R, record: unknown): R;
}

/** @public */
export declare type StoreValidators<R extends UnknownRecord> = {
    [K in R['typeName']]: StoreValidator<Extract<R, {
        typeName: K;
    }>>;
};

/** @public */
export declare type UnknownRecord = BaseRecord<string, RecordId<UnknownRecord>>;

export { }
