import { DiscreteArray, DiscreteObject } from "../types.ts"; import { Patch } from "./applyPatches.ts"; import type { DeepPatch, DeepSignal } from "@ng-org/alien-deepsignals"; import type { BaseType } from "@ng-org/shex-orm"; /** * Class for managing RDF-based ORM subscriptions with the engine. * * You have two options on how to interact with the ORM: * - Use a hook for your favorite framework under `@ng-org/orm/react|vue|svelte` * - Call {@link OrmSubscription.getOrCreate} to create a subscription manually * * For more information about RDF-based ORM subscriptions, * see the [README](../../../README.md) and follow the tutorial. */ export declare class DiscreteOrmSubscription { /** Global store of all subscriptions. We use that for pooling. */ private static idToEntry; /** The document ID (NURI) of the subscribed document. */ readonly documentId: string; private _signalObject; private stopSignalListening; /** The subscription ID kept as an identifier for communicating with the verifier. */ private subscriptionId; /** The number of OrmSubscriptions with the same shape and scope (for pooling). */ private refCount; /** When true, modifications from the signalObject are not processed. */ private suspendDeepWatcher; /** True, if a transaction is running. */ private inTransaction_; /** Aggregation of patches to be sent when in transaction. @ignore */ private pendingPatches; /** **Await to ensure that the subscription is established and the data arrived.** */ private readyPromise_; private closeOrmSubscription; /** Function to call once initial data has been applied. */ private resolveReady; private constructor(); /** * The signalObject containing all data of the document * (once subscription is established). * The object behaves like a regular object or array with a couple of additions: * - Modifications are immediately propagated back to the database. * - Database changes are immediately reflected in the object. * - Watch for object changes using {@link watchDeepSignal}. * - Objects in arrays receive a unique `@id` property. */ get signalObject(): DeepSignal | undefined; /** * Returns an OrmSubscription which subscribes to the given * document in a 2-way binding. * * You **find the document data** in the **`signalObject`**, * once {@link readyPromise} resolves. * This is a {@link DeepSignal} object or array, depending on * your CRDT document (e.g. YArray vs YMap). The signalObject * behaves like a regular set to the outside but has a couple * of additional features: * - Modifications are propagated back to the document. * Note that multiple immediate modifications in the same task, * e.g. `obj[0] = "foo"; obj[1] = "bar"` are batched together * and sent in a subsequent microtask. * - External document changes are immediately reflected in the object. * - Watch for object changes using {@link watchDeepSignal}. * * You can use **transactions**, to prevent excessive calls to the engine * with {@link beginTransaction} and {@link commitTransaction}. * * In many cases, you are advised to use a hook for your * favorite framework under `@ng-org/orm/react|vue|svelte` * instead of calling `getOrCreate` directly. * * Call `{@link close}, to close the subscription. * * Note: If another call to `getOrCreate` was previously made * and {@link close} was not called on it (or only shortly after), * it will return the same OrmSubscription (pooling). * * @param documentId The document ID (NURI) of the CRDT * * @example * ```typescript * // We assume you have created a CRDT document already, as below. * // const documentId = await ng.doc_create( * // session_id, * // crdt, // "Automerge" | "YMap" | "YArray". YArray is for root arrays, the other two have objects at root. * // crdt === "Automerge" ? "data:json" : crdt === "YMap ? "data:map" : "data:array", * // "store", * // undefined * // ); * const subscription = DiscreteOrmSubscription.getOrCreate(documentId); * // Wait for data. * await subscription.readyPromise; * * const document = subscription.signalObject; * if (!document.expenses) { * document.expenses = []; * } * document.expenses.push({ * name: "New Expense name", * description: "Expense description" * }); * * // Await promise to run the below code in a new task. * // That will have push the changes to the database. * await Promise.resolve(); * * // Here, the expense modifications have been committed * // (unless you had previously called subscription.beginTransaction()). * // The data is available in subscriptions running on a different device too. * * subscription.close(); * * // If you create a new subscription with the same document within a couple of 100ms, * // The subscription hasn't been closed and the old one is returned so that the data * // is available instantly. This is especially useful in the context of unmounting and remounting frontend frameworks. * const subscription2 = DiscreteOrmSubscription.getOrCreate(documentId); * * subscription2.signalObject.expenses.push({ * name: "Second expense", * description: "Second description" * }); * * subscription2.close(); * ``` */ static getOrCreate: (documentId: string) => DiscreteOrmSubscription; /** True, if a transaction is running. */ get inTransaction(): boolean; /** **Await to ensure that the subscription is established and the data arrived.** */ get readyPromise(): Promise; /** * Stop the subscription. * * **If there is more than one subscription with the document ID, * the orm subscription won't close yet.** * * Additionally, the closing of the subscription is delayed by a couple hundred milliseconds * so that when frontend frameworks unmount and soon mount a component again with the same * document ID, we reuse the same orm subscription. */ close: () => void; /** Handle updates (patches) coming from signal object modifications. */ private onSignalObjectUpdate; /** Handle messages coming from the engine (initial data or patches). */ private onBackendMessage; private handleInitialResponse; /** Handle incoming patches from the engine */ private onBackendUpdate; /** * Begins a transaction that batches changes to be committed to the database. * This is useful for performance reasons. * * Note that this does not disable reactivity of the `signalObject`. * Modifications keep being rendered instantly. */ beginTransaction: () => void; /** * Commits a transactions sending all modifications made during the transaction * (started with `beginTransaction`) to the database. * @throws if no transaction is open. */ commitTransaction: () => Promise; } /** * Converts DeepSignal patches to ORM Wasm-compatible patches * @param patches DeepSignal patches * @returns Patches with stringified path * * @ignore */ export declare function deepPatchesToWasm(patches: DeepPatch[]): Patch[]; //# sourceMappingURL=DiscreteOrmSubscription.d.ts.map