/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import type { IDisposable, Listenable } from "@fluidframework/core-interfaces";
import { type ChangeFamilyEditor, type GraphCommit, type TaggedChange } from "../core/index.js";
import type { SharedTreeBranch, SharedTreeBranchEvents } from "./branch.js";
/**
 * Describes the result of a transaction.
 * Transactions may either succeed and commit, or fail and abort.
 */
export declare enum TransactionResult {
    /**
     * Indicates the transaction failed.
     */
    Abort = 0,
    /**
     * Indicates the transaction succeeded.
     */
    Commit = 1
}
/**
 * A simple API for managing transactions.
 */
export interface Transactor {
    /**
     * Start a new transaction.
     * If a transaction is already in progress when this new transaction starts, then this transaction will be "nested" inside of it,
     * i.e. the outer transaction will still be in progress after this new transaction is committed or aborted.
     *
     * @remarks - Asynchronous transactions are not supported on the root checkout,
     * since it is always kept up-to-date with the latest remote edits and the results of this rebasing (which might invalidate
     * the transaction) is not visible to the application author.
     * Instead,
     *
     * 1. fork the root checkout
     * 2. run the transaction on the fork
     * 3. merge the fork back into the root checkout
     *
     * @privateRemarks - There is currently no enforcement that asynchronous transactions don't happen on the root checkout.
     * AB#6488 tracks adding some enforcement to make it more clear to application authors that this is not supported.
     */
    start(): void;
    /**
     * Close this transaction by squashing its edits and committing them as a single edit.
     * If this is the root checkout and there are no ongoing transactions remaining, the squashed edit will be submitted to Fluid.
     */
    commit(): void;
    /**
     * Close this transaction and revert the state of the tree to what it was before this transaction began.
     */
    abort(): void;
    /**
     * True if there is at least one transaction currently in progress on this view, otherwise false.
     */
    isInProgress(): boolean;
    /**
     * Provides events for changes in transaction progress.
     */
    events: Listenable<TransactionEvents>;
}
export interface TransactionEvents {
    /**
     * Raised just after a transaction has begun.
     * @remarks When this event fires, {@link Transactor.isInProgress} will be true because the transaction has already begun.
     */
    started(): void;
    /**
     * Raised just before a transaction is aborted.
     * @remarks When this event fires, {@link Transactor.isInProgress} will still be true because the transaction has not yet ended.
     */
    aborting(): void;
    /**
     * Raised just before a transaction is committed.
     * @remarks When this event fires, {@link Transactor.isInProgress} will still be true because the transaction has not yet ended.
     */
    committing(): void;
}
/**
 * A function that will be called when a transaction is pushed to the {@link TransactionStack | stack}.
 * @remarks This function may return {@link OnPop | its complement} - another function that will be called when the transaction is popped from the stack.
 * This function runs just before the transaction begins, so if this is the beginning of an outermost (not nested) transaction then {@link Transactor.isInProgress} will be false during its execution.
 */
export type OnPush = () => OnPop | void;
/**
 * A function that will be called when a transaction is popped from the {@link TransactionStack | stack}.
 * @remarks This function runs just after the transaction ends, so if this is the end of an outermost (not nested) transaction then {@link Transactor.isInProgress} will be false during its execution.
 */
export type OnPop = (result: TransactionResult) => void;
/**
 * An implementation of {@link Transactor} that uses a stack to manage transactions.
 * @remarks Using a stack allows transactions to nest - i.e. an inner transaction may be started while an outer transaction is already in progress.
 */
export declare class TransactionStack implements Transactor, IDisposable {
    #private;
    get events(): Listenable<TransactionEvents>;
    get disposed(): boolean;
    /**
     * Construct a new {@link TransactionStack}.
     * @param onPush - A {@link OnPush | function} that will be called when a transaction begins.
     */
    constructor(onPush?: () => OnPop | void);
    isInProgress(): boolean;
    start(): void;
    commit(): void;
    abort(): void;
    dispose(): void;
    private ensureNotDisposed;
}
/**
 * An implementation of {@link Transactor} that {@link TransactionStack | uses a stack} and a {@link SharedTreeBranch | branch} to manage transactions.
 * @remarks Given a branch, this class will fork the branch when a transaction begins and squash the forked branch back into the original branch when the transaction ends.
 * This class provides conveniences for interacting with the {@link SquashingTransactionStack.activeBranch | active branch} in a way that is stable across transaction boundaries.
 * For example, see {@link SquashingTransactionStack.activeBranchEditor | activeBranchEditor} and {@link SquashingTransactionStack.activeBranchEvents | activeBranchEvents}.
 */
export declare class SquashingTransactionStack<TEditor extends ChangeFamilyEditor, TChange> extends TransactionStack {
    #private;
    readonly branch: SharedTreeBranch<TEditor, TChange>;
    /**
     * An editor for whichever branch is currently the {@link SquashingTransactionStack.activeBranch | active branch}.
     * @remarks This editor can safely be held on to across transaction boundaries, as it will properly delegate to the correct branch.
     * In contrast, it is not safe to hold onto e.g. `activeBranch.editor` across transaction boundaries, since the active branch may change.
     */
    readonly activeBranchEditor: TEditor;
    /**
     * Get the "active branch" for this transactor - either the transaction branch if a transaction is in progress, or the original branch otherwise.
     */
    get activeBranch(): SharedTreeBranch<TEditor, TChange>;
    /**
     * Provides events for changes in the {@link SquashingTransactionStack.activeBranch | active branch}.
     * @remarks When the active branch changes, the listeners for these events will automatically be transferred to the new active branch.
     * In contrast, binding an event to the {@link SquashingTransactionStack.activeBranch | active branch} directly will not automatically transfer the listener when the active branch changes.
     */
    get activeBranchEvents(): Listenable<SharedTreeBranchEvents<TEditor, TChange>>;
    /**
     * Construct a new {@link SquashingTransactionStack}.
     * @param branch - The {@link SquashingTransactionStack.branch | branch} that will be forked off of when a transaction begins.
     * @param squash - Called once when the outer-most transaction is committed to produce a single squashed change from the transaction's commits.
     * The change will be applied to the original {@link SquashingTransactionStack.branch | branch}.
     * @param onPush - {@link OnPush | A function} that will be called when a transaction is pushed to the {@link TransactionStack | stack}.
     */
    constructor(branch: SharedTreeBranch<TEditor, TChange>, squash: (commits: GraphCommit<TChange>[]) => TaggedChange<TChange>, onPush?: OnPush);
    /** Updates the transaction branch (and therefore the active branch) and rebinds the branch events. */
    private setTransactionBranch;
}
//# sourceMappingURL=transaction.d.ts.map