/**
 * The mergeable-store module contains the types, interfaces, and functions to
 * work with MergeableStore objects, which provide merge and synchronization
 * functionality.
 *
 * The main entry point to this module is the createMergeableStore function,
 * which returns a new MergeableStore, a subtype of Store that can be merged
 * with another with deterministic results.
 *
 * Please be aware that a lot of the types and methods exposed by this module
 * are used internally within TinyBase itself (in particular the Synchronizer
 * framework). They're documented here, but mostly for interest, and it is
 * generally assumed that they won't be called directly by applications.
 *
 * As an application developer, it's more likely that you will continue to use
 * the main Store methods for reading, writing, and listening to data, and rely
 * on Synchronizer instances to keep the data in step with other places.
 * @packageDocumentation
 * @module mergeable-store
 * @since v5.0.0
 */
import type {
  CellIdFromSchema,
  TableIdFromSchema,
  ValueIdFromSchema,
} from '../../_internal/store/with-schemas/index.d.ts';
import type {GetNow, Hash, Hlc, Id} from '../../common/with-schemas/index.d.ts';
import type {
  CellOrUndefined,
  Content,
  NoSchemas,
  NoTablesSchema,
  NoValuesSchema,
  OptionalSchemas,
  OptionalTablesSchema,
  OptionalValuesSchema,
  Store,
  TablesSchema,
  ValueOrUndefined,
  ValuesSchema,
} from '../../store/with-schemas/index.d.ts';

/**
 * The Stamp type is used as metadata to decide how to merge two different
 * MergeableStore objects together.
 *
 * It describes a combination of a value (or object), an Hlc timestamp, and
 * optionally a Hash, all in an array.
 *
 * This type is mostly utilized internally within TinyBase itself and is
 * generally assumed to be opaque to applications that use it.
 * @category Stamps
 * @since v5.0.0
 */
export type Stamp<Thing, Hashed extends boolean = false> = Hashed extends true
  ? [thing: Thing, hlc: Hlc, hash: Hash]
  : [thing: Thing, hlc?: Hlc];

/**
 * The ContentHashes type is used to quickly compare the content of two
 * MergeableStore objects.
 *
 * It is simply an array of two Hash types, one for the MergeableStore's Tables
 * and one for its Values.
 *
 * This type is mostly utilized internally within TinyBase itself and is
 * generally assumed to be opaque to applications that use it.
 * @category Syncing
 * @since v5.0.0
 */
export type ContentHashes = [tablesHash: Hash, valuesHash: Hash];

/**
 * The TablesStamp type is used as metadata to decide how to merge two different
 * sets of Tables together.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type TablesStamp<Hashed extends boolean = false> = Stamp<
 *   {[tableId: Id]: TableStamp<Hashed>},
 *   Hashed
 * >;
 * ```
 *
 * This type is mostly utilized internally within TinyBase itself and is
 * generally assumed to be opaque to applications that use it.
 * @category Stamps
 * @since v5.0.0
 */
export type TablesStamp<
  Schema extends OptionalTablesSchema,
  Hashed extends boolean = false,
> = Stamp<
  {
    [TableId in TableIdFromSchema<Schema>]?: TableStamp<
      Schema,
      TableId,
      Hashed
    >;
  },
  Hashed
>;

/**
 * The TableHashes type is used to quickly compare the content of two sets of
 * Table objects.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * {[tableId: Id]: Hash};
 * ```
 *
 * It is simply an object of Hash types, one for each Table Id in the
 * MergeableStore.
 *
 * This type is mostly utilized internally within TinyBase itself and is
 * generally assumed to be opaque to applications that use it.
 * @category Syncing
 * @since v5.0.0
 */
export type TableHashes<Schema extends OptionalTablesSchema> = {
  [TableId in TableIdFromSchema<Schema>]?: Hash;
};

/**
 * The TableStamp type is used as metadata to decide how to merge two different
 * Table objects together.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type TableStamp<Hashed extends boolean = false> = Stamp<
 *   {[rowId: Id]: RowStamp<Hashed>},
 *   Hashed
 * >;
 * ```
 *
 * This type is mostly utilized internally within TinyBase itself and is
 * generally assumed to be opaque to applications that use it.
 * @category Stamps
 * @since v5.0.0
 */
export type TableStamp<
  Schema extends OptionalTablesSchema,
  TableId extends TableIdFromSchema<Schema>,
  Hashed extends boolean = false,
> = Stamp<{[rowId: Id]: RowStamp<Schema, TableId, Hashed>}, Hashed>;

/**
 * The RowHashes type is used to quickly compare the content of two sets of Row
 * objects.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * {[tableId: Id]: {[rowId: Id]: Hash}};
 * ```
 *
 * It is simply a nested object of Hash types, one for each Row Id, for each
 * TableId, in the MergeableStore.
 *
 * This type is mostly utilized internally within TinyBase itself and is
 * generally assumed to be opaque to applications that use it.
 * @category Syncing
 * @since v5.0.0
 */
export type RowHashes<Schema extends OptionalTablesSchema> = {
  [TableId in TableIdFromSchema<Schema>]?: {[rowId: Id]: Hash};
};

/**
 * The RowStamp type is used as metadata to decide how to merge two different
 * Row objects together.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type RowStamp<Hashed extends boolean = false> = Stamp<
 *   {[cellId: Id]: CellStamp<Hashed>},
 *   Hashed
 * >;
 * ```
 *
 * This type is mostly utilized internally within TinyBase itself and is
 * generally assumed to be opaque to applications that use it.
 * @category Stamps
 * @since v5.0.0
 */
export type RowStamp<
  Schema extends OptionalTablesSchema,
  TableId extends TableIdFromSchema<Schema>,
  Hashed extends boolean = false,
> = Stamp<
  {
    [CellId in CellIdFromSchema<Schema, TableId>]?: CellStamp<
      Schema,
      TableId,
      CellId,
      Hashed
    >;
  },
  Hashed
>;

/**
 * The CellHashes type is used to quickly compare the content of two sets of
 * Cell objects.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * {[tableId: Id]: {[rowId: Id]: {[cellId: Id]: Hash}}};
 * ```
 *
 * It is simply a nested object of Hash types, one for each Cell Id, for each
 * Row Id, for each TableId, in the MergeableStore.
 *
 * This type is mostly utilized internally within TinyBase itself and is
 * generally assumed to be opaque to applications that use it.
 * @category Syncing
 * @since v5.0.0
 */
export type CellHashes<Schema extends OptionalTablesSchema> = {
  [TableId in TableIdFromSchema<Schema>]?: {
    [rowId: Id]: {[CellId in CellIdFromSchema<Schema, TableId>]?: Hash};
  };
};

/**
 * The CellStamp type is used as metadata to decide how to merge two different
 * Cell objects together.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type CellStamp<Hashed extends boolean = false> = Stamp<
 *   CellOrUndefined,
 *   Hashed
 * >;
 * ```
 *
 * This type is mostly utilized internally within TinyBase itself and is
 * generally assumed to be opaque to applications that use it.
 * @category Stamps
 * @since v5.0.0
 */
export type CellStamp<
  Schema extends OptionalTablesSchema,
  TableId extends TableIdFromSchema<Schema>,
  CellId extends CellIdFromSchema<Schema, TableId>,
  Hashed extends boolean = false,
> = Stamp<CellOrUndefined<Schema, TableId, CellId>, Hashed>;

/**
 * The ValuesStamp type is used as metadata to decide how to merge two different
 * sets of Values together.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type ValuesStamp<Hashed extends boolean = false> = Stamp<
 *   {[valueId: Id]: ValueStamp<Hashed>},
 *   Hashed
 * >;
 * ```
 *
 * This type is mostly utilized internally within TinyBase itself and is
 * generally assumed to be opaque to applications that use it.
 * @category Stamps
 * @since v5.0.0
 */
export type ValuesStamp<
  Schema extends OptionalValuesSchema,
  Hashed extends boolean = false,
> = Stamp<
  {
    [ValueId in ValueIdFromSchema<Schema>]?: ValueStamp<
      Schema,
      ValueId,
      Hashed
    >;
  },
  Hashed
>;

/**
 * The ValueHashes type is used to quickly compare the content of two sets of
 * Value objects.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * {[valueId: Id]: Hash};
 * ```
 *
 * It is simply an object of Hash types, one for each Value Id in the
 * MergeableStore.
 *
 * This type is mostly utilized internally within TinyBase itself and is
 * generally assumed to be opaque to applications that use it.
 * @category Syncing
 * @since v5.0.0
 */
export type ValueHashes<Schema extends OptionalValuesSchema> = {
  [ValueId in ValueIdFromSchema<Schema>]?: Hash;
};

/**
 * The ValueStamp type is used as metadata to decide how to merge two different
 * Value objects together.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type ValueStamp<Hashed extends boolean = false> = Stamp<
 *   ValueOrUndefined,
 *   Hashed
 * >;
 * ```
 *
 * This type is mostly utilized internally within TinyBase itself and is
 * generally assumed to be opaque to applications that use it.
 * @category Stamps
 * @since v5.0.0
 */
export type ValueStamp<
  Schema extends OptionalValuesSchema,
  ValueId extends ValueIdFromSchema<Schema>,
  Hashed extends boolean = false,
> = Stamp<ValueOrUndefined<Schema, ValueId>, Hashed>;

/**
 * The MergeableContent type represents the content of a MergeableStore and the
 * metadata about that content) required to merge it with another.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * [
 *   mergeableTables: TablesStamp<true>,
 *   mergeableValues: ValuesStamp<true>,
 * ];
 * ```
 *
 * It is simply an array of two Stamp types, one for the MergeableStore's Tables
 * and one for its Values.
 *
 * This type is mostly utilized internally within TinyBase itself and is
 * generally assumed to be opaque to applications that use it.
 * @category Mergeable
 * @since v5.0.0
 */
export type MergeableContent<Schemas extends OptionalSchemas> = [
  mergeableTables: TablesStamp<Schemas[0], true>,
  mergeableValues: ValuesStamp<Schemas[1], true>,
];

/**
 * The MergeableChanges type represents changes to the content of a
 * MergeableStore and the metadata about that content) required to merge it with
 * another.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type MergeableChanges<Hashed extends boolean = false> = [
 *   mergeableTables: TablesStamp<Hashed>,
 *   mergeableValues: ValuesStamp<Hashed>,
 *   isChanges: 1,
 * ];
 * ```
 *
 * It is simply an array of two Stamp types, one for changes to the
 * MergeableStore's Tables and one for changes to its Values. A final `1` is
 * used to distinguish it from a full MergeableContent object.
 *
 * This type is mostly utilized internally within TinyBase itself and is
 * generally assumed to be opaque to applications that use it.
 * @category Mergeable
 * @since v5.0.0
 */
export type MergeableChanges<
  Schemas extends OptionalSchemas,
  Hashed extends boolean = false,
> = [
  mergeableTables: TablesStamp<Schemas[0], Hashed>,
  mergeableValues: ValuesStamp<Schemas[1], Hashed>,
  isChanges: 1,
];

/**
 * The MergeableStore type represents a Store that carries with it sufficient
 * metadata to be able to be merged with another MergeableStore with
 * deterministic results.
 *
 * This is the key data type used when you need TinyBase data to be cleanly
 * synchronized or merged with data elsewhere on the system, or on another
 * system. It acts as a Conflict-Free Replicated Data Type (CRDT) which allows
 * deterministic disambiguation of how changes to different instances should be
 * merged.
 *
 * Please be aware that a lot of the methods exposed by this interface are used
 * internally within TinyBase itself (in particular the Synchronizer framework).
 * They're documented here, but mostly for interest, and it is generally assumed
 * that they won't be called directly by applications.
 *
 * As an application developer, it's more likely that you will continue to use
 * the main Store methods for reading, writing, and listening to data, and rely
 * on Synchronizer instances to keep the data in step with other places.
 *
 * One possible exceptions is the merge method, which can be used to simply
 * merge two co-located MergeableStore instances together.
 * @example
 * This example shows very simple usage of the MergeableStore: whereby two are
 * created, updated with different data, and then merged with one another.
 *
 * ```js
 * import {createMergeableStore} from 'tinybase';
 *
 * const localStore1 = createMergeableStore();
 * const localStore2 = createMergeableStore();
 *
 * localStore1.setCell('pets', 'fido', 'color', 'brown');
 * localStore2.setCell('pets', 'felix', 'color', 'black');
 *
 * localStore1.merge(localStore2);
 *
 * console.log(localStore1.getContent());
 * // -> [{pets: {felix: {color: 'black'}, fido: {color: 'brown'}}}, {}]
 *
 * console.log(localStore2.getContent());
 * // -> [{pets: {felix: {color: 'black'}, fido: {color: 'brown'}}}, {}]
 *```
 * @category Mergeable
 * @since v5.0.0
 */
export interface MergeableStore<
  Schemas extends OptionalSchemas,
> extends Store<Schemas> {
  //
  /**
   * The getMergeableContent method returns the full content of a
   * MergeableStore, together with the metadata required to make it mergeable
   * with another.
   *
   * This has schema-based typing. The following is a simplified representation:
   *
   * ```ts override
   * getMergeableContent(): MergeableContent;
   * ```
   *
   * The method is generally intended to be used internally within TinyBase
   * itself and the return type is assumed to be opaque to applications that use
   * it.
   * @returns A MergeableContent object for the full content of the
   * MergeableStore.
   * @example
   * This example creates a MergeableStore, sets some data, and then accesses
   * the content and metadata required to make it mergeable.
   *
   * ```js
   * import {createMergeableStore} from 'tinybase';
   *
   * const store = createMergeableStore('store1'); // !reset
   *
   * store.setCell('pets', 'fido', 'color', 'brown');
   *
   * console.log(store.getMergeableContent());
   * // ->
   * [
   *   [
   *     {
   *       pets: [
   *         {
   *           fido: [
   *             {color: ['brown', 'Nn1JUF-----FnHIC', 923684530]},
   *             '',
   *             851131566,
   *           ],
   *         },
   *         '',
   *         518810247,
   *       ],
   *     },
   *     '',
   *     784336119,
   *   ],
   *   [{}, '', 0],
   * ];
   * ```
   * @category Getter
   * @since v5.0.0
   */
  getMergeableContent(): MergeableContent<Schemas>;

  /**
   * The getMergeableContentHashes method returns hashes for the full content of
   * a MergeableStore.
   *
   * If two MergeableStore instances have different hashes, that indicates that
   * the mergeable Tables or Values within them are different and should be
   * synchronized.
   *
   * The method is generally intended to be used internally within TinyBase
   * itself and the return type is assumed to be opaque to applications that use
   * it.
   * @returns A ContentHashes array for the hashes of the full content of the
   * MergeableStore.
   * @example
   * This example creates a MergeableStore, sets some data, and then accesses
   * the content hashes.
   *
   * ```js
   * import {createMergeableStore} from 'tinybase';
   *
   * const store = createMergeableStore('store1'); // !reset
   *
   * store.setCell('pets', 'fido', 'color', 'brown');
   * console.log(store.getMergeableContentHashes());
   * // -> [784336119, 0]
   *
   * store.setValue('open', true);
   * console.log(store.getMergeableContentHashes());
   * // -> [784336119, 2829789038]
   * ```
   * @category Syncing
   * @since v5.0.0
   */
  getMergeableContentHashes(): ContentHashes;

  /**
   * The getMergeableTableHashes method returns hashes for the Table objects in
   * a MergeableStore.
   *
   * This has schema-based typing. The following is a simplified representation:
   *
   * ```ts override
   * getMergeableTableHashes(): TableHashes;
   * ```
   *
   * If two Table Ids have different hashes, that indicates that the content
   * within them is different and should be synchronized.
   *
   * The method is generally intended to be used internally within TinyBase
   * itself and the return type is assumed to be opaque to applications that use
   * it.
   * @returns A TableHashes object with the hashes of each Table in the
   * MergeableStore.
   * @example
   * This example creates a MergeableStore, sets some data, and then accesses
   * the Table hashes.
   *
   * ```js
   * import {createMergeableStore} from 'tinybase';
   *
   * const store = createMergeableStore('store1'); // !reset
   *
   * store.setCell('pets', 'fido', 'color', 'brown');
   * console.log(store.getMergeableTableHashes());
   * // -> {pets: 518810247}
   *
   * store.setCell('species', 'dog', 'price', 5);
   * console.log(store.getMergeableTableHashes());
   * // -> {pets: 518810247, species: 2324343240}
   * ```
   * @category Syncing
   * @since v5.0.0
   */
  getMergeableTableHashes(): TableHashes<Schemas[0]>;

  /**
   * The getMergeableTableDiff method returns information about new and
   * differing Table objects of a MergeableStore relative to another.
   *
   * This has schema-based typing. The following is a simplified representation:
   *
   * ```ts override
   * getMergeableTableDiff(
   *   otherTableHashes: TableHashes,
   * ): [newTables: TablesStamp, differingTableHashes: TableHashes];
   * ```
   *
   * The method is generally intended to be used internally within TinyBase
   * itself and the return type is assumed to be opaque to applications that use
   * it.
   * @param otherTableHashes The TableHashes of another MergeableStore.
   * @returns A pair of objects describing the new and differing Table objects
   * of this MergeableStore relative to the other.
   * @example
   * This example creates two MergeableStores, sets some differing data, and
   * then identifies the differences in the Table objects of one versus the
   * other. Once they have been merged, the differences are empty.
   *
   * ```js
   * import {createMergeableStore} from 'tinybase';
   *
   * const store1 = createMergeableStore('store1'); // !reset
   * store1.setTables({pets: {fido: {color: 'brown'}}});
   *
   * const store2 = createMergeableStore('store2');
   * store2.setTables({
   *   pets: {fido: {species: 'dog'}},
   *   species: {dog: {price: 5}},
   * });
   *
   * console.log(
   *   store2.getMergeableTableDiff(store1.getMergeableTableHashes()),
   * );
   * // ->
   * [
   *   [{species: [{dog: [{price: [5, 'Nn1JUF----0CnH-J']}]}]}],
   *   {pets: 1212600658},
   * ];
   *
   * store1.merge(store2);
   *
   * console.log(
   *   store2.getMergeableTableDiff(store1.getMergeableTableHashes()),
   * );
   * // -> [[{}], {}]
   * ```
   * @category Syncing
   * @since v5.0.0
   */
  getMergeableTableDiff(
    otherTableHashes: TableHashes<Schemas[0]>,
  ): [
    newTables: TablesStamp<Schemas[0]>,
    differingTableHashes: TableHashes<Schemas[0]>,
  ];

  /**
   * The getMergeableRowHashes method returns hashes for Row objects in a
   * MergeableStore.
   *
   * This has schema-based typing. The following is a simplified representation:
   *
   * ```ts override
   * getMergeableRowHashes(otherTableHashes: TableHashes): RowHashes;
   * ```
   *
   * If two Row Ids have different hashes, that indicates that the content
   * within them is different and should be synchronized.
   *
   * The method is generally intended to be used internally within TinyBase
   * itself and the return type is assumed to be opaque to applications that use
   * it.
   * @param otherTableHashes The TableHashes from the other MergeableStore so
   * that the differences can be efficiently identified.
   * @returns A RowHashes object with the hashes of each Row in the relevant
   * Table objects of the MergeableStore.
   * @example
   * This example creates a MergeableStore, sets some data, and then accesses
   * the Row hashes for the differing Table Ids.
   *
   * ```js
   * import {createMergeableStore} from 'tinybase';
   *
   * const store1 = createMergeableStore('store1'); // !reset
   * store1.setTables({pets: {fido: {color: 'brown'}, felix: {color: 'tan'}}});
   *
   * const store2 = createMergeableStore('store2');
   * store2.setTables({pets: {fido: {color: 'black'}, felix: {color: 'tan'}}});
   *
   * console.log(
   *   store1.getMergeableRowHashes(
   *     store2.getMergeableTableDiff(store1.getMergeableTableHashes())[1],
   *   ),
   * );
   * // -> {pets: {felix: 1683761402, fido: 851131566}}
   * ```
   * @category Syncing
   * @since v5.0.0
   */
  getMergeableRowHashes(
    otherTableHashes: TableHashes<Schemas[0]>,
  ): RowHashes<Schemas[0]>;

  /**
   * The getMergeableRowDiff method returns information about new and differing
   * Row objects of a MergeableStore relative to another.
   *
   * This has schema-based typing. The following is a simplified representation:
   *
   * ```ts override
   * getMergeableRowDiff(
   *   otherTableRowHashes: RowHashes,
   * ): [newRows: TablesStamp, differingRowHashes: RowHashes];
   * ```
   *
   * The method is generally intended to be used internally within TinyBase
   * itself and the return type is assumed to be opaque to applications that use
   * it.
   * @param otherTableRowHashes The RowHashes of another MergeableStore.
   * @returns A pair of objects describing the new and differing Row objects of
   * this MergeableStore relative to the other.
   * @example
   * This example creates two MergeableStores, sets some differing data, and
   * then identifies the differences in the Row objects of one versus the other.
   * Once they have been merged, the differences are empty.
   *
   * ```js
   * import {createMergeableStore} from 'tinybase';
   *
   * const store1 = createMergeableStore('store1'); // !reset
   * store1.setTables({pets: {fido: {color: 'brown'}}});
   *
   * const store2 = createMergeableStore('store2');
   * store2.setTables({pets: {fido: {color: 'black'}, felix: {color: 'tan'}}});
   *
   * console.log(
   *   store2.getMergeableRowDiff(
   *     store1.getMergeableRowHashes(
   *       store2.getMergeableTableDiff(store1.getMergeableTableHashes())[1],
   *     ),
   *   ),
   * );
   * // ->
   * [
   *   [{pets: [{felix: [{color: ['tan', 'Nn1JUF----0CnH-J']}]}]}],
   *   {pets: {fido: 1038491054}},
   * ];
   *
   * store1.merge(store2);
   *
   * console.log(
   *   store2.getMergeableRowDiff(
   *     store1.getMergeableRowHashes(
   *       store2.getMergeableTableDiff(store1.getMergeableTableHashes())[1],
   *     ),
   *   ),
   * );
   * // -> [[{}], {}]
   * ```
   * @category Syncing
   * @since v5.0.0
   */
  getMergeableRowDiff(
    otherTableRowHashes: RowHashes<Schemas[0]>,
  ): [
    newRows: TablesStamp<Schemas[0]>,
    differingRowHashes: RowHashes<Schemas[0]>,
  ];

  /**
   * The getMergeableCellHashes method returns hashes for Cell objects in a
   * MergeableStore.
   *
   * This has schema-based typing. The following is a simplified representation:
   *
   * ```ts override
   * getMergeableCellHashes(otherTableRowHashes: RowHashes): CellHashes;
   * ```
   *
   * If two Cell Ids have different hashes, that indicates that the content
   * within them is different and should be synchronized.
   *
   * The method is generally intended to be used internally within TinyBase
   * itself and the return type is assumed to be opaque to applications that use
   * it.
   * @param otherTableRowHashes The RowHashes from the other MergeableStore so
   * that the differences can be efficiently identified.
   * @returns A CellHashes object with the hashes of each Cell in the relevant
   * Row objects of the MergeableStore.
   * @example
   * This example creates a MergeableStore, sets some data, and then accesses
   * the Cell hashes for the differing Table Ids.
   *
   * ```js
   * import {createMergeableStore} from 'tinybase';
   *
   * const store1 = createMergeableStore('store1'); // !reset
   * store1.setTables({pets: {fido: {color: 'brown', species: 'dog'}}});
   *
   * const store2 = createMergeableStore('store2');
   * store2.setTables({pets: {fido: {color: 'black', species: 'dog'}}});
   *
   * console.log(
   *   store1.getMergeableCellHashes(
   *     store2.getMergeableRowDiff(
   *       store1.getMergeableRowHashes(
   *         store2.getMergeableTableDiff(store1.getMergeableTableHashes())[1],
   *       ),
   *     )[1],
   *   ),
   * );
   * // -> {pets: {fido: {color: 923684530, species: 227729753}}}
   * ```
   * @category Syncing
   * @since v5.0.0
   */
  getMergeableCellHashes(
    otherTableRowHashes: RowHashes<Schemas[0]>,
  ): CellHashes<Schemas[0]>;

  /**
   * The getMergeableCellDiff method returns information about new and differing
   * Cell objects of a MergeableStore relative to another.
   *
   * This has schema-based typing. The following is a simplified representation:
   *
   * ```ts override
   * getMergeableCellDiff(otherTableRowCellHashes: CellHashes): TablesStamp;
   * ```
   *
   * The method is generally intended to be used internally within TinyBase
   * itself and the return type is assumed to be opaque to applications that use
   * it.
   * @param otherTableRowCellHashes The CellHashes of another MergeableStore.
   * @returns The new and differing Cell objects of this MergeableStore relative
   * to the other.
   * @example
   * This example creates two MergeableStores, sets some differing data, and
   * then identifies the differences in the Cell objects of one versus the
   * other. Once they have been merged, the differences are empty.
   *
   * ```js
   * import {createMergeableStore} from 'tinybase';
   *
   * const store1 = createMergeableStore('store1'); // !reset
   * store1.setTables({pets: {fido: {color: 'brown'}}});
   *
   * const store2 = createMergeableStore('store2');
   * store2.setTables({pets: {fido: {color: 'black', species: 'dog'}}});
   *
   * console.log(
   *   store2.getMergeableCellDiff(
   *     store1.getMergeableCellHashes(
   *       store2.getMergeableRowDiff(
   *         store1.getMergeableRowHashes(
   *           store2.getMergeableTableDiff(
   *             store1.getMergeableTableHashes(),
   *           )[1],
   *         ),
   *       )[1],
   *     ),
   *   ),
   * );
   * // ->
   * [
   *   {
   *     pets: [
   *       {
   *         fido: [
   *           {
   *             color: ['black', 'Nn1JUF-----CnH-J'],
   *             species: ['dog', 'Nn1JUF----0CnH-J'],
   *           },
   *         ],
   *       },
   *     ],
   *   },
   * ];
   *
   * store1.merge(store2);
   *
   * console.log(
   *   store2.getMergeableCellDiff(
   *     store1.getMergeableCellHashes(
   *       store2.getMergeableRowDiff(
   *         store1.getMergeableRowHashes(
   *           store2.getMergeableTableDiff(
   *             store1.getMergeableTableHashes(),
   *           )[1],
   *         ),
   *       )[1],
   *     ),
   *   ),
   * );
   * // -> [{}]
   * ```
   * @category Syncing
   * @since v5.0.0
   */
  getMergeableCellDiff(
    otherTableRowCellHashes: CellHashes<Schemas[0]>,
  ): TablesStamp<Schemas[0]>;

  /**
   * The getMergeableValueHashes method returns hashes for the Value objects in
   * a MergeableStore.
   *
   * This has schema-based typing. The following is a simplified representation:
   *
   * ```ts override
   * getMergeableValueHashes(): ValueHashes;
   * ```
   *
   * If two Value Ids have different hashes, that indicates that the content
   * within them is different and should be synchronized.
   *
   * The method is generally intended to be used internally within TinyBase
   * itself and the return type is assumed to be opaque to applications that use
   * it.
   * @returns A ValueHashes object with the hashes of each Value in the
   * MergeableStore.
   * @example
   * This example creates a MergeableStore, sets some data, and then accesses
   * the Value hashes.
   *
   * ```js
   * import {createMergeableStore} from 'tinybase';
   *
   * const store = createMergeableStore('store1'); // !reset
   *
   * store.setValue('employees', 3);
   * console.log(store.getMergeableValueHashes());
   * // -> {employees: 1940815977}
   *
   * store.setValue('open', true);
   * console.log(store.getMergeableValueHashes());
   * // -> {employees: 1940815977, open: 3860530645}
   * ```
   * @category Syncing
   * @since v5.0.0
   */
  getMergeableValueHashes(): ValueHashes<Schemas[1]>;

  /**
   * The getMergeableValueDiff method returns information about new and
   * differing Value objects of a MergeableStore relative to another.
   *
   * This has schema-based typing. The following is a simplified representation:
   *
   * ```ts override
   * getMergeableValueDiff(otherValueHashes: ValueHashes): ValuesStamp;
   * ```
   *
   * The method is generally intended to be used internally within TinyBase
   * itself and the return type is assumed to be opaque to applications that use
   * it.
   * @param otherValueHashes The ValueHashes of another MergeableStore.
   * @returns The new and differing Value objects of this MergeableStore
   * relative to the other.
   * @example
   * This example creates two MergeableStores, sets some differing data, and
   * then identifies the differences in the Value objects of one versus the
   * other. Once they have been merged, the differences are empty.
   *
   * ```js
   * import {createMergeableStore} from 'tinybase';
   *
   * const store1 = createMergeableStore('store1'); // !reset
   * store1.setValues({employees: 3});
   *
   * const store2 = createMergeableStore('store2');
   * store2.setValues({employees: 4, open: true});
   *
   * console.log(
   *   store2.getMergeableValueDiff(store1.getMergeableValueHashes()),
   * );
   * // ->
   * [
   *   {
   *     employees: [4, 'Nn1JUF-----CnH-J'],
   *     open: [true, 'Nn1JUF----0CnH-J'],
   *   },
   * ];
   *
   * store1.merge(store2);
   *
   * console.log(
   *   store2.getMergeableValueDiff(store1.getMergeableValueHashes()),
   * );
   * // -> [{}]
   * ```
   * @category Syncing
   * @since v5.0.0
   */
  getMergeableValueDiff(
    otherValueHashes: ValueHashes<Schemas[1]>,
  ): ValuesStamp<Schemas[1]>;

  /**
   * The setMergeableContent method sets the full content of a MergeableStore,
   * together with the metadata required to make it mergeable with another.
   *
   * This has schema-based typing. The following is a simplified representation:
   *
   * ```ts override
   * setMergeableContent(mergeableContent: MergeableContent): MergeableStore;
   * ```
   *
   * The method is generally intended to be used internally within TinyBase
   * itself and the return type is assumed to be opaque to applications that use
   * it.
   * @param mergeableContent The full content and metadata of a MergeableStore.
   * @returns A reference to the MergeableStore.
   * @example
   * This example creates a new MergeableStore and initializes it with
   * the content and metadata from another.
   *
   * ```js
   * import {createMergeableStore} from 'tinybase';
   *
   * const store1 = createMergeableStore('store1'); // !reset
   * store1.setValues({employees: 3});
   * console.log(store1.getMergeableContent());
   * // ->
   * [
   *   [{}, '', 0],
   *   [{employees: [3, 'Nn1JUF-----FnHIC', 1940815977]}, '', 1260895905],
   * ];
   *
   * const store2 = createMergeableStore('store2');
   * store2.setMergeableContent(store1.getMergeableContent());
   * console.log(store2.getMergeableContent());
   * // ->
   * [
   *   [{}, '', 0],
   *   [{employees: [3, 'Nn1JUF-----FnHIC', 1940815977]}, '', 1260895905],
   * ];
   * ```
   * @category Setter
   * @since v5.0.0
   */
  setMergeableContent(
    mergeableContent: MergeableContent<Schemas>,
  ): MergeableStore<Schemas>;

  /**
   * The setDefaultContent method sets initial content of a MergeableStore.
   *
   * This has schema-based typing. The following is a simplified representation:
   *
   * ```ts override
   * setDefaultContent(content: Content | (() => Content)): MergeableStore;
   * ```
   *
   * This differs from the setMergeableContent method in that all of the
   * metadata is initialized with a empty HLC timestamp - meaning that any
   * changes applied to it will 'win', yet ensuring that at least default,
   * initial data exists.
   *
   * The method is generally intended to be used internally within TinyBase
   * itself and the return type is assumed to be opaque to applications that use
   * it.
   *
   * Since v5.4.2, this method can also take a function that returns the
   * content.
   * @param content An array containing the tabular and keyed-value data to be
   * set, or a function that returns the array.
   * @returns A reference to the MergeableStore.
   * @example
   * This example creates a new MergeableStore with default data, and
   * demonstrates that it is overwritten with another MergeableStore's data on
   * merge, even if the other MergeableStore was provisioned earlier.
   *
   * ```js
   * import {createMergeableStore} from 'tinybase';
   *
   * const store1 = createMergeableStore('store1'); // !reset
   * store1.setValues({employees: 3});
   *
   * const store2 = createMergeableStore('store2');
   * store2.setDefaultContent([{}, {employees: 4}]);
   * console.log(store2.getMergeableContent());
   * // -> [[{}, "", 0], [{"employees": [4, "", 2414055963]}, "", 3035768673]]
   *
   * store2.merge(store1);
   * console.log(store2.getContent());
   * // -> [{}, {employees: 3}]
   * ```
   * @category Setter
   * @since v5.0.0
   */
  setDefaultContent(
    content: Content<Schemas> | (() => Content<Schemas>),
  ): MergeableStore<Schemas>;

  /**
   * The getTransactionMergeableChanges method returns the net meaningful
   * changes that have been made to a MergeableStore during a transaction.
   *
   * This has schema-based typing. The following is a simplified representation:
   *
   * ```ts override
   * getTransactionMergeableChanges(withHashes?: boolean): MergeableChanges<true>;
   * ```
   *
   * The method is generally intended to be used internally within TinyBase
   * itself and the return type is assumed to be opaque to applications that use
   * it.
   * @param withHashes Whether to include hashes in the output, defaulting to
   * false.
   * @returns A MergeableChanges object representing the changes, with hashes.
   * @example
   * This example makes changes to the MergeableStore. At the end of the
   * transaction, detail about what changed is enumerated.
   *
   * ```js
   * import {createMergeableStore} from 'tinybase';
   *
   * const store = createMergeableStore('store1'); // !reset
   * store.setTables({pets: {fido: {species: 'dog', color: 'brown'}}});
   * store.setValues({open: true});
   *
   * store
   *   .startTransaction()
   *   .setCell('pets', 'fido', 'color', 'black')
   *   .setValue('open', false)
   *   .finishTransaction(() => {
   *     console.log(store.getTransactionMergeableChanges());
   *   });
   * // ->
   * [
   *   [{pets: [{fido: [{color: ['black', 'Nn1JUF----2FnHIC']}]}]}],
   *   [{open: [false, 'Nn1JUF----3FnHIC']}],
   *   1,
   * ];
   * ```
   * @category Transaction
   * @since v5.0.0
   */
  getTransactionMergeableChanges(
    withHashes?: boolean,
  ): MergeableChanges<Schemas, true>;

  /**
   * The applyMergeableChanges method applies a set of mergeable changes or
   * content to the MergeableStore.
   *
   * This has schema-based typing. The following is a simplified representation:
   *
   * ```ts override
   * applyMergeableChanges(
   *   mergeableChanges: MergeableChanges | MergeableContent,
   * ): MergeableStore;
   * ```
   *
   * The method is generally intended to be used internally within TinyBase
   * itself and the return type is assumed to be opaque to applications that use
   * it.
   * @param mergeableChanges The MergeableChanges or MergeableContent to apply
   * to the MergeableStore.
   * @returns A reference to the MergeableStore.
   * @example
   * This example applies a MergeableChanges object that sets a Cell and removes
   * a Value.
   *
   * ```js
   * import {createMergeableStore} from 'tinybase';
   *
   * const store = createMergeableStore('store1')
   *   .setTables({pets: {fido: {species: 'dog', color: 'brown'}}})
   *   .setValues({open: true});
   *
   * store.applyMergeableChanges([
   *   [{pets: [{fido: [{color: ['black', 'Nn1JUF----2FnHIC']}]}]}],
   *   [{open: [null, 'Nn1JUF----3FnHIC']}],
   *   1,
   * ]);
   * console.log(store.getTables());
   * // -> {pets: {fido: {species: 'dog', color: 'black'}}}
   * console.log(store.getValues());
   * // -> {}
   * ```
   * @category Setter
   * @since v5.0.0
   */
  applyMergeableChanges(
    mergeableChanges: MergeableChanges<Schemas> | MergeableContent<Schemas>,
  ): MergeableStore<Schemas>;

  /**
   * The merge method is a convenience method that applies the mergeable content
   * from two MergeableStores to each other in order to bring them to the same
   * state.
   *
   * This has schema-based typing. The following is a simplified representation:
   *
   * ```ts override
   * merge(mergeableStore: MergeableStore): MergeableStore;
   * ```
   *
   * This method is symmetrical: applying `store1` to `store2` will have exactly
   * the same effect as applying `store2` to `store1`.
   * @param mergeableStore A reference to the other MergeableStore to merge with
   * this one.
   * @returns A reference to this MergeableStore.
   * @example
   * This example merges two MergeableStore objects together. Note how the final
   * part of the timestamps on each Cell give you a clue that the data comes
   * from changes made to different MergeableStore objects.
   *
   * ```js
   * import {createMergeableStore} from 'tinybase';
   *
   * const store1 = createMergeableStore('store1');
   * store1.setTables({pets: {fido: {species: 'dog', color: 'brown'}}});
   *
   * const store2 = createMergeableStore('store2');
   * store2.setTables({pets: {felix: {species: 'cat', color: 'tan'}}});
   *
   * store1.merge(store2);
   *
   * console.log(store1.getContent());
   * // ->
   * [
   *   {
   *     pets: {
   *       felix: {color: 'tan', species: 'cat'},
   *       fido: {color: 'brown', species: 'dog'},
   *     },
   *   },
   *   {},
   * ];
   *
   * console.log(store2.getContent());
   * // ->
   * [
   *   {
   *     pets: {
   *       felix: {color: 'tan', species: 'cat'},
   *       fido: {color: 'brown', species: 'dog'},
   *     },
   *   },
   *   {},
   * ];
   * console.log(store2.getMergeableContent());
   * // ->
   * [
   *   [
   *     {
   *       pets: [
   *         {
   *           felix: [
   *             {
   *               color: ['tan', 'Nn1JUF----0CnH-J', 2576658292],
   *               species: ['cat', 'Nn1JUF-----CnH-J', 3409607562],
   *             },
   *             '',
   *             4146239216,
   *           ],
   *           fido: [
   *             {
   *               color: ['brown', 'Nn1JUF----0FnHIC', 1240535355],
   *               species: ['dog', 'Nn1JUF-----FnHIC', 290599168],
   *             },
   *             '',
   *             3989065420,
   *           ],
   *         },
   *         '',
   *         4155188296,
   *       ],
   *     },
   *     '',
   *     972931118,
   *   ],
   *   [{}, '', 0],
   * ];
   * ```
   * @category Setter
   * @since v5.0.0
   */
  merge(mergeableStore: MergeableStore<Schemas>): MergeableStore<Schemas>;

  /**
   * The isMergeable method lets you know if the Store is mergeable.
   *
   * This will always return false for a Store, and true for a MergeableStore.
   * @returns Whether the Store is mergeable.
   * @category Getter
   * @since v5.0.0
   */
  isMergeable(): boolean;

  /**
   * The setTablesSchema method lets you specify the TablesSchema of the tabular
   * part of the Store.
   *
   * Note that this may result in a change to data in the Store, as defaults are
   * applied or as invalid Table, Row, or Cell objects are removed. These
   * changes will fire any listeners to that data, as expected.
   *
   * When no longer needed, you can also completely remove an existing
   * TablesSchema with the delTablesSchema method.
   * @param tablesSchema The TablesSchema to be set for the Store.
   * @returns A reference to the Store.
   * @example
   * This example sets the TablesSchema of a Store after it has been created.
   *
   * ```js
   * import {createStore} from 'tinybase';
   *
   * const store = createStore().setTablesSchema({
   *   pets: {
   *     species: {type: 'string'},
   *     sold: {type: 'boolean', default: false},
   *   },
   * });
   * store.addRow('pets', {species: 'dog', color: 'brown', sold: 'maybe'});
   *
   * console.log(store.getTables());
   * // -> {pets: {0: {species: 'dog', sold: false}}}
   * ```
   * @category Setter
   * @since v3.0.0
   */
  setTablesSchema<TS extends TablesSchema>(
    tablesSchema: TS,
  ): MergeableStore<[typeof tablesSchema, Schemas[1]]>;

  /**
   * The setValuesSchema method lets you specify the ValuesSchema of the keyed
   * Values part of the Store.
   *
   * Note that this may result in a change to data in the Store, as defaults are
   * applied or as invalid Values are removed. These changes will fire any
   * listeners to that data, as expected.
   *
   * When no longer needed, you can also completely remove an existing
   * ValuesSchema with the delValuesSchema method.
   * @param valuesSchema The ValuesSchema to be set for the Store.
   * @returns A reference to the Store.
   * @example
   * This example sets the ValuesSchema of a Store after it has been created.
   *
   * ```js
   * import {createStore} from 'tinybase';
   *
   * const store = createStore().setValuesSchema({
   *   open: {type: 'boolean', default: false},
   * });
   * store.setValue('open', 'maybe');
   *
   * console.log(store.getValues());
   * // -> {open: false}
   * ```
   * @category Setter
   * @since v3.0.0
   */
  setValuesSchema<VS extends ValuesSchema>(
    valuesSchema: VS,
  ): MergeableStore<[Schemas[0], typeof valuesSchema]>;

  /**
   * The setSchema method lets you specify the TablesSchema and ValuesSchema of
   * the Store.
   *
   * Note that this may result in a change to data in the Store, as defaults are
   * applied or as invalid Table, Row, Cell, or Value objects are removed. These
   * changes will fire any listeners to that data, as expected.
   *
   * From v3.0 onwards, this method takes two arguments. The first is the
   * TablesSchema object, the second the ValuesSchema. In previous versions
   * (before the existence of the ValuesSchema data structure), only the first
   * was present. For backwards compatibility the new second parameter is
   * optional.
   * @param tablesSchema The TablesSchema to be set for the Store.
   * @param valuesSchema The ValuesSchema to be set for the Store.
   * @returns A reference to the Store.
   * @example
   * This example sets the TablesSchema and ValuesSchema of a Store after it has
   * been created.
   *
   * ```js
   * import {createStore} from 'tinybase';
   *
   * const store = createStore().setSchema(
   *   {
   *     pets: {
   *       species: {type: 'string'},
   *       sold: {type: 'boolean', default: false},
   *     },
   *   },
   *   {open: {type: 'boolean', default: false}},
   * );
   * store.addRow('pets', {species: 'dog', color: 'brown', sold: 'maybe'});
   * store.setValue('open', 'maybe');
   *
   * console.log(store.getTables());
   * // -> {pets: {0: {species: 'dog', sold: false}}}
   * console.log(store.getValues());
   * // -> {open: false}
   * ```
   * @example
   * This example sets just the TablesSchema of a Store after it has been
   * created.
   *
   * ```js
   * import {createStore} from 'tinybase';
   *
   * const store = createStore().setSchema({
   *   pets: {
   *     species: {type: 'string'},
   *     sold: {type: 'boolean', default: false},
   *   },
   * });
   * store.addRow('pets', {species: 'dog', color: 'brown', sold: 'maybe'});
   *
   * console.log(store.getTables());
   * // -> {pets: {0: {species: 'dog', sold: false}}}
   * ```
   * @category Setter
   * @since v1.0.0
   */
  setSchema<TS extends TablesSchema, VS extends ValuesSchema>(
    tablesSchema: TS,
    valuesSchema?: VS,
  ): MergeableStore<
    [
      typeof tablesSchema,
      Exclude<ValuesSchema, typeof valuesSchema> extends never
        ? NoValuesSchema
        : NonNullable<typeof valuesSchema>,
    ]
  >;

  /**
   * The delTablesSchema method lets you remove the TablesSchema of the Store.
   * @returns A reference to the Store.
   * @example
   * This example removes the TablesSchema of a Store.
   *
   * ```js
   * import {createStore} from 'tinybase';
   *
   * const store = createStore().setTablesSchema({
   *   pets: {species: {type: 'string'}},
   * });
   * store.delTablesSchema();
   * console.log(store.getTablesSchemaJson());
   * // -> '{}'
   * ```
   * @category Deleter
   * @since v1.0.0
   */
  delTablesSchema<
    ValuesSchema extends OptionalValuesSchema = Schemas[1],
  >(): MergeableStore<[NoTablesSchema, ValuesSchema]>;

  /**
   * The delValuesSchema method lets you remove the ValuesSchema of the Store.
   * @returns A reference to the Store.
   * @example
   * This example removes the ValuesSchema of a Store.
   *
   * ```js
   * import {createStore} from 'tinybase';
   *
   * const store = createStore().setValuesSchema({
   *   sold: {type: 'boolean', default: false},
   * });
   * store.delValuesSchema();
   * console.log(store.getValuesSchemaJson());
   * // -> '{}'
   * ```
   * @category Deleter
   * @since v3.0.0
   */
  delValuesSchema<
    TablesSchema extends OptionalTablesSchema = Schemas[0],
  >(): MergeableStore<[TablesSchema, NoValuesSchema]>;

  /**
   * The delSchema method lets you remove both the TablesSchema and ValuesSchema
   * of the Store.
   *
   * Prior to v3.0, this method removed the TablesSchema only.
   * @returns A reference to the Store.
   * @example
   * This example removes the TablesSchema and ValuesSchema of a Store.
   *
   * ```js
   * import {createStore} from 'tinybase';
   *
   * const store = createStore()
   *   .setTablesSchema({
   *     pets: {species: {type: 'string'}},
   *   })
   *   .setValuesSchema({
   *     sold: {type: 'boolean', default: false},
   *   });
   * store.delSchema();
   * console.log(store.getSchemaJson());
   * // -> '[{},{}]'
   * ```
   * @category Deleter
   * @since v3.0.0
   */
  delSchema(): MergeableStore<NoSchemas>;
}

/**
 * The createMergeableStore function creates a MergeableStore, and is the main
 * entry point into the mergeable-store module.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * createMergeableStore(
 *   uniqueId?: Id,
 *   getNow?: GetNow,
 * ): MergeableStore;
 * ```
 *
 * There are two optional parameters which are only for testing and advanced
 * usage.
 *
 * The first is a uniqueId for the MergeableStore, used to distinguish
 * conflicting changes made in the same millisecond by two different
 * MergeableStore objects as its hash is added to the end of the HLC timestamps.
 * Generally this can be omitted unless you have a need for deterministic HLCs,
 * such as in a testing scenario. Otherwise, TinyBase will assign a unique Id to
 * the Store at the time of creation.
 *
 * Since v6.1.0, the second is a function that can be used to replace the way
 * the timestamp is generated for HLCs (by default JavaScript's `Date.now()`
 * method).
 * @param uniqueId An optional unique Id for the MergeableStore.
 * @param getNow An optional function that generates millisecond timestamps,
 * since v6.1.0, defaulting to `Date.now`.
 * @returns A reference to the new MergeableStore.
 * @example
 * This example creates a MergeableStore.
 *
 * ```js
 * import {createMergeableStore} from 'tinybase';
 *
 * const store = createMergeableStore('store1');
 *
 * console.log(store.getContent());
 * // -> [{}, {}]
 * console.log(store.getMergeableContent());
 * // -> [[{}, '', 0], [{}, '', 0]]
 * ```
 * @example
 * This example creates a MergeableStore with some initial data:
 *
 * ```js
 * import {createMergeableStore} from 'tinybase';
 *
 * const store = createMergeableStore('store1').setTables({
 *   pets: {fido: {species: 'dog'}},
 * });
 *
 * console.log(store.getContent());
 * // -> [{pets: {fido: {species: 'dog'}}}, {}]
 * console.log(store.getMergeableContent());
 * // ->
 * [
 *   [
 *     {
 *       pets: [
 *         {
 *           fido: [
 *             {species: ['dog', 'Nn1JUF-----FnHIC', 290599168]},
 *             '',
 *             2682656941,
 *           ],
 *         },
 *         '',
 *         2102515304,
 *       ],
 *     },
 *     '',
 *     3506229770,
 *   ],
 *   [{}, '', 0],
 * ];
 * ```
 * @example
 * This example creates a MergeableStore with some initial data and a
 * TablesSchema:
 *
 * ```js
 * import {createMergeableStore} from 'tinybase';
 *
 * const store = createMergeableStore('store1')
 *   .setTables({pets: {fido: {species: 'dog'}}})
 *   .setTablesSchema({
 *     pets: {
 *       species: {type: 'string'},
 *       sold: {type: 'boolean', default: false},
 *     },
 *   });
 *
 * console.log(store.getContent());
 * // -> [{pets: {fido: {sold: false, species: 'dog'}}}, {}]
 * console.log(store.getMergeableContent());
 * // ->
 * [
 *   [
 *     {
 *       pets: [
 *         {
 *           fido: [
 *             {
 *               sold: [false, 'Nn1JUF----2FnHIC', 2603026204],
 *               species: ['dog', 'Nn1JUF----1FnHIC', 2817056260],
 *             },
 *             '',
 *             2859424112,
 *           ],
 *         },
 *         '',
 *         1640515891,
 *       ],
 *     },
 *     '',
 *     2077041985,
 *   ],
 *   [{}, '', 0],
 * ];
 * ```
 * @category Creation
 * @essential Creating stores
 * @since v5.0.0
 */
export function createMergeableStore(
  uniqueId?: Id,
  getNow?: GetNow,
): MergeableStore<NoSchemas>;
