/*! * Copyright (c) Microsoft Corporation and contributors. All rights reserved. * Licensed under the MIT License. */ import type { ILayerCompatDetails, IProvideLayerCompatDetails } from "@fluid-internal/client-utils"; import { TypedEventEmitter } from "@fluid-internal/client-utils"; import type { IAudience, ICriticalContainerError } from "@fluidframework/container-definitions"; import { AttachState } from "@fluidframework/container-definitions"; import type { IContainerContext, IGetPendingLocalStateProps, IRuntime, IDeltaManager, IContainerStorageService, ConnectionStatus } from "@fluidframework/container-definitions/internal"; import type { ContainerExtensionFactory, ContainerExtensionId, ExtensionRuntimeProperties, IContainerRuntime, IContainerRuntimeEvents, IContainerRuntimeInternal, IContainerRuntimeWithResolveHandle_Deprecated } from "@fluidframework/container-runtime-definitions/internal"; import type { FluidObject, IFluidHandle, IRequest, IResponse, ITelemetryBaseLogger } from "@fluidframework/core-interfaces"; import type { IFluidHandleContext, IFluidHandleInternal, IProvideFluidHandleContext, ISignalEnvelope, OpaqueJsonDeserialized, TypedMessage } from "@fluidframework/core-interfaces/internal"; import type { IClientDetails, IQuorumClients, ISummaryTree } from "@fluidframework/driver-definitions"; import type { IDocumentMessage, ISequencedDocumentMessage, ISignalMessage, ISnapshotTree } from "@fluidframework/driver-definitions/internal"; import { MessageType } from "@fluidframework/driver-definitions/internal"; import type { IIdCompressor } from "@fluidframework/id-compressor"; import type { IIdCompressorCore, SerializedIdCompressorWithOngoingSession } from "@fluidframework/id-compressor/internal"; import { FlushMode } from "@fluidframework/runtime-definitions/internal"; import type { ISummaryTreeWithStats, ITelemetryContext, IGarbageCollectionData, CreateChildSummarizerNodeParam, IDataStore, IFluidDataStoreContextDetached, IFluidDataStoreRegistry, IFluidParentContext, NamedFluidDataStoreRegistryEntries, SummarizeInternalFn, ISummarizerNodeWithGC, StageControlsInternal, IContainerRuntimeBaseInternal, MinimumVersionForCollab, ContainerExtensionExpectations } from "@fluidframework/runtime-definitions/internal"; import { TelemetryContext } from "@fluidframework/runtime-utils/internal"; import type { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal"; import { type IPendingBlobs, type IBlobManagerLoadInfo } from "./blobManager/index.js"; import type { ICompressionRuntimeOptions } from "./compressionDefinitions.js"; import { GCNodeType, type IGCRuntimeOptions, type IGCStats, type IGarbageCollectionRuntime } from "./gc/index.js"; import { type ContainerRuntimeAliasMessage, type ContainerRuntimeDataStoreOpMessage, type LocalContainerRuntimeMessage, type OutboundContainerRuntimeAttachMessage } from "./messageTypes.js"; import { type OutboundBatch } from "./opLifecycle/index.js"; import { type IPendingLocalState } from "./pendingStateManager.js"; import { DocumentsSchemaController, type EnqueueSummarizeResult, type IContainerRuntimeMetadata, type IdCompressorMode, type IDocumentSchemaCurrent, type IDocumentSchemaFeatures, type IEnqueueSummarizeOptions, type IOnDemandSummarizeOptions, type IRefreshSummaryAckOptions, type ISerializedElection, type ISubmitSummaryOptions, type ISummarizeResults, type ISummarizerInternalsProvider, type ISummarizerRuntime, type ISummaryConfiguration, type SubmitSummaryResult } from "./summary/index.js"; /** * @legacy @beta */ export interface ISummaryRuntimeOptions { /** * Override summary configurations set by the server. */ summaryConfigOverrides?: ISummaryConfiguration; /** * Delay before first attempt to spawn summarizing container. * * @deprecated Use {@link ISummaryRuntimeOptions.summaryConfigOverrides}'s * {@link ISummaryBaseConfiguration.initialSummarizerDelayMs} instead. */ initialSummarizerDelayMs?: number; } /** * Full set of options for container runtime as "required". * * @remarks * {@link IContainerRuntimeOptions} is expected to be used by consumers. * * @privateRemarks If any new properties are added to this interface (or * {@link IContainerRuntimeOptionsInternal}), then we will also need to make * changes in {@link file://./containerCompatibility.ts}. * If the new property does not change the DocumentSchema, then it must be * explicity omitted from {@link RuntimeOptionsAffectingDocSchema}. * If it does change the DocumentSchema, then a corresponding entry must be * added to `runtimeOptionsAffectingDocSchemaConfigMap` with the appropriate * compat configuration info. * If neither of the above is done, then the build will fail to compile. * * @legacy @beta */ export interface ContainerRuntimeOptions { readonly summaryOptions: ISummaryRuntimeOptions; readonly gcOptions: IGCRuntimeOptions; /** * Affects the behavior while loading the runtime when the data verification check which * compares the DeltaManager sequence number (obtained from protocol in summary) to the * runtime sequence number (obtained from runtime metadata in summary) finds a mismatch. * 1. "close" (default) will close the container with an assertion. * 2. "log" will log an error event to telemetry, but still continue to load. * 3. "bypass" will skip the check entirely. This is not recommended. */ readonly loadSequenceNumberVerification: "close" | "log" | "bypass"; /** * Enables the runtime to compress ops. See {@link ICompressionRuntimeOptions}. */ readonly compressionOptions: ICompressionRuntimeOptions; /** * If specified, when in FlushMode.TurnBased, if the size of the ops between JS turns exceeds this value, * an error will be thrown and the container will close. * * If unspecified, the limit is 700Kb. * * 'Infinity' will disable any limit. * * @experimental This config should be driven by the connection with the service and will be moved in the future. */ readonly maxBatchSizeInBytes: number; /** * If the op payload needs to be chunked in order to work around the maximum size of the batch, this value represents * how large the individual chunks will be. This is only supported when compression is enabled. If after compression, the * batch content size exceeds this value, it will be chunked into smaller ops of this exact size. * * This value is a trade-off between having many small chunks vs fewer larger chunks and by default, the runtime is configured to use * 200 * 1024 = 204800 bytes. This default value ensures that no compressed payload's content is able to exceed {@link ContainerRuntimeOptions.maxBatchSizeInBytes} * regardless of the overhead of an individual op. * * Any value of `chunkSizeInBytes` exceeding {@link ContainerRuntimeOptions.maxBatchSizeInBytes} will disable this feature, therefore if a compressed batch's content * size exceeds {@link ContainerRuntimeOptions.maxBatchSizeInBytes} after compression, the container will close with an instance of `DataProcessingError` with * the `BatchTooLarge` message. */ readonly chunkSizeInBytes: number; /** * Enable the IdCompressor in the runtime. * @experimental Not ready for use. */ readonly enableRuntimeIdCompressor: IdCompressorMode; /** * If enabled, the runtime will group messages within a batch into a single * message to be sent to the service. * The grouping and ungrouping of such messages is handled by the "OpGroupingManager". * * By default, the feature is enabled. This feature can only be disabled when compression is also disabled. * @deprecated The ability to disable Grouped Batching is deprecated and will be removed in a future release. This feature is required for the proper functioning of the Fluid Framework. */ readonly enableGroupedBatching: boolean; /** * When this property is set to true, it requires runtime to control is document schema properly through ops * The benefit of this mode is that clients who do not understand schema will fail in predictable way, with predictable message, * and will not attempt to limp along, which could cause data corruptions and crashes in random places. * When this property is not set (or set to false), runtime operates in legacy mode, where new features (modifying document schema) * are engaged as they become available, without giving legacy clients any chance to fail predictably. */ readonly explicitSchemaControl: boolean; /** * Create blob handles with pending payloads when calling createBlob (default is `undefined` (disabled)). * When enabled (`true`), createBlob will return a handle before the blob upload completes. */ readonly createBlobPayloadPending: true | undefined; /** * Controls automatic batch flushing during staging mode. * Normal turn-based/async flush scheduling is suppressed while in staging mode * until the accumulated batch reaches this many ops, at which point the batch * is flushed. Incoming ops always break the current batch regardless of this setting. * * Set to Infinity to only break batches on system events (incoming ops). * * @defaultValue `largeBatchThreshold` (currently 1000) */ readonly stagingModeAutoFlushThreshold: number; /** * When this property is set to true, the runtime will never send DocumentSchemaChange ops * and will throw an error if any incoming DocumentSchemaChange ops are received. * This effectively freezes the document schema at whatever state it was in when the document was created. */ readonly disableSchemaUpgrade: boolean; } /** * Options for container runtime. * * @legacy @beta */ export type IContainerRuntimeOptions = Partial; /** * Internal extension of {@link ContainerRuntimeOptions} * * @privateRemarks * These options are not available to consumers when creating a new container runtime, * but we do need to expose them for internal use, e.g. when configuring the container runtime * to ensure compatibility with older versions. * * This is defined as a fully required set of options as this package does not yet * use `exactOptionalPropertyTypes` and `Required<>` applied to optional type allowing * `undefined` like {@link IdCompressorMode} will exclude `undefined`. * * @internal */ export interface ContainerRuntimeOptionsInternal extends ContainerRuntimeOptions { /** * Sets the flush mode for the runtime. In Immediate flush mode the runtime will immediately * send all operations to the driver layer, while in TurnBased the operations will be buffered * and then sent them as a single batch at the end of the turn. * By default, flush mode is TurnBased. */ readonly flushMode: FlushMode; /** * Allows Grouped Batching to be disabled by setting to false (default is true). * In that case, batched messages will be sent individually (but still all at the same time). */ readonly enableGroupedBatching: boolean; } /** * Internal extension of {@link IContainerRuntimeOptions} * * @internal */ export type IContainerRuntimeOptionsInternal = Partial; /** * Error responses when requesting a deleted object will have this header set to true * @internal */ export declare const DeletedResponseHeaderKey = "wasDeleted"; /** * Tombstone error responses will have this header set to true * @legacy @beta */ export declare const TombstoneResponseHeaderKey = "isTombstoned"; /** * Inactive error responses will have this header set to true * @legacy @beta * * @deprecated this header is deprecated and will be removed in the future. The functionality corresponding * to this was experimental and is no longer supported. */ export declare const InactiveResponseHeaderKey = "isInactive"; /** * The full set of parsed header data that may be found on Runtime requests * @internal */ export interface RuntimeHeaderData { wait?: boolean; viaHandle?: boolean; allowTombstone?: boolean; } /** * Default values for Runtime Headers */ export declare const defaultRuntimeHeaderData: Required; /** * State saved when the container closes, to be given back to a newly * instantiated runtime in a new instance of the container, so it can load to the * same state */ export interface IPendingRuntimeState { /** * Pending ops from PendingStateManager */ pending?: IPendingLocalState; /** * Pending blobs from BlobManager */ pendingAttachmentBlobs?: IPendingBlobs; /** * Pending idCompressor state */ pendingIdCompressorState?: SerializedIdCompressorWithOngoingSession; /** * Time at which session expiry timer started. */ sessionExpiryTimerStarted?: number | undefined; } /** * The default time to wait for pending ops to be processed during summarization */ export declare const defaultPendingOpsWaitTimeoutMs = 1000; /** * The default time to delay a summarization retry attempt when there are pending ops */ export declare const defaultPendingOpsRetryDelayMs = 1000; /** * Checks whether a message.type is one of the values in ContainerMessageType */ export declare function isUnpackedRuntimeMessage(message: ISequencedDocumentMessage): boolean; /** * Legacy ID for the built-in AgentScheduler. To minimize disruption while removing it, retaining this as a * special-case for document dirty state. Ultimately we should have no special-cases from the * ContainerRuntime's perspective. * @internal */ export declare const agentSchedulerId = "_scheduler"; export declare function getDeviceSpec(): { deviceMemory?: number | undefined; hardwareConcurrency?: number | undefined; }; /** * Older loader doesn't have a submitBatchFn member, this is the older way of submitting a batch. * Rather than exposing the submitFn (now deprecated) and IDeltaManager (dangerous to hand out) to the Outbox, * we can provide a partially-applied function to keep those items private to the ContainerRuntime. */ export declare const makeLegacySendBatchFn: (submitFn: (type: MessageType, contents: unknown, batch: boolean, appData?: unknown) => number, deltaManager: Pick, "flush">) => (batch: OutboundBatch) => number; /** * There is some ancient back-compat code that we'd like to instrument * to understand if/when it is hit. * We only want to log this once, to avoid spamming telemetry if we are wrong and these cases are hit commonly. */ export declare let getSingleUseLegacyLogCallback: (logger: ITelemetryLoggerExt, type: string) => (codePath: string) => void; /** * A {@link TypedMessage} that has unknown content explicitly * noted as deserialized JSON. */ export interface UnknownIncomingTypedMessage extends TypedMessage { content: OpaqueJsonDeserialized; } /** * This object holds the parameters necessary for the {@link loadContainerRuntime} function. * @legacy @beta */ export interface LoadContainerRuntimeParams { /** * Context of the container. */ context: IContainerContext; /** * Mapping from data store types to their corresponding factories */ registryEntries: NamedFluidDataStoreRegistryEntries; /** * Pass 'true' if loading from an existing snapshot. */ existing: boolean; /** * Additional options to be passed to the runtime. * @remarks * Defaults to `{}`. */ runtimeOptions?: IContainerRuntimeOptions; /** * runtime services provided with context */ containerScope?: FluidObject; /** * Promise that resolves to an object which will act as entryPoint for the Container. */ provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise; /** * Request handler for the request() method of the container runtime. * Only relevant for back-compat while we remove the request() method and move fully to entryPoint as the main pattern. * @deprecated Will be removed once Loader LTS version is "2.0.0-internal.7.0.0". Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md * */ requestHandler?: (request: IRequest, runtime: IContainerRuntime) => Promise; /** * Minimum version of the FF runtime that is required to collaborate on new documents. * The input should be a string that represents the minimum version of the FF runtime that should be * supported for collaboration. The format of the string must be in valid semver format. * * The inputted version will be used to determine the default configuration for * {@link IContainerRuntimeOptionsInternal} to ensure compatibility with the specified version. * * @example * minVersionForCollab: "2.0.0" * * @privateRemarks * Used to determine the default configuration for {@link IContainerRuntimeOptionsInternal} that affect the document schema. * For example, let's say that feature `foo` was added in 2.0 which introduces a new op type. Additionally, option `bar` * was added to `IContainerRuntimeOptionsInternal` in 2.0 to enable/disable `foo` since clients prior to 2.0 would not * understand the new op type. If a customer were to set minVersionForCollab to 2.0.0, then `bar` would be set to * enable `foo` by default. If a customer were to set minVersionForCollab to 1.0.0, then `bar` would be set to * disable `foo` by default. */ minVersionForCollab?: MinimumVersionForCollab; } /** * This is meant to be used by a {@link @fluidframework/container-definitions#IRuntimeFactory} to instantiate a container runtime. * @param params - An object which specifies all required and optional params necessary to instantiate a runtime. * @returns A runtime which provides all the functionality necessary to bind with the loader layer via the {@link @fluidframework/container-definitions#IRuntime} interface and provide a runtime environment via the {@link @fluidframework/container-runtime-definitions#IContainerRuntime} interface. * @legacy @beta */ export declare function loadContainerRuntime(params: LoadContainerRuntimeParams): Promise; /** * Alpha variant of {@link loadContainerRuntime} that returns the runtime in an * extendable object, allowing additional properties to be added in the future. * * @param params - An object which specifies all required and optional params necessary to instantiate a runtime. * @returns An object containing the runtime. * * @legacy @alpha */ export declare function loadContainerRuntimeAlpha(params: LoadContainerRuntimeParams): Promise<{ runtime: IContainerRuntime & IRuntime; }>; /** * Represents the runtime of the container. Contains helper functions/state of the container. * It will define the store level mappings. * * @internal */ export declare class ContainerRuntime extends TypedEventEmitter implements IContainerRuntimeInternal, IContainerRuntimeBaseInternal, IContainerRuntimeWithResolveHandle_Deprecated, IRuntime, IGarbageCollectionRuntime, ISummarizerRuntime, ISummarizerInternalsProvider, Omit, IProvideFluidHandleContext, IProvideLayerCompatDetails { private readonly registry; private readonly metadata; private readonly electedSummarizerData; private readonly runtimeOptions; private readonly containerScope; readonly baseLogger: ITelemetryBaseLogger; private readonly _storage; private readonly createIdCompressorFn; private readonly documentsSchemaController; readonly minVersionForCollab: MinimumVersionForCollab; private readonly requestHandler?; private readonly summaryConfiguration; /** * Load the stores from a snapshot and returns the runtime. * @param params - An object housing the runtime properties. * {@link LoadContainerRuntimeParams} except internal, while still having layer compat obligations. * @privateRemarks * Despite this being `@internal`, `@fluidframework/test-utils` uses it in `createTestContainerRuntimeFactory` and assumes multiple versions of the package expose the same API. * * Also note that `mixinAttributor` from `@fluid-experimental/attributor` overrides this function: * that will have to be updated if changing the signature of this function as well. * * Assuming these usages are updated appropriately, * `loadRuntime` could be removed (replaced by `loadRuntime2` which could be renamed back to `loadRuntime`). */ static loadRuntime(params: LoadContainerRuntimeParams & { /** * Constructor to use to create the ContainerRuntime instance. * @remarks * Defaults to {@link ContainerRuntime}. */ containerRuntimeCtor?: typeof ContainerRuntime; }): Promise; /** * Load the stores from a snapshot and returns an object containing the runtime. * @remarks * Same as {@link ContainerRuntime.loadRuntime}, * but with `registry` instead of `registryEntries` and more `runtimeOptions`. * Returns `{ runtime }` to allow future extensions (e.g. staging mode controls). */ static loadRuntime2(params: Omit & { /** * Mapping from data store types to their corresponding factories. */ registry: IFluidDataStoreRegistry; /** * Constructor to use to create the ContainerRuntime instance. * @remarks * Defaults to {@link ContainerRuntime}. */ containerRuntimeCtor?: typeof ContainerRuntime; /** * {@link LoadContainerRuntimeParams.runtimeOptions}, except with additional internal only options. */ runtimeOptions?: IContainerRuntimeOptionsInternal; }): Promise<{ runtime: ContainerRuntime; }>; readonly options: Record; private readonly _getClientId; get clientId(): string | undefined; readonly clientDetails: IClientDetails; private readonly isSummarizerClient; get storage(): IContainerStorageService; get containerRuntime(): ContainerRuntime; private readonly submitSummaryFn; private readonly submitSignalFn; readonly disposeFn: (error?: ICriticalContainerError) => void; readonly closeFn: (error?: ICriticalContainerError) => void; get flushMode(): FlushMode; get scope(): FluidObject; get IFluidDataStoreRegistry(): IFluidDataStoreRegistry; private readonly _getAttachState; get attachState(): AttachState; readonly isReadOnly: () => boolean; /** * Current session schema - defines what options are on & off. * It's overlap of document schema (controlled by summary & ops) and options controlling this session. * For example, document schema might have compression ON, but feature gates / runtime options turn it Off. * In such case it will be off in session schema (i.e. this session should not use compression), but this client * has to deal with compressed ops as other clients might send them. * And in reverse, session schema can have compression Off, but feature gates / runtime options want it On. * In such case it will be off in session schema, however this client will propose change to schema, and once / if * this op roundtrips, compression will be On. Client can't send compressed ops until it's change in schema. */ get sessionSchema(): { [P in keyof IDocumentSchemaFeatures]?: IDocumentSchemaFeatures[P] extends boolean ? true : IDocumentSchemaFeatures[P]; }; private _idCompressor; private pendingIdCompressorOps; private readonly skipSavedCompressorOps; /** * {@inheritDoc @fluidframework/runtime-definitions#IContainerRuntimeBase.idCompressor} */ get idCompressor(): (IIdCompressor & IIdCompressorCore) | undefined; /** * {@inheritDoc @fluidframework/runtime-definitions#IContainerRuntimeBase.generateDocumentUniqueId} */ generateDocumentUniqueId(): string | number; get IFluidHandleContext(): IFluidHandleContext; private readonly handleContext; /** * This is a proxy to the delta manager provided by the container context (innerDeltaManager). It restricts certain * accesses such as sets "read-only" mode for the summarizer client. This is the default delta manager that should * be used unless the innerDeltaManager is required. */ get deltaManager(): IDeltaManager; private readonly _deltaManager; /** * The delta manager provided by the container context. By default, using the default delta manager (proxy) * should be sufficient. This should be used only if necessary. For example, for validating and propagating connected * events which requires access to the actual real only info, this is needed. */ private readonly innerDeltaManager; private readonly mc; private summarizerClientElection?; /** * summaryManager will only be created if this client is permitted to spawn a summarizing client * It is created only by interactive client, i.e. summarizer client, as well as non-interactive bots * do not create it (see SummarizerClientElection.clientDetailsPermitElection() for details) */ private summaryManager?; private readonly summarizerNode; private readonly maxConsecutiveReconnects; private readonly batchRunner; private readonly _flushMode; private readonly stagingModeAutoFlushThreshold; /** * BatchId tracking is needed whenever there's a possibility of a "forked Container", * where the same local state is pending in two different running Containers, each of * which is trying to ensure it's persisted. * "Offline Load" from serialized pending state is one such scenario since two Containers * could load from the same serialized pending state. */ private readonly batchIdTrackingEnabled; private flushScheduled; private canSendOps; private canSendSignals; private readonly getConnectionState?; private consecutiveReconnects; private readonly dataModelChangeRunner; /** * Invokes the given callback and expects that no ops are submitted * until execution finishes. If an op is submitted, it will be marked as reentrant. * * @param callback - the callback to be invoked */ ensureNoDataModelChanges(callback: () => T): T; /** * Indicates whether the container is in a state where it is able to send * ops (connected to op stream and not in readonly mode). */ get connected(): boolean; /** * clientId of parent (non-summarizing) container that owns summarizer container */ get summarizerClientId(): string | undefined; private _disposed; get disposed(): boolean; private lastEmittedDirty; private emitDirtyDocumentEvent; private readonly useDeltaManagerOpsProxy; private readonly closeSummarizerDelayMs; private readonly signalTelemetryManager; /** * Summarizer is responsible for coordinating when to send generate and send summaries. * It is the main entry point for summary work. * It is created only by summarizing container (i.e. one with clientType === "summarizer") */ private _summarizer?; private readonly deltaScheduler; private readonly inboundBatchAggregator; private readonly blobManager; private readonly pendingStateManager; private readonly duplicateBatchDetector; private readonly outbox; private readonly garbageCollector; private readonly channelCollection; private readonly remoteMessageProcessor; /** * The last message processed at the time of the last summary. */ private messageAtLastSummary; private readonly summariesDisabled; private readonly createContainerMetadata; /** * The summary number of the next summary that will be generated for this container. This is incremented every time * a summary is generated. */ private nextSummaryNumber; /** * If false, loading or using a Tombstoned object should merely log, not fail. * @deprecated NOT SUPPORTED - hardcoded to return false since it's deprecated. */ get gcTombstoneEnforcementAllowed(): boolean; /** * If true, throw an error when a tombstone data store is used. * @deprecated NOT SUPPORTED - hardcoded to return false since it's deprecated. */ get gcThrowOnTombstoneUsage(): boolean; /** * GUID to identify a document in telemetry * ! Note: should not be used for anything other than telemetry and is not considered a stable GUID */ private readonly telemetryDocumentId; /** * The id of the version used to initially load this runtime, or undefined if it's newly created. */ private readonly loadedFromVersionId; private readonly isSnapshotInstanceOfISnapshot; /** * The summary context of the last acked summary. The properties from this as used when uploading a summary. */ private lastAckedSummaryContext; /** * It a cache for holding mapping for loading groupIds with its snapshot from the service. Add expiry policy of 1 minute. * Starting with 1 min and based on recorded usage we can tweak it later on. */ private readonly snapshotCacheForLoadingGroupIds; /** * The compatibility details of the Runtime layer that is exposed to the Loader layer * for validating Loader-Runtime compatibility. */ get ILayerCompatDetails(): ILayerCompatDetails; private readonly extensions; /***/ protected constructor(context: IContainerContext, registry: IFluidDataStoreRegistry, metadata: IContainerRuntimeMetadata | undefined, electedSummarizerData: ISerializedElection | undefined, chunks: [string, string[]][], dataStoreAliasMap: [string, string][], runtimeOptions: Readonly, containerScope: FluidObject, baseLogger: ITelemetryBaseLogger, existing: boolean, blobManagerLoadInfo: IBlobManagerLoadInfo, _storage: IContainerStorageService, createIdCompressorFn: () => IIdCompressor & IIdCompressorCore, documentsSchemaController: DocumentsSchemaController, featureGatesForTelemetry: Record, provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise, minVersionForCollab: MinimumVersionForCollab, requestHandler?: ((request: IRequest, runtime: IContainerRuntime) => Promise) | undefined, summaryConfiguration?: ISummaryConfiguration, recentBatchInfo?: [number, string][]); onSchemaChange(schema: IDocumentSchemaCurrent): void; getCreateChildSummarizerNodeFn(id: string, createParam: CreateChildSummarizerNodeParam): (summarizeInternal: SummarizeInternalFn, getGCDataFn: (fullGC?: boolean) => Promise) => ISummarizerNodeWithGC; deleteChildSummarizerNode(id: string): void; makeLocallyVisible(): void; setChannelDirty(address: string): void; /** * Initializes the state from the base snapshot this container runtime loaded from. */ private initializeBaseState; private initializeSummarizer; dispose(error?: Error): void; /** * Api to fetch the snapshot from the service for a loadingGroupIds. * @param loadingGroupIds - LoadingGroupId for which the snapshot is asked for. * @param pathParts - Parts of the path, which we want to extract from the snapshot tree. * @returns snapshotTree and the sequence number of the snapshot. */ getSnapshotForLoadingGroupId(loadingGroupIds: string[], pathParts: string[]): Promise<{ snapshotTree: ISnapshotTree; sequenceNumber: number; }>; /** * Api to find a snapshot tree inside a bigger snapshot tree based on the path in the pathParts array. * @param snapshotTree - snapshot tree to look into. * @param pathParts - Part of the path, which we want to extract from the snapshot tree. * @param hasIsolatedChannels - whether the channels are present inside ".channels" subtree. Older * snapshots will not have trees inside ".channels", so check that. * @returns requested snapshot tree based on the path parts. */ private getSnapshotTreeForPath; /** * Notifies this object about the request made to the container. * @param request - Request made to the handler. * @deprecated Will be removed in future major release. This method needs to stay private until LTS version of Loader moves to "2.0.0-internal.7.0.0". */ private request; /** * Resolves URI representing handle * @param request - Request made to the handler. */ resolveHandle(request: IRequest): Promise; /** * {@inheritDoc @fluidframework/container-definitions#IRuntime.getEntryPoint} */ getEntryPoint(): Promise; private readonly entryPoint; private internalId; /** * Adds the container's metadata to the given summary tree. */ private addMetadataToSummary; protected addContainerStateToSummary(summaryTree: ISummaryTreeWithStats, fullTree: boolean, trackState: boolean, telemetryContext?: ITelemetryContext): void; private shouldContinueReconnecting; private resetReconnectCount; private replayPendingStates; /** * Parse an op's type and actual content from given serialized content * ! Note: this format needs to be in-line with what is set in the "ContainerRuntime.submit(...)" method */ private parseLocalOpContent; private applyStashedOp; private loadIdCompressor; private readonly notifyReadOnlyState; setConnectionState(canSendOps: boolean, clientId?: string): void; setConnectionStatus(status: ConnectionStatus): void; private setConnectionStateToConnectedOrDisconnected; /** * Raises and propagates connected events. * @param canSendOps - Indicates whether the container can send ops or not (connected and not readonly). * @remarks The connection state from container context used here when raising connected events. */ private setConnectionStateCore; /** * Emits service connection events based on connection state changes. * * @remarks * "connectedToService" is emitted when container connection state transitions to 'CatchingUp' or 'Connected' regardless of connection mode. * "disconnectedFromService" excludes false "disconnected" events that happen when readonly client transitions to 'Connected'. */ private emitServiceConnectionEvents; notifyOpReplay(message: ISequencedDocumentMessage): Promise; /** * Processes the op. * @param messageCopy - Sequenced message for a distributed document. * @param local - true if the message was originally generated by the client receiving it. */ process({ ...messageCopy }: ISequencedDocumentMessage, local: boolean): void; /** * Implementation of core logic for {@link ContainerRuntime.process}, once preconditions are established * * @param messageCopy - Shallow copy of the sequenced message. If it's a virtualized batch, we'll process * all messages in the batch here. */ private processInboundMessageOrBatch; private _processedClientSequenceNumber; /** * Processes inbound message(s). It calls delta scheduler according to the messages' location in the batch. * @param messagesWithMetadata - messages to process along with their metadata. * @param locationInBatch - Are we processing the start and/or end of a batch? * @param local - true if the messages were originally generated by the client receiving it. * @param savedOp - true if the message is a replayed saved op. * @param runtimeBatch - true if these are runtime messages. * @param groupedBatch - true if these messages are part of a grouped op batch. */ private processInboundMessages; /** * Observes messages that are not intended for the runtime layer, updating/notifying Runtime systems as needed. * @param message - non-runtime message to process. */ private observeNonRuntimeMessage; /** * Process runtime messages. The messages here are contiguous messages in a batch. * Assuming the messages in the given bunch are also a TypedContainerRuntimeMessage, checks its type and dispatch * the messages to the appropriate handler in the runtime. * Throws a DataProcessingError if the message looks like but doesn't conform to a known TypedContainerRuntimeMessage type. * @param message - The core message with common properties for all the messages. * @param messageContents - The contents, local metadata and clientSequenceNumbers of the messages. * @param local - true if the messages were originally generated by the client receiving it. * @param savedOp - true if the message is a replayed saved op. * */ private validateAndProcessRuntimeMessages; private processIdCompressorMessages; processSignal(message: ISignalMessage<{ type: string; content: ISignalEnvelope<{ type: string; content: OpaqueJsonDeserialized; }>; }>, local: boolean): void; private routeNonContainerSignal; /** * Flush the current batch of ops to the ordering service for sequencing * This method is not expected to be called in the middle of a batch. * @remarks If it throws (e.g. if the batch is too large to send), the container will be closed. * * @param resubmitInfo - If defined, indicates this is a resubmission of a batch with the given Batch info needed for resubmit. */ private flush; /** * {@inheritDoc @fluidframework/runtime-definitions#IContainerRuntimeBase.orderSequentially} */ orderSequentially(callback: () => T): T; private stageControls; /** * If true, the ContainerRuntime is not submitting any new ops to the ordering service. * Ops submitted to the ContainerRuntime while in Staging Mode will be queued in the PendingStateManager, * either to be discarded or committed later (via the Stage Controls returned from enterStagingMode). */ get inStagingMode(): boolean; /** * Enter Staging Mode, such that ops submitted to the ContainerRuntime will not be sent to the ordering service. * To exit Staging Mode, call either discardChanges or commitChanges on the Stage Controls returned from this method. * * @remarks * The `stagingModeChanged` event is emitted when staging mode is entered or exited via this method. * It is NOT emitted when staging mode is used internally (e.g. by `orderSequentially` for rollback support). * * @returns Controls for exiting Staging Mode. */ enterStagingMode: () => StageControlsInternal; /** * Internal implementation of enterStagingMode. * @param silent - When true, suppresses `stagingModeChanged` event emission. * Pass `true` when staging mode is used as an internal implementation detail (e.g. by * `orderSequentially` for rollback support) so that external listeners only observe * user-initiated staging mode transitions. Pass `false` for all public entry points. */ private readonly enterStagingModeCore; /** * Returns the aliased data store's entryPoint, given the alias. * @param alias - The alias for the data store. * @returns The data store's entry point ({@link @fluidframework/core-interfaces#IFluidHandle}) if it exists and is aliased. * Returns undefined if no data store has been assigned the given alias. */ getAliasedDataStoreEntryPoint(alias: string): Promise | undefined>; createDetachedDataStore(pkg: readonly string[], loadingGroupId?: string): IFluidDataStoreContextDetached; createDataStore(pkg: Readonly, loadingGroupId?: string): Promise; private shouldSendOps; private readonly _quorum; getQuorum(): IQuorumClients; private readonly _audience; getAudience(): IAudience; /** * When defined, this {@link @fluidframework/container-definitions#IAudience} * maintains member list using signals only. * Thus "write" members may be known earlier than quorum and avoid noise from * un-summarized quorum history. */ private readonly signalAudience?; /** * Returns true of container is dirty, i.e. there are some pending local changes that * either were not sent out to delta stream or were not yet acknowledged. */ get isDirty(): boolean; /** * Returns true if the container is dirty: not attached, or has pending user messages (ignores "non-dirtyable" ones though) */ private computeCurrentDirtyState; /** * Submits the signal to be sent to other clients. * @param type - Type of the signal. * @param content - Content of the signal. Should be a JSON serializable object or primitive. * @param targetClientId - When specified, the signal is only sent to the provided client id. * * @remarks * * The `targetClientId` parameter here is currently intended for internal testing purposes only. * Support for this option at container runtime is planned to be deprecated in the future. * */ submitSignal(type: string, content: unknown, targetClientId?: string): void; setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void; /** * Create a summary. Used when attaching or serializing a detached container. * * @param blobRedirectTable - A table passed during the attach process. While detached, blob upload is supported * using IDs generated locally. After attach, these IDs cannot be used, so this table maps the old local IDs to the * new storage IDs so requests can be redirected. * @param telemetryContext - summary data passed through the layers for telemetry purposes */ createSummary(blobRedirectTable?: Map, telemetryContext?: ITelemetryContext): ISummaryTree; readonly getAbsoluteUrl: (relativeUrl: string) => Promise; /** * Builds the Summary tree including all the channels and the container state. * * @remarks Unfortunately, this function is accessed in a non-typesafe way by a legacy first-party partner, * so until we can provide a proper API for their scenario, we need to ensure this function doesn't change. */ private summarizeInternal; /** * Returns a summary of the runtime at the current sequence number. */ summarize(options: { /** * True to generate the full tree with no handle reuse optimizations; defaults to false */ fullTree?: boolean; /** * True to track the state for this summary in the SummarizerNodes; defaults to true */ trackState?: boolean; /** * Logger to use for correlated summary events */ summaryLogger?: ITelemetryLoggerExt; /** * True to run garbage collection before summarizing; defaults to true */ runGC?: boolean; /** * True to generate full GC data */ fullGC?: boolean; /** * True to run GC sweep phase after the mark phase */ runSweep?: boolean; /** * Telemetry context to populate during summarization. */ telemetryContext?: TelemetryContext; }): Promise; private getGCDataInternal; /** * Generates and returns the GC data for this container. * @param fullGC - true to bypass optimizations and force full generation of GC data. * @see IGarbageCollectionRuntime.getGCData */ getGCData(fullGC?: boolean): Promise; /** * After GC has run, called to notify this container's nodes of routes that are used in it. * @param usedRoutes - The routes that are used in all nodes in this Container. * @see IGarbageCollectionRuntime.updateUsedRoutes */ updateUsedRoutes(usedRoutes: readonly string[]): void; /** * After GC has run and identified nodes that are sweep ready, this is called to delete the sweep ready nodes. * @param sweepReadyRoutes - The routes of nodes that are sweep ready and should be deleted. * @returns The routes of nodes that were deleted. */ deleteSweepReadyNodes(sweepReadyRoutes: readonly string[]): readonly string[]; /** * This is called to update objects that are tombstones. * * A Tombstoned object has been unreferenced long enough that GC knows it won't be referenced again. * Tombstoned objects are eventually deleted by GC. * * @param tombstonedRoutes - Data store and attachment blob routes that are tombstones in this Container. */ updateTombstonedRoutes(tombstonedRoutes: readonly string[]): void; /** * Returns a server generated referenced timestamp to be used to track unreferenced nodes by GC. */ getCurrentReferenceTimestampMs(): number | undefined; /** * Returns the type of the GC node. Currently, there are nodes that belong to the root ("/"), data stores or * blob manager. */ getNodeType(nodePath: string): GCNodeType; /** * Called by GC to retrieve the package path of the node with the given path. The node should belong to a * data store or an attachment blob. */ getGCNodePackagePath(nodePath: string): Promise; /** * From a given list of routes, separate and return routes that belong to blob manager and data stores. * @param routes - A list of routes that can belong to data stores or blob manager. * @returns Two route lists - One that contains routes for blob manager and another one that contains routes * for data stores. */ private getDataStoreAndBlobManagerRoutes; /** * Runs garbage collection and updates the reference / used state of the nodes in the container. * @returns the statistics of the garbage collection run; undefined if GC did not run. */ collectGarbage(options: { /** * Logger to use for logging GC events */ logger?: ITelemetryLoggerExt; /** * True to run GC sweep phase after the mark phase */ runSweep?: boolean; /** * True to generate full GC data */ fullGC?: boolean; }, telemetryContext?: ITelemetryContext): Promise; /** * Called when a new outbound route is added to another node. This is used by garbage collection to identify * all references added in the system. * @param fromPath - The absolute path of the node that added the reference. * @param toPath - The absolute path of the outbound node that is referenced. * @param messageTimestampMs - The timestamp of the message that added the reference. */ addedGCOutboundRoute(fromPath: string, toPath: string, messageTimestampMs?: number): void; /** * Generates the summary tree, uploads it to storage, and then submits the summarize op. * This is intended to be called by the summarizer, since it is the implementation of * ISummarizerInternalsProvider.submitSummary. * It takes care of state management at the container level, including pausing inbound * op processing, updating SummarizerNode state tracking, and garbage collection. * @param options - options controlling how the summary is generated or submitted */ submitSummary(options: ISubmitSummaryOptions): Promise; /** * This helper is called during summarization. If the container is dirty, it will return a failed summarize result * (IBaseSummarizeResult) unless this is the final summarize attempt, in which case the summary is allowed to * proceed to make progress in documents where there are consistently pending ops in the summarizer. * @param logger - The logger to be used for sending telemetry. * @param referenceSequenceNumber - The reference sequence number of the summary attempt. * @param minimumSequenceNumber - The minimum sequence number of the summary attempt. * @param finalAttempt - Whether this is the final summary attempt. * @param beforeSummaryGeneration - Whether this is called before summary generation or after. * @returns failed summarize result (IBaseSummarizeResult) if summary should be failed, undefined otherwise. */ private shouldFailSummaryOnPendingOps; private get pendingMessagesCount(); private hasPendingMessages; /** * Emit "dirty" or "saved" event based on the current dirty state of the document. * This must be called every time the states underlying the dirty state change. * * @privateRemarks It's helpful to think of this as an event handler registered * for hypothetical "changed" events for PendingStateManager, Outbox, and Container Attach machinery. * But those events don't exist so we manually call this wherever we know those changes happen. */ private updateDocumentDirtyState; submitMessage(containerRuntimeMessage: ContainerRuntimeDataStoreOpMessage | OutboundContainerRuntimeAttachMessage | ContainerRuntimeAliasMessage, localOpMetadata?: unknown): void; uploadBlob(blob: ArrayBufferLike, signal?: AbortSignal): Promise>; /** * 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 * This method provides access to the BlobManager's storage ID lookup functionality. * For blobs with pending payloads (localId exists but upload hasn't finished), this returns undefined. * Consumers should use the observability APIs on the handle to understand/wait for storage ID availability. * * Warning: the returned blob URL may expire and does not support permalinks. * This API is intended for temporary integration scenarios only. */ lookupTemporaryBlobStorageId(localId: string): string | undefined; private submit; private scheduleFlush; private submitSummaryMessage; /** * Throw an error if the runtime is closed. Methods that are expected to potentially * be called after dispose due to asynchrony should not call this. */ private verifyNotClosed; /** * Resubmits each message in the batch, and then flushes the outbox. * This typically happens when we reconnect and there are pending messages. * * @remarks * Attempting to resubmit a batch that has been successfully sequenced will not happen due to * checks in the ConnectionStateHandler (Loader layer) * * The only exception to this would be if the Container "forks" due to misuse of the "Offline Load" feature. * If the "Offline Load" feature is enabled, the batchId is included in the resubmitted messages, * for correlation to detect container forking. */ private reSubmitBatch; /** * Resubmit the given message as part of a squash rebase upon exiting Staging Mode. * How exactly to resubmit the message is up to the subsystem that submitted the op to begin with. */ private reSubmitWithSquashing; /** * Resubmit the given message which was previously submitted to the ContainerRuntime but not successfully * transmitted to the ordering service (e.g. due to a disconnect, or being in Staging Mode) * How to resubmit is up to the subsystem that submitted the op to begin with */ private reSubmit; /** * Rollback the given op which was only staged but not yet submitted. */ private rollbackStagedChange; /** * Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */ refreshLatestSummaryAck(options: IRefreshSummaryAckOptions): Promise; private readonly readAndParseBlob; /** * Fetches the latest snapshot from storage. If the fetched snapshot is same or newer than the one for which ack * was received, close this client. Fetching the snapshot will update the cache for this client so if it's * re-elected as summarizer, this will prevent any thrashing. * If the fetched snapshot is older than the one for which ack was received, ignore the ack and return. This can * happen in scenarios where the snapshot for the ack was lost in storage in scenarios like DB rollback, etc. */ private fetchLatestSnapshotAndMaybeClose; getPendingLocalState(props?: IGetPendingLocalStateProps): unknown; /** * ContainerRuntime knows about additional restrictions on when blob sharing can be resumed as compared * to BlobManager. In particular, it wants to avoid sharing blobs while in readonly state, and it also * wants to avoid sharing blobs before connection completes (otherwise it may cause the sharing to happen * before processing shared ops). * * This method can be called safely before those conditions are met. In the background, it will wait until * it is safe before initiating sharing. It will close the container on any error. */ sharePendingBlobs: () => void; summarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults; enqueueSummarize(options: IEnqueueSummarizeOptions): EnqueueSummarizeResult; private readonly lazyEventsForExtensions; private getJoinedStatus; private readonly submitExtensionSignal; acquireExtension(id: ContainerExtensionId, factory: ContainerExtensionFactory, ...useContext: TUseContext): T; getExtension(id: ContainerExtensionId, requirements: ContainerExtensionExpectations, ...useContext: TUseContext): T; private acquireExtensionInternal; private get groupedBatchingEnabled(); } export declare function isContainerMessageDirtyable({ type, contents, }: LocalContainerRuntimeMessage): boolean; //# sourceMappingURL=containerRuntime.d.ts.map