/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { type IContainerStorageService } from "@fluidframework/container-definitions/internal";
import type { IContainerRuntime, IContainerRuntimeEvents } from "@fluidframework/container-runtime-definitions/internal";
import type { IEventProvider, IFluidHandleContext, IFluidHandleInternalPayloadPending, ILocalFluidHandle, ILocalFluidHandleEvents, Listenable, PayloadState } from "@fluidframework/core-interfaces/internal";
import type { ICreateBlobResponse } from "@fluidframework/driver-definitions/internal";
import type { IGarbageCollectionData, ISummaryTreeWithStats, ITelemetryContext, ISequencedMessageEnvelope } from "@fluidframework/runtime-definitions/internal";
import { FluidHandleBase } from "@fluidframework/runtime-utils/internal";
import { type IBlobManagerLoadInfo } from "./blobManagerSnapSum.js";
/**
 * This class represents blob (long string)
 * This object is used only when creating (writing) new blob and serialization purposes.
 * De-serialization process goes through FluidObjectHandle and request flow:
 * DataObject.request() recognizes requests in the form of `/blobs/<id>`
 * and loads blob.
 */
export declare class BlobHandle extends FluidHandleBase<ArrayBufferLike> implements ILocalFluidHandle<ArrayBufferLike>, IFluidHandleInternalPayloadPending<ArrayBufferLike> {
    readonly path: string;
    readonly routeContext: IFluidHandleContext;
    get: () => Promise<ArrayBufferLike>;
    readonly payloadPending: boolean;
    private readonly onAttachGraph?;
    private attached;
    get isAttached(): boolean;
    private _events;
    get events(): Listenable<ILocalFluidHandleEvents>;
    private _payloadState;
    get payloadState(): PayloadState;
    /**
     * The error property starts undefined, signalling that there has been no error yet.
     * If an error occurs, the property will contain the error.
     */
    private _payloadShareError;
    get payloadShareError(): unknown;
    readonly absolutePath: string;
    constructor(path: string, routeContext: IFluidHandleContext, get: () => Promise<ArrayBufferLike>, payloadPending: boolean, onAttachGraph?: (() => void) | undefined);
    readonly notifyShared: () => void;
    readonly notifyFailed: (error: unknown) => void;
    attachGraph(): void;
}
export type IBlobManagerRuntime = Pick<IContainerRuntime, "attachState" | "baseLogger" | "disposed"> & IEventProvider<IContainerRuntimeEvents>;
export type ICreateBlobResponseWithTTL = ICreateBlobResponse & Partial<Record<"minTTLInSeconds", number>>;
/**
 * A blob tracked by BlobManager that is only available on the local client. It is not currently
 * attempting an upload.
 */
interface LocalOnlyBlob {
    state: "localOnly";
    blob: ArrayBufferLike;
}
/**
 * A blob tracked by BlobManager that has been uploaded to storage. If the TTL has not expired, it
 * should still be available in storage. It is not currently attempting to send a BlobAttach op.
 */
interface UploadedBlob {
    state: "uploaded";
    blob: ArrayBufferLike;
    storageId: string;
    uploadTime: number;
    minTTLInSeconds: number | undefined;
}
/**
 * Serializable form of the LocalBlobRecord that can be used to save and restore pending state.
 * Omits attached blobs since they are fully uploaded and don't need to be saved and restored.
 * Omits uploading and attaching states since upon restore we will need to restart those processes.
 */
export type SerializableLocalBlobRecord = (Omit<LocalOnlyBlob, "blob"> & {
    blob: string;
}) | (Omit<UploadedBlob, "blob"> & {
    blob: string;
});
export interface IPendingBlobs {
    [localId: string]: SerializableLocalBlobRecord;
}
export declare const blobManagerBasePath = "_blobs";
export declare class BlobManager {
    private readonly mc;
    private readonly internalEvents;
    /**
     * Map of local IDs to storage IDs. Also includes identity mappings of storage ID to storage ID for all known
     * storage IDs. All requested IDs must be a key in this map. Blobs created while the container is detached are
     * stored in IDetachedBlobStorage which gives pseudo storage IDs; the real storage IDs are filled in at attach
     * time via setRedirectTable().
     */
    private readonly redirectTable;
    /**
     * The localBlobCache has a dual role of caching locally-created blobs, as well as tracking their state as they
     * are shared. Keys are localIds.
     */
    private readonly localBlobCache;
    /**
     * Blobs with an attached handle that have not finished blob-attaching are the set we need to provide from
     * getPendingState().  This stores their local IDs, and then we can look them up against the localBlobCache.
     */
    private readonly pendingBlobsWithAttachedHandles;
    /**
     * Local IDs for any pending blobs we loaded with and have not yet started the upload/attach flow for.
     */
    private readonly pendingOnlyLocalIds;
    private readonly sendBlobAttachMessage;
    private readonly routeContext;
    private readonly storage;
    private readonly blobRequested;
    private readonly isBlobDeleted;
    private readonly runtime;
    private readonly createBlobPayloadPending;
    constructor(props: {
        readonly routeContext: IFluidHandleContext;
        blobManagerLoadInfo: IBlobManagerLoadInfo;
        readonly storage: Pick<IContainerStorageService, "createBlob" | "readBlob">;
        /**
         * Submit a BlobAttach message. When a blob is uploaded, there is a short grace period before which the blob is
         * deleted. The BlobAttach message notifies the server that blob is in use. The server will then not delete the
         * the blob as long as it is listed as referenced in future summaries. The summarizing client will know to
         * include the storage ID in the summary when it sees the message.
         *
         * The message will also include a local ID to inform all clients of the relation to the storage ID, without
         * knowledge of which they cannot request the blob from storage. It's important that this message is sequenced
         * before any messages that reference the local ID, otherwise, an invalid handle could be added to the document.
         */
        sendBlobAttachMessage: (localId: string, storageId: string) => void;
        readonly blobRequested: (blobPath: string) => void;
        readonly isBlobDeleted: (blobPath: string) => boolean;
        readonly runtime: IBlobManagerRuntime;
        pendingBlobs: IPendingBlobs | undefined;
        readonly createBlobPayloadPending: boolean;
    });
    /**
     * Returns whether a blob with the given localId can be retrieved by the BlobManager via getBlob().
     */
    hasBlob(localId: string): boolean;
    /**
     * Lookup the blob storage ID for a given local blob id.
     * @param localId - The local blob id. Likely coming from a handle.
     * @returns The storage ID if found and the blob is not pending, undefined otherwise.
     * @remarks
     * For blobs with pending payloads (localId exists but upload hasn't finished), this is expected to return undefined.
     * Consumers should use the observability APIs on the handle (handle.payloadState, payloadShared event)
     * to understand/wait for storage ID availability.
     * Similarly, when the runtime is detached, this will return undefined as no blobs have been uploaded to storage.
     */
    lookupTemporaryBlobStorageId(localId: string): string | undefined;
    /**
     * Retrieve the blob with the given local blob id.
     * @param localId - The local blob id.  Likely coming from a handle.
     * @param payloadPending - Whether we suspect the payload may be pending and not available yet.
     * @returns A promise which resolves to the blob contents
     */
    getBlob(localId: string, payloadPending: boolean): Promise<ArrayBufferLike>;
    private getNonPayloadPendingBlobHandle;
    createBlob(blob: ArrayBufferLike, signal?: AbortSignal): Promise<IFluidHandleInternalPayloadPending<ArrayBufferLike>>;
    private createBlobDetached;
    private createBlobLegacy;
    private createBlobWithPayloadPending;
    /**
     * Upload and attach the localBlobCache entry for the given localId.
     *
     * Expects the localBlobCache entry for the given localId to be in either localOnly or uploaded state
     * when called. Returns a promise that resolves when the blob completes uploading and attaching, or else
     * rejects if an error is encountered or the signal is aborted.
     */
    private readonly uploadAndAttach;
    /**
     * Resubmit a BlobAttach op. Used to add storage IDs to messages that were
     * submitted to runtime while disconnected.
     * @param metadata - message metadata containing storage and/or local IDs
     */
    reSubmit(metadata: Record<string, unknown> | undefined): void;
    processBlobAttachMessage(message: ISequencedMessageEnvelope, local: boolean): void;
    summarize(telemetryContext?: ITelemetryContext): ISummaryTreeWithStats;
    /**
     * Generates data used for garbage collection. Each blob uploaded represents a node in the GC graph as it can be
     * individually referenced by storing its handle in a referenced DDS. Returns the list of blob ids as GC nodes.
     * @param fullGC - true to bypass optimizations and force full generation of GC data. BlobManager doesn't care
     * about this for now because the data is a simple list of blob ids.
     */
    getGCData(fullGC?: boolean): IGarbageCollectionData;
    /**
     * Delete blobs with the given routes from the redirect table.
     * @returns The routes of blobs that were deleted.
     *
     * @remarks
     * The routes are GC nodes paths of format -`/<blobManagerBasePath>/<localId>`.
     * Deleting the blobs involves 2 steps:
     *
     * 1. The redirect table entry for the local ids are deleted.
     *
     * 2. If the storage ids corresponding to the deleted local ids are not referenced by any further local ids, the
     * identity mappings in the redirect table are deleted as well.
     *
     * Note that this does not delete the blobs from storage service immediately. Deleting the blobs from redirect table
     * will ensure we don't create an attachment blob for them at the next summary. The service would then delete them
     * some time in the future.
     */
    deleteSweepReadyNodes(sweepReadyBlobRoutes: readonly string[]): readonly string[];
    /**
     * Verifies that the blob with given id is not deleted, i.e., it has not been garbage collected. If the blob is GC'd,
     * log an error and throw if necessary.
     */
    private verifyBlobNotDeleted;
    /**
     * Called in detached state just prior to attaching, this will update the redirect table by
     * converting the pseudo storage IDs into real storage IDs using the provided detachedStorageTable.
     * The provided table must have exactly the same set of pseudo storage IDs as are found in the redirect table.
     * @param detachedStorageTable - A map of pseudo storage IDs to real storage IDs.
     */
    readonly patchRedirectTable: (detachedStorageTable: Map<string, string>) => void;
    /**
     * Upload and attach any pending blobs that the BlobManager was loaded with that have not already
     * been attached in the meantime.
     * @returns A promise that resolves when all the uploads and attaches have completed, or rejects
     * if any of them fail.
     */
    readonly sharePendingBlobs: () => Promise<void>;
    /**
     * To be used in getPendingLocalState flow. Get a serializable record of the blobs that are
     * pending upload and/or their BlobAttach op, which can be given to a new BlobManager to
     * resume work.
     */
    getPendingBlobs(): IPendingBlobs | undefined;
}
/**
 * For a localId, returns its path in GC's graph. The node path is of the format `/<blobManagerBasePath>/<localId>`.
 * This path must match the path of the blob handle returned by the createBlob API because blobs are marked
 * referenced by storing these handles in a referenced DDS.
 */
export declare const getGCNodePathFromLocalId: (localId: string) => string;
/**
 * Returns whether a given path is for attachment blobs that are in the format - "/blobManagerBasePath/...".
 */
export declare const isBlobPath: (path: string) => path is `/_blobs/${string}`;
export {};
//# sourceMappingURL=blobManager.d.ts.map