import { inspect } from "util";
import type { Client } from "../abstract/Client";
import type { Handler } from "../abstract/Loader";
import { Loader } from "../abstract/Loader";
import type { QueryAnnotation } from "../abstract/QueryAnnotation";
import type { Shard } from "../abstract/Shard";
import { MASTER, STALE_REPLICA } from "../abstract/Shard";
import { Timeline } from "../abstract/Timeline";
import type { TimelineStorage } from "./TimelineStorage";
import type { VCFlavor } from "./VCFlavor";
/**
 * Guest VC: has minimum permissions. Typically if the user is not logged in,
 * this VC is used.
 */
export declare const GUEST_ID = "guest";
/**
 * Temporary "omniscient" VC. Any Ent can be loaded with it, but this VC is
 * replaced with lower-pri VC as soon as possible. E.g. when some Ent is loaded
 * with omni VC, its ent.vc is assigned to either this Ent's "owner" VC
 * (accessible via VC pointing field) or, if not detected, to guest VC.
 */
export declare const OMNI_ID = "omni";
/**
 * VC - Viewer Context.
 *
 * VC is set per HTTP request (or per worker job) in each Ent and represents the
 * person who is about to run some database operation. It can represent a user,
 * or a guest, or a bot observing that Ent.
 *
 * Depending on the Ent's Configuration object and privacy rules, it may allow
 * the user to load/insert/update/etc. or to traverse to related objects.
 */
export declare class VC {
    /** Trace information to quickly find all the requests done by this VC in
     * debug logs. Trace is inherited once VC is derived. */
    private readonly trace;
    /** A principal (typically user ID) represented by this VC. */
    readonly principal: string;
    /** Allows to set VC to always use either a master or a replica DB. E.g. if
     * freshness=MASTER, then all the timeline data is ignored, and all the
     * requests are sent to master. */
    readonly freshness: null | typeof MASTER | typeof STALE_REPLICA;
    /** Replication WAL position per Shard & Ent. Used to make decisions,
     * should a request be sent to a replica or to the master. */
    private timelines;
    /** Sticky objects attached to the VC (and inherited when deriving). */
    private flavors;
    /** The heartbeat callback is called before each primitive operation. It
     * plays the similar role as AbortController: when called, it may throw
     * sometimes (signalled externally). Delay callback can also be passed since
     * it's pretty common use case to wait for some time and be aborted on a
     * heartbeat exception. */
    readonly heartbeater: {
        readonly heartbeat: () => Promise<void>;
        readonly delay: (ms: number) => Promise<void>;
    };
    /** If true, it's the initial "root" VC which is not yet derived to any
     * user's VC. */
    private isRoot;
    /** If nonzero, VC#cache() will return the values which will be auto-removed
     * when VC#cache() hasn't been called for more than this time. */
    private cachesExpirationMs;
    private annotationCache?;
    private caches;
    private instanceNumber;
    /**
     * Please please don't call this method except one or two core places. The
     * idea is that we create an "origin" VC once and then derive all other VCs
     * from it (possibly upgrading or downgrading permissions, controlling
     * master/replica read policy etc.). It's also good to trace the entire chain
     * of calls and reasons, why some object was accessed.
     */
    static createGuestPleaseDoNotUseCreationPointsMustBeLimited({ trace, cachesExpirationMs }?: {
        trace?: string;
        cachesExpirationMs?: number;
    }): VC;
    /**
     * This is to show VCs in console.log() and inspect() nicely.
     */
    [inspect.custom](): string;
    /**
     * Some IDs are cached in VC (e.g. is this ID readable? is it writable? is
     * this VC an admin VC?). Also, people may define their own VC-local caches.
     */
    cache<TInstance>(Class: {
        new (vc: VC): TInstance;
    }): TInstance;
    /**
     * Same as the above overload, but allows to use a custom creating function.
     * This is useful when e.g. cached values are async-created.
     */
    cache<TInstance>(tag: symbol, creator: (vc: VC) => TInstance): TInstance;
    /**
     * Returns a cached instance of Loader whose actual code is defined in
     * HandlerClass. In case there is no such Loader yet, creates it.
     */
    loader<TLoadArgs extends unknown[], TReturn>(HandlerClass: {
        new (vc: VC): Handler<TLoadArgs, TReturn>;
        $loader?: symbol;
    }): Loader<TLoadArgs, TReturn>;
    /**
     * Returns Shard+schemaName timeline which tracks replica staleness for the
     * particular schema name (most likely, table).
     */
    timeline(shard: Shard<Client>, schemaName: string): Timeline;
    /**
     * Serializes Shard timelines (master WAL positions) to a string format. The
     * method always returns a value which is compatible to
     * deserializeTimelines() input.
     */
    serializeTimelines(): string | undefined;
    /**
     * Restores all replication timelines in the VC based on the serialized info
     * provided. Returns the new VC derived from the current one, but with empty
     * caches.
     *
     * This method has a side effect of changing the timelines of the current VC
     * (and actually all parent VCs), because it reflects the changes in the
     * global DB state as seen by the current VC's principal. It restores
     * previously serialized timelines to the existing VC and all its parent VCs
     * which share the same principal. (The latter happens, because
     * `this.timelines` map is passed by reference to all derived VCs starting
     * from the one which sets principal; see `new VC(...)` clauses all around and
     * toLowerInternal() logic.) The timelines are merged according to WAL
     * positions (larger WAL positions win).
     */
    deserializeTimelines(...dataStrs: ReadonlyArray<string | undefined>): VC;
    /**
     * Saves the timelines to the storage. The function minimizes the number of
     * writes to the storage:
     *
     * - Calling saveTimelines() the 2nd time without making changes to the
     *   timelines is a no-op.
     * - Calling saveTimelines() after loadTimelines() without making changes to
     *   the timelines is a no-op.
     */
    saveTimelines(storage: TimelineStorage): Promise<string | undefined>;
    /**
     * Loads the timelines from the storage and deserializes them into the current
     * VC. Returns the new VC derived from the current one, but with empty caches.
     */
    loadTimelines(storage: TimelineStorage): Promise<VC>;
    /**
     * Returns a new VC derived from the current one, but with empty cache.
     */
    withEmptyCache(): VC;
    /**
     * Returns a new VC derived from the current one, but with master freshness.
     * Master freshness is inherited by ent.vc after an Ent is loaded.
     */
    withTransitiveMasterFreshness(): VC;
    /**
     * Returns a new VC derived from the current one, but which forces an Ent to
     * be loaded always from replica. Freshness is NOT inherited by Ents (not
     * transitive): e.g. if an Ent is loaded with STALE_REPLICA freshness, its
     * ent.vc will have the DEFAULT freshness.
     *
     * Also, if an Ent is inserted with a VC of STALE_REPLICA freshness, its VC
     * won't remember it, so next immediate reads will go to a replica and not to
     * the master.
     */
    withOneTimeStaleReplica(): VC;
    /**
     * Creates a new VC with default freshness (i.e. not sticky to master or
     * replica, auto-detected on request). Generally, it's not a good idea to use
     * this derivation since we lose some bit of internal knowledge from the past
     * history of the VC, but for e.g. tests or benchmarks, it's fine.
     */
    withDefaultFreshness(): VC;
    /**
     * Returns a new VC derived from the current one adding some more flavors to
     * it. If no flavors were added, returns the same VC (`this`).
     */
    withFlavor(prepend: "prepend", ...flavors: Array<VCFlavor | undefined>): this;
    withFlavor(...flavors: Array<VCFlavor | undefined>): this;
    /**
     * Returns a new VC derived from the current one removing the specified flavors.
     * If no flavors were removed, returns the same VC (`this`).
     */
    withoutFlavor(...flavorClasses: Array<new (...args: never[]) => VCFlavor>): this;
    /**
     * Derives the VC with new trace ID.
     */
    withNewTrace(trace: string | undefined): VC;
    /**
     * Derives the VC with the provided heartbeater injected.
     */
    withHeartbeater(heartbeater: VC["heartbeater"]): VC;
    /**
     * Creates a new VC upgraded to omni permissions. This VC will not
     * be placed to some Ent's ent.vc property; instead, it will be
     * automatically downgraded to either the owning VC of this Ent or
     * to a guest VC (see Ent.ts).
     */
    toOmniDangerous(): VC;
    /**
     * Creates a new VC downgraded to guest permissions.
     */
    toGuest(): VC;
    /**
     * Checks if it's an omni VC.
     */
    isOmni(): boolean;
    /**
     * Checks if it's a guest VC.
     */
    isGuest(): boolean;
    /**
     * Checks if it's a regular user (i.e. owning) VC.
     */
    isLoggedIn(): boolean;
    /**
     * Returns VC's flavor of the particular type.
     */
    flavor<TFlavor extends VCFlavor>(flavor: new (...args: never[]) => TFlavor): TFlavor | null;
    /**
     * Used for debugging purposes.
     */
    toString(withInstanceNumber?: boolean): string;
    /**
     * Returns a debug annotation of this VC.
     */
    toAnnotation(): QueryAnnotation;
    /**
     * Used internally by Ent framework to lower permissions of an injected VC.
     * For guest, principal === null.
     * - freshness is always reset to default one it VC is demoted
     * - isRoot is changed to false once a root VC is switched to a per-user VC
     */
    toLowerInternal(principal: string | null): VC;
    /**
     * Private constructor disallows inheritance and manual object creation.
     */
    private constructor();
}
//# sourceMappingURL=VC.d.ts.map