import { StorageAdapter } from '@localfirst/storage-abstract'; import A from 'automerge'; import { ChangeManifest, Clock, ClockMap, RepoHistory, RepoSnapshot } from './types'; /** * A Repo manages a set of Automerge documents. For each document, it persists: * 1. the document history (in an append-only log of changes), and * 2. a snapshot of the document's latest state. * * Each repo is uniquely identified by a discovery key. * * A repo is instantiated by StoreManager when creating or joining a store. Actions coming from the * store are passed onto the repo, as are changes received from peers. */ export declare class Repo { private log; private storage; collections: string[]; databaseName: string; clientId: string; /** In-memory map of document snapshots */ private state; /** In-memory map of document clocks */ clock: ClockMap; /** Document change event listeners. Each listener fires every time a document is set or removed. */ private listeners; constructor({ discoveryKey, databaseName, clientId, storage, collections, }: RepoOptions); open: () => Promise; close: () => Promise; /** * Initializes the repo and returns a snapshot of its current state. * @param initialState The starting state to use when creating a new repo. * @param create Use `true` if creating a new repo, `false` if joining an existing repo (one * that we already created locally, or that a peer has) * @returns A snapshot of the repo's current state. */ init(initialState: any, create: boolean): Promise; /** @returns true if this repo has this document (even if it's been deleted) */ has(documentId: string): boolean; /** Returns the number of document IDs that this repo has (including deleted) */ get count(): number; /** Reconstitutes an Automerge document from its change history */ get(documentId: string): Promise | undefined>; /** * Saves the document's change history and snapshot, and updates our in-memory state. * @param documentId The ID of the document * @param doc The new version of the document * @param changes (optional) If we're already given the changes (e.g. in `applyChanges`), we can * pass them in so we don't have to recalculate them. */ set(documentId: string, doc: A.Doc, changes?: A.Change[]): Promise; /** * Updates a document using an Automerge change function (e.g. from a reducer) * @param documentId The ID of the document * @param changeFn An Automerge change function * @returns The updated document */ change(documentId: string, changeFn: A.ChangeFn, { collectionName, snapshotOnly, }?: { collectionName?: string; snapshotOnly?: boolean; }): Promise; /** * Updates a document using a set of Automerge changes (typically received from a peer). * @param documentId The ID of the document * @param changes A diff in the form of an array of Automerge change objects * @returns The updated document */ applyChanges(documentId: string, changes: A.Change[]): Promise>; /** * Marks all documents belonging to the given collection as deleted * @param collectionName The name of the collection (e.g. `widgets`) */ drop(collectionName: string, snapshotOnly?: boolean): Promise; /** * Updates a document from a change manifest. This is called either * - from a reducer (in which case `snapshotOnly` will be true and this will happen * synchronously); or * - from middleware (in which case `snapshotOnly` will be false and this will happen * asynchronously). * @param cm The ChangeManifest contains information about what needs to change. Can be: * - a function that is applied to the GLOBAL document * - an object containing a function, along with the name of the collection and the id of the * document to apply it to * - an object containing the name of a collection, and id, and a `delete` flag, indicating that * the item should be deleted * - an object containing the name of a collection and a `drop` flag, indicating that the * collection should be dropped * @param snapshotOnly Indicates whether the changes should be made to snapshots (synchronously), * or to the change history (asynchronously) */ applyChangeManifest(cm: ChangeManifest, snapshotOnly?: boolean): Promise; /** * Used for sending the entire current state of the repo to a new peer. * @batchSize The number of items to send at once * @returns an object mapping documentIds to an array of changes. */ getHistory(batchSize?: number): AsyncGenerator; /** Used when receiving the entire current state of a repo from a peer. */ loadHistory(history: RepoHistory): Promise; /** * Gets the in-memory snapshot of a document * @param documentId * @returns a plain JS object */ getSnapshot(documentId: string): import("@localfirst/storage-abstract").Snapshot | null; /** * Sets the in-memory snapshot of a document. * > NOTE: This does not update the document's change history or persist anything; it's just to * allow synchronous updates of the state for UI purposes. * @param documentId * @param snapshot */ setSnapshot(documentId: string, snapshot: any): void; /** * Removes the snapshot with the given `documentId` from in-memory state. (More precisely, sets it * to `null`, so we don't forget that we've seen the document before.) * @param documentId */ deleteSnapshot(documentId: string): void; /** Returns the state of the entire repo, containing snapshots of all the documents. */ getState(): RepoSnapshot; /** * Replaces the (snapshot) state of the entire repo. * > NOTE: This doesn't update the repo's change history or persist anything; this is only used * for synchronous updates of the state for UI purposes. */ setState(state: RepoSnapshot): void; /** * Accessor for a document's clock * @param documentId * @returns Our clock, or if none exists, an empty clock */ getClock(documentId: string): Clock; /** Returns our entire ClockMap as-is */ getAllClocks(): ClockMap; /** * Updates the vector clock by merging in the new vector clock `clock`, setting each node's * sequence number to the maximum for that node * @param documentId * @param newClock */ updateClock(documentId: string, newClock: Clock): void; /** Adds a change event listener */ addListener(listener: RepoEventListener): void; /** Removes a change event listener */ removeListener(listener: RepoEventListener): void; private get ids(); /** @returns `true` if there is any stored data in the repo. */ private hasData; /** Takes a (denormalized) initial state, and creates a new repo */ private create; /** Loads all the repo's snapshots and clocks into memory */ private load; /** Recreates an Automerge document from its change history */ private reconstruct; /** Adds a set of changes to the document's append-only history. */ private appendChanges; /** * Gets all stored changesets from a document's history. * @param documentId The ID of the requested document. * @returns An array of changesets in order of application. */ private getChanges; /** Saves the snapshot for the given `documentId`, replacing any existing snapshot. */ private saveSnapshot; } export declare type RepoEventListener = (documentId: string, doc: A.Doc) => void | Promise; interface RepoOptions { /** The discovery key is a unique ID for this dataset, used to identify it when seeking peers with * whom to synchronize. In the example apps we use randomly generated two-word names like * `golden-lizard`. It could also be a UUID. */ discoveryKey: string; /** Name to distinguish this application's data from others that this browser might have stored; * e.g. `grid` or `todos`. */ databaseName: string; /** Unique identifier representing this peer */ clientId?: string; /** Storage adapter to use. Defaults to `IdbAdapter` */ storage?: StorageAdapter; /** Collections */ collections?: string[]; } export {};