/*! * Copyright (c) Microsoft Corporation and contributors. All rights reserved. * Licensed under the MIT License. */ import { TypedEventEmitter } from "@fluid-internal/client-utils"; import type { IEventThisPlaceHolder, IFluidHandle } from "@fluidframework/core-interfaces"; import type { IFluidDataStoreRuntime, IChannelStorageService } from "@fluidframework/datastore-definitions/internal"; import { type ISequencedDocumentMessage } from "@fluidframework/driver-definitions/internal"; import type { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions/internal"; import type { IFluidSerializer } from "@fluidframework/shared-object-base/internal"; import { type TelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal"; import { type IMergeTreeTextHelper } from "./MergeTreeTextHelper.js"; import { type LocalReferencePosition, SlidingPreference } from "./localReference.js"; import { type IMergeTreeOptionsInternal } from "./mergeTree.js"; import type { IMergeTreeDeltaCallbackArgs, IMergeTreeDeltaOpArgs, IMergeTreeMaintenanceCallbackArgs } from "./mergeTreeDeltaCallback.js"; import { type CollaborationWindow, type ISegment, type ISegmentAction, type Marker, type ISegmentInternal } from "./mergeTreeNodes.js"; import { type IJSONSegment, type IMergeTreeAnnotateMsg, type IMergeTreeGroupMsg, type IMergeTreeInsertMsg, type IMergeTreeObliterateMsg, type IMergeTreeOp, type IMergeTreeRemoveMsg, type IRelativePosition, ReferenceType, type AdjustParams, type IMergeTreeAnnotateAdjustMsg, type IMergeTreeObliterateSidedMsg } from "./ops.js"; import type { PropertySet, MapLike } from "./properties.js"; import { type ReferencePosition } from "./referencePositions.js"; import { type InteriorSequencePlace } from "./sequencePlace.js"; /** * A range [start, end) * @internal */ export interface IIntegerRange { start: number; end: number; } /** * Emitted before this client's merge-tree normalizes its segments on reconnect, potentially * ordering them. Useful for DDS-like consumers built atop the merge-tree to compute any information * they need for rebasing their ops on reconnection. * @internal */ export interface IClientEvents { (event: "normalize", listener: (squash: boolean, target: IEventThisPlaceHolder) => void): void; (event: "delta", listener: (opArgs: IMergeTreeDeltaOpArgs, deltaArgs: IMergeTreeDeltaCallbackArgs, target: IEventThisPlaceHolder) => void): void; (event: "maintenance", listener: (args: IMergeTreeMaintenanceCallbackArgs, deltaArgs: IMergeTreeDeltaOpArgs | undefined, target: IEventThisPlaceHolder) => void): void; } /** * This class encapsulates a merge-tree, and provides a local client specific view over it and * the capability to modify it as the local client. Additionally it provides * binding for processing remote ops on the encapsulated merge tree, and projects local and remote events * caused by all modification to the underlying merge-tree. * * @internal */ export declare class Client extends TypedEventEmitter { readonly specToSegment: (spec: IJSONSegment) => ISegment; readonly logger: TelemetryLoggerExt; private readonly getMinInFlightRefSeq; longClientId: string | undefined; private readonly _mergeTree; private readonly clientNameToIds; private readonly shortClientIdMap; /** * @param specToSegment - Rehydrates a segment from its JSON representation * @param logger - Telemetry logger for diagnostics * @param options - Options for this client. See {@link IMergeTreeOptions} for details. * @param getMinInFlightRefSeq - Upon applying a message (see {@link Client.applyMsg}), client purges collab-window information which * is no longer necessary based on that message's minimum sequence number. * However, if the user of this client has in-flight messages which refer to positions in this Client, * they may wish to preserve additional merge information. * The effective minimum sequence number will be the minimum of the message's minimumSequenceNumber and the result of this function. * If this function returns undefined, the message's minimumSequenceNumber will be used. * * @privateRemarks * - Passing specToSegment would be unnecessary if Client were merged with SharedSegmentSequence * - AB#6866 tracks a more unified approach to collab window min seq handling. */ constructor(specToSegment: (spec: IJSONSegment) => ISegment, logger: TelemetryLoggerExt, options?: IMergeTreeOptionsInternal & PropertySet, getMinInFlightRefSeq?: () => number | undefined); get endOfTree(): ISegmentInternal; get startOfTree(): ISegmentInternal; /** * The merge tree maintains a queue of segment groups for each local operation. * These segment groups track segments modified by an operation. * This method peeks the tail of that queue, and returns the segments groups there. * It is used to get the segment group(s) for the previous operations. * @param count - The number segment groups to get peek from the tail of the queue. Default 1. */ peekPendingSegmentGroups(count?: number): unknown; /** * Annotates the markers with the provided properties * @param marker - The marker to annotate * @param props - The properties to annotate the marker with * @returns The annotate op if valid, otherwise undefined */ annotateMarker(marker: Marker, props: PropertySet): IMergeTreeAnnotateMsg | undefined; /** * Annotates the range with the provided properties * @param start - The inclusive start position of the range to annotate * @param end - The exclusive end position of the range to annotate * @param props - The properties to annotate the range with * @returns The annotate op if valid, otherwise undefined */ annotateRangeLocal(start: number, end: number, props: PropertySet): IMergeTreeAnnotateMsg | undefined; /** * adjusts a value */ annotateAdjustRangeLocal(start: number, end: number, adjust: MapLike): IMergeTreeAnnotateAdjustMsg; /** * Removes the range * * @param start - The inclusive start of the range to remove * @param end - The exclusive end of the range to remove */ removeRangeLocal(start: number, end: number): IMergeTreeRemoveMsg; /** * Obliterates the range. This is similar to removing the range, but also * includes any concurrently inserted content. * * @param start - The start of the range to obliterate. Inclusive is side is Before (default). * @param end - The end of the range to obliterate. Exclusive is side is After * (default is to be after the last included character, but number index is exclusive). */ obliterateRangeLocal(start: number | InteriorSequencePlace, end: number | InteriorSequencePlace): IMergeTreeObliterateMsg | IMergeTreeObliterateSidedMsg; /** * Create and insert a segment at the specified position. * @param pos - The position to insert the segment at * @param segment - The segment to insert */ insertSegmentLocal(pos: number, segment: ISegment): IMergeTreeInsertMsg | undefined; /** * Create and insert a segment at the specified reference position. * @param refPos - The reference position to insert the segment at * @param segment - The segment to insert */ insertAtReferencePositionLocal(refPos: ReferencePosition, segment: ISegment): IMergeTreeInsertMsg | undefined; walkSegments(handler: ISegmentAction, start: number | undefined, end: number | undefined, accum: TClientData, splitRange?: boolean, perspective?: Pick): void; walkSegments(handler: ISegmentAction, start?: number, end?: number, accum?: undefined, splitRange?: boolean, perspective?: Pick): void; protected walkAllSegments(action: (segment: ISegment, accum?: TClientData) => boolean, accum?: TClientData): boolean; /** * Serializes the data required for garbage collection. The IFluidHandles stored in all segments that haven't * been removed represent routes to other objects. We serialize the data in these segments using the passed in * serializer which keeps track of all serialized handles. */ serializeGCData(handle: IFluidHandle, handleCollectingSerializer: IFluidSerializer): void; getCollabWindow(): CollaborationWindow; /** * Returns the current position of a segment, and -1 if the segment * does not exist in this merge tree * @param segment - The segment to get the position of */ getPosition(segment: ISegment | undefined, localSeq?: number): number; /** * Creates a `LocalReferencePosition` on this client. If the refType does not include ReferenceType.Transient, * the returned reference will be added to the localRefs on the provided segment. * @param segment - Segment to add the local reference on * @param offset - Offset on the segment at which to place the local reference * @param refType - ReferenceType for the created local reference * @param properties - PropertySet to place on the created local reference * @param canSlideToEndpoint - Whether or not the created local reference can * slide onto one of the special endpoint segments denoting the position * before the start of or after the end of the tree */ createLocalReferencePosition(segment: ISegment | "start" | "end", offset: number | undefined, refType: ReferenceType, properties: PropertySet | undefined, slidingPreference?: SlidingPreference, canSlideToEndpoint?: boolean): LocalReferencePosition; /** * Removes a `LocalReferencePosition` from this client. */ removeLocalReferencePosition(lref: LocalReferencePosition): LocalReferencePosition | undefined; /** * Resolves a `ReferencePosition` into a character position using this client's perspective. * * Reference positions that point to a character that has been removed will * always return the position of the nearest non-removed character, regardless * of {@link ReferenceType}. To handle this case specifically, one may wish * to look at the segment returned by {@link ReferencePosition.getSegment}. */ localReferencePositionToPosition(lref: ReferencePosition): number; /** * Given a position specified relative to a marker id, lookup the marker * and convert the position to a character position. * @param relativePos - Id of marker (may be indirect) and whether position is before or after marker. */ posFromRelativePos(relativePos: IRelativePosition): number; getMarkerFromId(id: string): ISegment | undefined; /** * Revert an op */ rollback(op: unknown, localOpMetadata: unknown): void; private applyObliterateRangeOp; private getOperationPerspective; /** * Returns the operation stamp to apply for a change, minting a new one local one if necessary. */ private getOperationStamp; /** * Performs the remove based on the provided op * @param opArgs - The ops args for the op */ private applyRemoveRangeOp; /** * Performs the annotate based on the provided op * @param opArgs - The ops args for the op */ private applyAnnotateRangeOp; /** * Performs the insert based on the provided op * @param opArgs - The ops args for the op * @returns True if the insert was applied. False if it could not be. */ private applyInsertOp; /** * Returns a valid range for the op, or throws if the range is invalid * @param op - The op to generate the range for * @param clientArgs - The client args for the op * @throws LoggingError if the range is invalid */ private getValidSidedRange; /** * Returns a valid range for the op, or undefined * @param op - The op to generate the range for * @param clientArgs - The client args for the op */ private getValidOpRange; private ackPendingSegment; getOrAddShortClientId(longClientId: string): number; protected getShortClientId(longClientId: string): number; getLongClientId(shortClientId: number): string; addLongClientId(longClientId: string): void; private getOrAddShortClientIdFromMessage; /** * During reconnect, we must find the positions to pending segments * relative to other pending segments. This methods computes that * position relative to a localSeq. Pending segments above the localSeq * will be ignored. * * @param segment - The segment to find the position for * @param localSeq - The localSeq to find the position of the segment at */ findReconnectionPosition(segment: ISegment, localSeq: number): number; /** * Rebases a sided local reference to the best fitting position in the current tree. */ private rebaseSidedLocalReference; private computeNewObliterateEndpoints; private resetPendingDeltaToOps; private applyRemoteOp; applyStashedOp(op: IMergeTreeOp): void; applyMsg(msg: ISequencedDocumentMessage, local?: boolean): void; private updateSeqNumbers; /** * Resolves a remote client's position against the local sequence * and returns the remote client's position relative to the local * sequence * @param remoteClientPosition - The remote client's position to resolve * @param remoteClientRefSeq - The reference sequence number of the remote client * @param remoteClientId - The client id of the remote client */ resolveRemoteClientPosition(remoteClientPosition: number, remoteClientRefSeq: number, remoteClientId: string): number | undefined; private lastNormalization; private pendingRebase; private readonly cachedObliterateRebases; private squashInsertion; /** * Given a pending operation and segment group, regenerate the op, so it * can be resubmitted * @param resetOp - The op to reset * @param segmentGroup - The segment group associated with the op * @param squash - whether intermediate states should be squashed. See `IDeltaHandler.reSubmit`'s squash parameter * documentation for more details. */ regeneratePendingOp(resetOp: IMergeTreeOp, localOpMetadata: unknown, squash: boolean): IMergeTreeOp; createTextHelper(): IMergeTreeTextHelper; summarize(runtime: IFluidDataStoreRuntime, handle: IFluidHandle, serializer: IFluidSerializer, catchUpMsgs: ISequencedDocumentMessage[]): ISummaryTreeWithStats; load(runtime: IFluidDataStoreRuntime, storage: IChannelStorageService, serializer: IFluidSerializer): Promise<{ catchupOpsP: Promise; }>; localTransaction(groupOp: IMergeTreeGroupMsg): void; updateMinSeq(minSeq: number): void; getContainingSegment(pos: number, sequenceArgs?: Pick, localSeq?: number): { segment: T; offset: number; } | undefined; getPropertiesAtPosition(pos: number): PropertySet | undefined; getRangeExtentsOfPosition(pos: number): { posStart: number | undefined; posAfterEnd: number | undefined; }; getCurrentSeq(): number; getClientId(): number; getLength(): number; startOrUpdateCollaboration(longClientId: string | undefined, minSeq?: number, currentSeq?: number): void; /** * Searches a string for the nearest marker in either direction to a given start position. * The search will include the start position, so markers at the start position are valid * results of the search. Makes use of block-accelerated search functions for log(n) complexity. * * @param startPos - Position at which to start the search * @param markerLabel - Label of the marker to search for * @param forwards - Whether the desired marker comes before (false) or after (true) `startPos` */ searchForMarker(startPos: number, markerLabel: string, forwards?: boolean): Marker | undefined; } //# sourceMappingURL=client.d.ts.map