Launch Week Day 3: Introducing Organization Notifications in Socket.Learn More
Socket
Book a DemoSign in
Socket

@fluidframework/protocol-base

Package Overview
Dependencies
Maintainers
2
Versions
273
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fluidframework/protocol-base - npm Package Compare versions

Comparing version
5.0.0-256582
to
5.0.0-259221
+3
-3
dist/protocol.js

@@ -15,2 +15,5 @@ "use strict";

class ProtocolOpHandler {
get quorum() {
return this._quorum;
}
constructor(minimumSequenceNumber, sequenceNumber, members, proposals, values, sendProposal) {

@@ -21,5 +24,2 @@ this.minimumSequenceNumber = minimumSequenceNumber;

}
get quorum() {
return this._quorum;
}
get attributes() {

@@ -26,0 +26,0 @@ return {

@@ -1,1 +0,1 @@

{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tIDocumentAttributes,\n\tIClientJoin,\n\tICommittedProposal,\n\tIProcessMessageResult,\n\tIProposal,\n\tIQuorum,\n\tISequencedClient,\n\tISequencedDocumentMessage,\n\tISequencedDocumentSystemMessage,\n\tISequencedProposal,\n\tMessageType,\n} from \"@fluidframework/protocol-definitions\";\nimport { IQuorumSnapshot, Quorum } from \"./quorum\";\n\n/**\n * @alpha\n */\nexport interface IScribeProtocolState {\n\tsequenceNumber: number;\n\tminimumSequenceNumber: number;\n\tmembers: [string, ISequencedClient][];\n\tproposals: [number, ISequencedProposal, string[]][];\n\tvalues: [string, ICommittedProposal][];\n}\n\n/**\n * @alpha\n */\nexport interface IProtocolHandler {\n\treadonly quorum: IQuorum;\n\treadonly attributes: IDocumentAttributes;\n\n\tsetConnectionState(connected: boolean, clientId: string | undefined);\n\tsnapshot(): IQuorumSnapshot;\n\n\tclose(): void;\n\tprocessMessage(message: ISequencedDocumentMessage, local: boolean): IProcessMessageResult;\n\tgetProtocolState(): IScribeProtocolState;\n}\n\n/**\n * Handles protocol specific ops.\n * @internal\n */\nexport class ProtocolOpHandler implements IProtocolHandler {\n\tprivate readonly _quorum: Quorum;\n\tpublic get quorum(): Quorum {\n\t\treturn this._quorum;\n\t}\n\n\tconstructor(\n\t\tpublic minimumSequenceNumber: number,\n\t\tpublic sequenceNumber: number,\n\t\tmembers: [string, ISequencedClient][],\n\t\tproposals: [number, ISequencedProposal, string[]][],\n\t\tvalues: [string, ICommittedProposal][],\n\t\tsendProposal: (key: string, value: any) => number,\n\t) {\n\t\tthis._quorum = new Quorum(members, proposals, values, sendProposal);\n\t}\n\n\tpublic get attributes(): IDocumentAttributes {\n\t\treturn {\n\t\t\tminimumSequenceNumber: this.minimumSequenceNumber,\n\t\t\tsequenceNumber: this.sequenceNumber,\n\t\t};\n\t}\n\n\tsetConnectionState(connected: boolean, clientId: string | undefined) {\n\t\tthis._quorum.setConnectionState(connected, clientId);\n\t}\n\n\tsnapshot(): IQuorumSnapshot {\n\t\treturn this._quorum.snapshot();\n\t}\n\n\tpublic close() {\n\t\tthis._quorum.close();\n\t}\n\n\tpublic processMessage(\n\t\tmessage: ISequencedDocumentMessage,\n\t\tlocal: boolean,\n\t): IProcessMessageResult {\n\t\t// verify it's moving sequentially\n\t\tif (message.sequenceNumber !== this.sequenceNumber + 1) {\n\t\t\tthrow new Error(\n\t\t\t\t`Protocol state is not moving sequentially. ` +\n\t\t\t\t\t`Current is ${this.sequenceNumber}. Next is ${message.sequenceNumber}`,\n\t\t\t);\n\t\t}\n\n\t\t// Update tracked sequence numbers\n\t\tthis.sequenceNumber = message.sequenceNumber;\n\t\tthis.minimumSequenceNumber = message.minimumSequenceNumber;\n\n\t\tlet immediateNoOp = false;\n\n\t\tswitch (message.type) {\n\t\t\tcase MessageType.ClientJoin:\n\t\t\t\tconst systemJoinMessage = message as ISequencedDocumentSystemMessage;\n\t\t\t\tconst join = JSON.parse(systemJoinMessage.data) as IClientJoin;\n\t\t\t\tconst member: ISequencedClient = {\n\t\t\t\t\tclient: join.detail,\n\t\t\t\t\tsequenceNumber: systemJoinMessage.sequenceNumber,\n\t\t\t\t};\n\t\t\t\tthis._quorum.addMember(join.clientId, member);\n\t\t\t\tbreak;\n\n\t\t\tcase MessageType.ClientLeave:\n\t\t\t\tconst systemLeaveMessage = message as ISequencedDocumentSystemMessage;\n\t\t\t\tconst clientId = JSON.parse(systemLeaveMessage.data) as string;\n\t\t\t\tthis._quorum.removeMember(clientId);\n\t\t\t\tbreak;\n\n\t\t\tcase MessageType.Propose:\n\t\t\t\t// back-compat: ADO #1385: This should become unconditional eventually.\n\t\t\t\t// Can be done only after Container.processRemoteMessage() stops parsing content!\n\t\t\t\tif (typeof message.contents === \"string\") {\n\t\t\t\t\tmessage.contents = JSON.parse(message.contents);\n\t\t\t\t}\n\t\t\t\tconst proposal = message.contents as IProposal;\n\t\t\t\tthis._quorum.addProposal(\n\t\t\t\t\tproposal.key,\n\t\t\t\t\tproposal.value,\n\t\t\t\t\tmessage.sequenceNumber,\n\t\t\t\t\tlocal,\n\t\t\t\t\tmessage.clientSequenceNumber,\n\t\t\t\t);\n\n\t\t\t\t// On a quorum proposal, immediately send a response to expedite the approval.\n\t\t\t\timmediateNoOp = true;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t}\n\n\t\t// Notify the quorum of the MSN from the message. We rely on it to handle duplicate values but may\n\t\t// want to move that logic to this class.\n\t\tthis._quorum.updateMinimumSequenceNumber(message);\n\n\t\treturn { immediateNoOp };\n\t}\n\n\t/**\n\t * Gets the scribe protocol state\n\t * @param scrubUserData - whether to remove all user data from the quorum members. CAUTION: this will corrupt the quorum if used in a summary.\n\t */\n\tpublic getProtocolState(scrubUserData = false): IScribeProtocolState {\n\t\t// return a new object every time\n\t\t// this ensures future state changes will not affect outside callers\n\t\tconst snapshot = this._quorum.snapshot();\n\n\t\tif (scrubUserData) {\n\t\t\t// In place, remove any identifying client information\n\t\t\tsnapshot.members = snapshot.members.map(([id, sequencedClient]) => [\n\t\t\t\tid,\n\t\t\t\t{\n\t\t\t\t\t...sequencedClient,\n\t\t\t\t\tclient: {\n\t\t\t\t\t\t...sequencedClient.client,\n\t\t\t\t\t\tuser: { id: \"\" },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t]);\n\t\t}\n\n\t\treturn {\n\t\t\tsequenceNumber: this.sequenceNumber,\n\t\t\tminimumSequenceNumber: this.minimumSequenceNumber,\n\t\t\t...snapshot,\n\t\t};\n\t}\n}\n"]}
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tIDocumentAttributes,\n\tIClientJoin,\n\tICommittedProposal,\n\tIProcessMessageResult,\n\tIProposal,\n\tIQuorum,\n\tISequencedClient,\n\tISequencedDocumentMessage,\n\tISequencedDocumentSystemMessage,\n\tISequencedProposal,\n\tMessageType,\n} from \"@fluidframework/protocol-definitions\";\nimport { IQuorumSnapshot, Quorum } from \"./quorum\";\n\n/**\n * @alpha\n */\nexport interface IScribeProtocolState {\n\tsequenceNumber: number;\n\tminimumSequenceNumber: number;\n\tmembers: [string, ISequencedClient][];\n\tproposals: [number, ISequencedProposal, string[]][];\n\tvalues: [string, ICommittedProposal][];\n}\n\n/**\n * @alpha\n */\nexport interface IProtocolHandler {\n\treadonly quorum: IQuorum;\n\treadonly attributes: IDocumentAttributes;\n\n\tsetConnectionState(connected: boolean, clientId: string | undefined);\n\tsnapshot(): IQuorumSnapshot;\n\n\tclose(): void;\n\tprocessMessage(message: ISequencedDocumentMessage, local: boolean): IProcessMessageResult;\n\tgetProtocolState(): IScribeProtocolState;\n}\n\n/**\n * Handles protocol specific ops.\n * @internal\n */\nexport class ProtocolOpHandler implements IProtocolHandler {\n\tprivate readonly _quorum: Quorum;\n\tpublic get quorum(): Quorum {\n\t\treturn this._quorum;\n\t}\n\n\tconstructor(\n\t\tpublic minimumSequenceNumber: number,\n\t\tpublic sequenceNumber: number,\n\t\tmembers: [string, ISequencedClient][],\n\t\tproposals: [number, ISequencedProposal, string[]][],\n\t\tvalues: [string, ICommittedProposal][],\n\t\tsendProposal: (key: string, value: any) => number,\n\t) {\n\t\tthis._quorum = new Quorum(members, proposals, values, sendProposal);\n\t}\n\n\tpublic get attributes(): IDocumentAttributes {\n\t\treturn {\n\t\t\tminimumSequenceNumber: this.minimumSequenceNumber,\n\t\t\tsequenceNumber: this.sequenceNumber,\n\t\t};\n\t}\n\n\tsetConnectionState(connected: boolean, clientId: string | undefined) {\n\t\tthis._quorum.setConnectionState(connected, clientId);\n\t}\n\n\tsnapshot(): IQuorumSnapshot {\n\t\treturn this._quorum.snapshot();\n\t}\n\n\tpublic close() {\n\t\tthis._quorum.close();\n\t}\n\n\tpublic processMessage(\n\t\tmessage: ISequencedDocumentMessage,\n\t\tlocal: boolean,\n\t): IProcessMessageResult {\n\t\t// verify it's moving sequentially\n\t\tif (message.sequenceNumber !== this.sequenceNumber + 1) {\n\t\t\tthrow new Error(\n\t\t\t\t`Protocol state is not moving sequentially. ` +\n\t\t\t\t\t`Current is ${this.sequenceNumber}. Next is ${message.sequenceNumber}`,\n\t\t\t);\n\t\t}\n\n\t\t// Update tracked sequence numbers\n\t\tthis.sequenceNumber = message.sequenceNumber;\n\t\tthis.minimumSequenceNumber = message.minimumSequenceNumber;\n\n\t\tlet immediateNoOp = false;\n\n\t\tswitch (message.type) {\n\t\t\tcase MessageType.ClientJoin:\n\t\t\t\tconst systemJoinMessage = message as ISequencedDocumentSystemMessage;\n\t\t\t\tconst join = JSON.parse(systemJoinMessage.data) as IClientJoin;\n\t\t\t\tconst member: ISequencedClient = {\n\t\t\t\t\tclient: join.detail,\n\t\t\t\t\tsequenceNumber: systemJoinMessage.sequenceNumber,\n\t\t\t\t};\n\t\t\t\tthis._quorum.addMember(join.clientId, member);\n\t\t\t\tbreak;\n\n\t\t\tcase MessageType.ClientLeave:\n\t\t\t\tconst systemLeaveMessage = message as ISequencedDocumentSystemMessage;\n\t\t\t\tconst clientId = JSON.parse(systemLeaveMessage.data) as string;\n\t\t\t\tthis._quorum.removeMember(clientId);\n\t\t\t\tbreak;\n\n\t\t\tcase MessageType.Propose:\n\t\t\t\t// back-compat: ADO #1385: This should become unconditional eventually.\n\t\t\t\t// Can be done only after Container.processRemoteMessage() stops parsing content!\n\t\t\t\tif (typeof message.contents === \"string\") {\n\t\t\t\t\tmessage.contents = JSON.parse(message.contents);\n\t\t\t\t}\n\t\t\t\tconst proposal = message.contents as IProposal;\n\t\t\t\tthis._quorum.addProposal(\n\t\t\t\t\tproposal.key,\n\t\t\t\t\tproposal.value,\n\t\t\t\t\tmessage.sequenceNumber,\n\t\t\t\t\tlocal,\n\t\t\t\t\tmessage.clientSequenceNumber,\n\t\t\t\t);\n\n\t\t\t\t// On a quorum proposal, immediately send a response to expedite the approval.\n\t\t\t\timmediateNoOp = true;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t}\n\n\t\t// Notify the quorum of the MSN from the message. We rely on it to handle duplicate values but may\n\t\t// want to move that logic to this class.\n\t\tthis._quorum.updateMinimumSequenceNumber(message);\n\n\t\treturn { immediateNoOp };\n\t}\n\n\t/**\n\t * Gets the scribe protocol state\n\t * @param scrubUserData - whether to remove all user data from the quorum members. CAUTION: this will corrupt the quorum if used in a summary.\n\t */\n\tpublic getProtocolState(scrubUserData = false): IScribeProtocolState {\n\t\t// return a new object every time\n\t\t// this ensures future state changes will not affect outside callers\n\t\tconst snapshot = this._quorum.snapshot();\n\n\t\tif (scrubUserData) {\n\t\t\t// In place, remove any identifying client information\n\t\t\tsnapshot.members = snapshot.members.map(([id, sequencedClient]) => [\n\t\t\t\tid,\n\t\t\t\t{\n\t\t\t\t\t...sequencedClient,\n\t\t\t\t\tclient: {\n\t\t\t\t\t\t...sequencedClient.client,\n\t\t\t\t\t\tuser: { id: \"\" },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t]);\n\t\t}\n\n\t\treturn {\n\t\t\tsequenceNumber: this.sequenceNumber,\n\t\t\tminimumSequenceNumber: this.minimumSequenceNumber,\n\t\t\t...snapshot,\n\t\t};\n\t}\n}\n"]}

@@ -11,3 +11,3 @@ /*!

*/
export declare type QuorumClientsSnapshot = [string, ISequencedClient][];
export type QuorumClientsSnapshot = [string, ISequencedClient][];
/**

@@ -17,3 +17,3 @@ * Snapshot format for a QuorumProposals

*/
export declare type QuorumProposalsSnapshot = {
export type QuorumProposalsSnapshot = {
proposals: [number, ISequencedProposal, string[]][];

@@ -20,0 +20,0 @@ values: [string, ICommittedProposal][];

@@ -1,1 +0,1 @@

{"version":3,"file":"quorum.d.ts","sourceRoot":"","sources":["../src/quorum.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"quorum.d.ts","sourceRoot":"","sources":["../src/quorum.ts"],"names":[],"mappings":"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"}

@@ -26,2 +26,5 @@ "use strict";

class QuorumClients extends common_utils_1.TypedEventEmitter {
get disposed() {
return this.isDisposed;
}
constructor(snapshot) {

@@ -33,5 +36,2 @@ super();

}
get disposed() {
return this.isDisposed;
}
/**

@@ -90,2 +90,5 @@ * Snapshots the current state of the QuorumClients

class QuorumProposals extends common_utils_1.TypedEventEmitter {
get disposed() {
return this.isDisposed;
}
constructor(snapshot, sendProposal) {

@@ -107,5 +110,2 @@ super();

}
get disposed() {
return this.isDisposed;
}
/**

@@ -310,2 +310,5 @@ * Snapshots the current state of the QuorumProposals

class Quorum extends common_utils_1.TypedEventEmitter {
get disposed() {
return this.isDisposed;
}
constructor(members, proposals, values, sendProposal) {

@@ -329,5 +332,2 @@ super();

}
get disposed() {
return this.isDisposed;
}
close() {

@@ -334,0 +334,0 @@ this.removeAllListeners();

@@ -1,1 +0,1 @@

{"version":3,"file":"quorum.js","sourceRoot":"","sources":["../src/quorum.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { EventEmitter } from \"events\";\n\nimport { assert, TypedEventEmitter } from \"@fluidframework/common-utils\";\nimport {\n\tICommittedProposal,\n\tIQuorum,\n\tIQuorumClients,\n\tIQuorumProposals,\n\tISequencedClient,\n\tISequencedDocumentMessage,\n\tISequencedProposal,\n} from \"@fluidframework/protocol-definitions\";\n\n/**\n * Structure for tracking proposals that have been sequenced but not approved yet.\n */\nclass PendingProposal implements ISequencedProposal {\n\tconstructor(\n\t\tpublic readonly sequenceNumber: number,\n\t\tpublic readonly key: string,\n\t\tpublic readonly value: any,\n\t\tpublic readonly local: boolean,\n\t) {}\n}\n\n/**\n * Snapshot format for a QuorumClients\n * @alpha\n */\nexport type QuorumClientsSnapshot = [string, ISequencedClient][];\n\n/**\n * Snapshot format for a QuorumProposals\n * @alpha\n */\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport type QuorumProposalsSnapshot = {\n\tproposals: [number, ISequencedProposal, string[]][];\n\tvalues: [string, ICommittedProposal][];\n};\n\n/**\n * Snapshot format for a Quorum\n * @alpha\n */\nexport interface IQuorumSnapshot {\n\tmembers: QuorumClientsSnapshot;\n\tproposals: QuorumProposalsSnapshot[\"proposals\"];\n\tvalues: QuorumProposalsSnapshot[\"values\"];\n}\n\n/**\n * The QuorumClients is used to track members joining and leaving the collaboration session.\n * @internal\n */\nexport class QuorumClients\n\textends TypedEventEmitter<IQuorumClients[\"on\"]>\n\timplements IQuorumClients\n{\n\tprivate readonly members: Map<string, ISequencedClient>;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed() {\n\t\treturn this.isDisposed;\n\t}\n\n\t/**\n\t * Cached snapshot state, to avoid unnecessary deep clones on repeated snapshot calls.\n\t * Cleared immediately (set to undefined) when the cache becomes invalid.\n\t */\n\tprivate snapshotCache: QuorumClientsSnapshot | undefined;\n\n\tconstructor(snapshot: QuorumClientsSnapshot) {\n\t\tsuper();\n\n\t\tthis.members = new Map(snapshot);\n\t\tthis.snapshotCache = snapshot;\n\t}\n\n\t/**\n\t * Snapshots the current state of the QuorumClients\n\t * @returns a snapshot of the clients in the quorum\n\t */\n\tpublic snapshot(): QuorumClientsSnapshot {\n\t\tthis.snapshotCache ??= Array.from(this.members);\n\n\t\treturn this.snapshotCache;\n\t}\n\n\t/**\n\t * Adds a new client to the quorum\n\t */\n\tpublic addMember(clientId: string, details: ISequencedClient) {\n\t\tassert(!!clientId, 0x46f /* clientId has to be non-empty string */);\n\t\tassert(!this.members.has(clientId), 0x1ce /* clientId not found */);\n\t\tthis.members.set(clientId, details);\n\t\tthis.emit(\"addMember\", clientId, details);\n\n\t\t// clear the cache\n\t\tthis.snapshotCache = undefined;\n\t}\n\n\t/**\n\t * Removes a client from the quorum\n\t */\n\tpublic removeMember(clientId: string) {\n\t\tassert(!!clientId, 0x470 /* clientId has to be non-empty string */);\n\t\tassert(this.members.has(clientId), 0x1cf /* clientId not found */);\n\t\tthis.members.delete(clientId);\n\t\tthis.emit(\"removeMember\", clientId);\n\n\t\t// clear the cache\n\t\tthis.snapshotCache = undefined;\n\t}\n\n\t/**\n\t * Retrieves all the members in the quorum\n\t */\n\tpublic getMembers(): Map<string, ISequencedClient> {\n\t\treturn new Map(this.members);\n\t}\n\n\t/**\n\t * Retrieves a specific member of the quorum\n\t */\n\tpublic getMember(clientId: string): ISequencedClient | undefined {\n\t\treturn this.members.get(clientId);\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.isDisposed = true;\n\t}\n}\n\n/**\n * The QuorumProposals holds a key/value store. Proposed values become finalized in the store once all connected\n * clients have seen the proposal.\n * @internal\n */\nexport class QuorumProposals\n\textends TypedEventEmitter<IQuorumProposals[\"on\"]>\n\timplements IQuorumProposals\n{\n\tprivate readonly proposals: Map<number, PendingProposal>;\n\tprivate readonly values: Map<string, ICommittedProposal>;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed() {\n\t\treturn this.isDisposed;\n\t}\n\n\t// Event emitter for changes to the environment that affect pending proposal promises.\n\tprivate readonly stateEvents = new EventEmitter();\n\n\t/**\n\t * Cached snapshot state, to avoid unnecessary deep clones on repeated snapshot calls.\n\t * Cleared immediately (set to undefined) when the cache becomes invalid.\n\t */\n\tprivate proposalsSnapshotCache: QuorumProposalsSnapshot[\"proposals\"] | undefined;\n\tprivate valuesSnapshotCache: QuorumProposalsSnapshot[\"values\"] | undefined;\n\n\tconstructor(\n\t\tsnapshot: QuorumProposalsSnapshot,\n\t\tprivate readonly sendProposal: (key: string, value: any) => number,\n\t) {\n\t\tsuper();\n\n\t\tthis.proposals = new Map(\n\t\t\tsnapshot.proposals.map(([, proposal]) => {\n\t\t\t\treturn [\n\t\t\t\t\tproposal.sequenceNumber,\n\t\t\t\t\tnew PendingProposal(\n\t\t\t\t\t\tproposal.sequenceNumber,\n\t\t\t\t\t\tproposal.key,\n\t\t\t\t\t\tproposal.value,\n\t\t\t\t\t\tfalse, // local\n\t\t\t\t\t),\n\t\t\t\t] as [number, PendingProposal];\n\t\t\t}),\n\t\t);\n\t\tthis.values = new Map(snapshot.values);\n\t\tthis.proposalsSnapshotCache = snapshot.proposals;\n\t\tthis.valuesSnapshotCache = snapshot.values;\n\t}\n\n\t/**\n\t * Snapshots the current state of the QuorumProposals\n\t * @returns arrays of proposals and values\n\t */\n\tpublic snapshot(): QuorumProposalsSnapshot {\n\t\tthis.proposalsSnapshotCache ??= Array.from(this.proposals).map(\n\t\t\t([sequenceNumber, proposal]) => [\n\t\t\t\tsequenceNumber,\n\t\t\t\t{ sequenceNumber, key: proposal.key, value: proposal.value },\n\t\t\t\t[], // rejections, which has been removed\n\t\t\t],\n\t\t);\n\t\tthis.valuesSnapshotCache ??= Array.from(this.values);\n\n\t\treturn {\n\t\t\tproposals: this.proposalsSnapshotCache,\n\t\t\tvalues: this.valuesSnapshotCache,\n\t\t};\n\t}\n\n\t/**\n\t * Returns whether the quorum has achieved a consensus for the given key.\n\t */\n\tpublic has(key: string): boolean {\n\t\treturn this.values.has(key);\n\t}\n\n\t/**\n\t * Returns the consensus value for the given key\n\t */\n\tpublic get(key: string): any {\n\t\treturn this.values.get(key)?.value;\n\t}\n\n\t/**\n\t * Returns additional data about the approved consensus value\n\t * @deprecated Removed in recent protocol-definitions. Use get() instead.\n\t */\n\tpublic getApprovalData(key: string): ICommittedProposal | undefined {\n\t\treturn this.values.get(key);\n\t}\n\n\t/**\n\t * Proposes a new value. Returns a promise that will either:\n\t * - Resolve when the proposal is accepted\n\t * - Reject if the proposal fails to send or if the QuorumProposals is disposed\n\t */\n\tpublic async propose(key: string, value: any): Promise<void> {\n\t\tconst clientSequenceNumber = this.sendProposal(key, value);\n\t\tif (clientSequenceNumber < 0) {\n\t\t\tthis.emit(\"error\", { eventName: \"ProposalInDisconnectedState\", key });\n\t\t\tthrow new Error(\"Can't propose in disconnected state\");\n\t\t}\n\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\t// The sequence number that our proposal was assigned and went pending.\n\t\t\t// If undefined, then it's not sequenced yet.\n\t\t\tlet thisProposalSequenceNumber: number | undefined;\n\n\t\t\t// A proposal goes through two phases before this promise resolves:\n\t\t\t// 1. Sequencing - waiting for the proposal to be ack'd by the server.\n\t\t\t// 2. Approval - waiting for the proposal to be approved by connected clients.\n\t\t\tconst localProposalSequencedHandler = (\n\t\t\t\tsequencedCSN: number,\n\t\t\t\tsequenceNumber: number,\n\t\t\t) => {\n\t\t\t\tif (sequencedCSN === clientSequenceNumber) {\n\t\t\t\t\tthisProposalSequenceNumber = sequenceNumber;\n\t\t\t\t\tthis.stateEvents.off(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\t\t\tthis.stateEvents.off(\"disconnected\", disconnectedHandler);\n\t\t\t\t\tthis.stateEvents.on(\"localProposalApproved\", localProposalApprovedHandler);\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst localProposalApprovedHandler = (sequenceNumber: number) => {\n\t\t\t\t// Proposals can be uniquely identified by the sequenceNumber they were assigned.\n\t\t\t\tif (sequenceNumber === thisProposalSequenceNumber) {\n\t\t\t\t\tresolve();\n\t\t\t\t\tremoveListeners();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// There are two error flows we consider: disconnect and disposal.\n\t\t\t// If we get disconnected before the proposal is sequenced, it has one of two possible futures:\n\t\t\t// 1. We reconnect and see the proposal was sequenced in the meantime.\n\t\t\t// -> The promise can still resolve, once it is approved.\n\t\t\t// 2. We reconnect and see the proposal was not sequenced in the meantime, so it will never sequence.\n\t\t\t// -> The promise rejects.\n\t\t\tconst disconnectedHandler = () => {\n\t\t\t\t// If we haven't seen the ack by the time we disconnect, we hope to see it by the time we reconnect.\n\t\t\t\tif (thisProposalSequenceNumber === undefined) {\n\t\t\t\t\tthis.stateEvents.once(\"connected\", () => {\n\t\t\t\t\t\t// If we don't see the ack by the time reconnection finishes, it failed to send.\n\t\t\t\t\t\tif (thisProposalSequenceNumber === undefined) {\n\t\t\t\t\t\t\treject(\n\t\t\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t\t\t\"Client disconnected without successfully sending proposal\",\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tremoveListeners();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t};\n\t\t\t// If the QuorumProposals is disposed of, we assume something catastrophic has happened\n\t\t\t// All outstanding proposals are considered rejected.\n\t\t\tconst disposedHandler = () => {\n\t\t\t\treject(new Error(\"QuorumProposals was disposed\"));\n\t\t\t\tremoveListeners();\n\t\t\t};\n\t\t\t// Convenience function to clean up our listeners.\n\t\t\tconst removeListeners = () => {\n\t\t\t\tthis.stateEvents.off(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\t\tthis.stateEvents.off(\"localProposalApproved\", localProposalApprovedHandler);\n\t\t\t\tthis.stateEvents.off(\"disconnected\", disconnectedHandler);\n\t\t\t\tthis.stateEvents.off(\"disposed\", disposedHandler);\n\t\t\t};\n\t\t\tthis.stateEvents.on(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\tthis.stateEvents.on(\"disconnected\", disconnectedHandler);\n\t\t\tthis.stateEvents.on(\"disposed\", disposedHandler);\n\t\t});\n\t}\n\n\t/**\n\t * Begins tracking a new proposal\n\t */\n\tpublic addProposal(\n\t\tkey: string,\n\t\tvalue: any,\n\t\tsequenceNumber: number,\n\t\tlocal: boolean,\n\t\tclientSequenceNumber: number,\n\t) {\n\t\tassert(!this.proposals.has(sequenceNumber), 0x1d0 /* sequenceNumber not found */);\n\n\t\tconst proposal = new PendingProposal(sequenceNumber, key, value, local);\n\t\tthis.proposals.set(sequenceNumber, proposal);\n\n\t\t// Legacy event, from rejection support. May still have some use for clients to learn that a proposal is\n\t\t// likely to be approved soon.\n\t\tthis.emit(\"addProposal\", proposal);\n\n\t\tif (local) {\n\t\t\tthis.stateEvents.emit(\"localProposalSequenced\", clientSequenceNumber, sequenceNumber);\n\t\t}\n\n\t\t// clear the proposal cache\n\t\tthis.proposalsSnapshotCache = undefined;\n\t}\n\n\t/**\n\t * Updates the minimum sequence number. If the MSN advances past the sequence number for any proposal then it\n\t * becomes an approved value.\n\t */\n\tpublic updateMinimumSequenceNumber(message: ISequencedDocumentMessage): void {\n\t\tconst msn = message.minimumSequenceNumber;\n\n\t\t// Accept proposals proposals whose sequenceNumber is <= the minimumSequenceNumber\n\n\t\t// Return a sorted list of approved proposals. We sort so that we apply them in their sequence number order\n\t\t// TODO this can be optimized if necessary to avoid the linear search+sort\n\t\tconst completed: PendingProposal[] = [];\n\t\tfor (const [sequenceNumber, proposal] of this.proposals) {\n\t\t\tif (sequenceNumber <= msn) {\n\t\t\t\tcompleted.push(proposal);\n\t\t\t}\n\t\t}\n\t\tcompleted.sort((a, b) => a.sequenceNumber - b.sequenceNumber);\n\n\t\tfor (const proposal of completed) {\n\t\t\tconst committedProposal: ICommittedProposal = {\n\t\t\t\tapprovalSequenceNumber: message.sequenceNumber,\n\t\t\t\t// No longer used. We still stamp a -1 for compat with older versions of the quorum.\n\t\t\t\t// Can be removed after 0.1035 and higher is ubiquitous.\n\t\t\t\tcommitSequenceNumber: -1,\n\t\t\t\tkey: proposal.key,\n\t\t\t\tsequenceNumber: proposal.sequenceNumber,\n\t\t\t\tvalue: proposal.value,\n\t\t\t};\n\n\t\t\tthis.values.set(committedProposal.key, committedProposal);\n\n\t\t\t// clear the values cache\n\t\t\tthis.valuesSnapshotCache = undefined;\n\n\t\t\t// check if there are multiple proposals with matching keys\n\t\t\tlet proposalSettled = false;\n\t\t\tlet proposalKeySeen = false;\n\t\t\tfor (const [, p] of this.proposals) {\n\t\t\t\tif (p.key === committedProposal.key) {\n\t\t\t\t\tif (!proposalKeySeen) {\n\t\t\t\t\t\t// set proposalSettled to true if the proposal key match is unique thus far\n\t\t\t\t\t\tproposalSettled = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// set proposalSettled to false if matching proposal key is not unique\n\t\t\t\t\t\tproposalSettled = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tproposalKeySeen = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.emit(\n\t\t\t\t\"approveProposal\",\n\t\t\t\tcommittedProposal.sequenceNumber,\n\t\t\t\tcommittedProposal.key,\n\t\t\t\tcommittedProposal.value,\n\t\t\t\tcommittedProposal.approvalSequenceNumber,\n\t\t\t);\n\n\t\t\t// emit approveProposalComplete when all pending proposals are processed\n\t\t\tif (proposalSettled) {\n\t\t\t\tthis.emit(\n\t\t\t\t\t\"approveProposalComplete\",\n\t\t\t\t\tcommittedProposal.sequenceNumber,\n\t\t\t\t\tcommittedProposal.key,\n\t\t\t\t\tcommittedProposal.value,\n\t\t\t\t\tcommittedProposal.approvalSequenceNumber,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.proposals.delete(proposal.sequenceNumber);\n\n\t\t\t// clear the proposals cache\n\t\t\tthis.proposalsSnapshotCache = undefined;\n\t\t\tif (proposal.local) {\n\t\t\t\tthis.stateEvents.emit(\"localProposalApproved\", proposal.sequenceNumber);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic setConnectionState(connected: boolean) {\n\t\tif (connected) {\n\t\t\tthis.stateEvents.emit(\"connected\");\n\t\t} else {\n\t\t\tthis.stateEvents.emit(\"disconnected\");\n\t\t}\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.isDisposed = true;\n\t\tthis.stateEvents.emit(\"disposed\");\n\t}\n}\n\n/**\n * A quorum represents all clients currently within the collaboration window. As well as the values\n * they have agreed upon and any pending proposals.\n * @internal\n */\nexport class Quorum extends TypedEventEmitter<IQuorum[\"on\"]> implements IQuorum {\n\tprivate readonly quorumClients: QuorumClients;\n\tprivate readonly quorumProposals: QuorumProposals;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed() {\n\t\treturn this.isDisposed;\n\t}\n\n\tconstructor(\n\t\tmembers: QuorumClientsSnapshot,\n\t\tproposals: QuorumProposalsSnapshot[\"proposals\"],\n\t\tvalues: QuorumProposalsSnapshot[\"values\"],\n\t\tsendProposal: (key: string, value: any) => number,\n\t) {\n\t\tsuper();\n\n\t\tthis.quorumClients = new QuorumClients(members);\n\t\tthis.quorumClients.on(\"addMember\", (clientId: string, details: ISequencedClient) => {\n\t\t\tthis.emit(\"addMember\", clientId, details);\n\t\t});\n\t\tthis.quorumClients.on(\"removeMember\", (clientId: string) => {\n\t\t\tthis.emit(\"removeMember\", clientId);\n\t\t});\n\n\t\tthis.quorumProposals = new QuorumProposals({ proposals, values }, sendProposal);\n\t\tthis.quorumProposals.on(\"addProposal\", (proposal: ISequencedProposal) => {\n\t\t\tthis.emit(\"addProposal\", proposal);\n\t\t});\n\t\tthis.quorumProposals.on(\n\t\t\t\"approveProposal\",\n\t\t\t(sequenceNumber: number, key: string, value: any, approvalSequenceNumber: number) => {\n\t\t\t\tthis.emit(\"approveProposal\", sequenceNumber, key, value, approvalSequenceNumber);\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic close() {\n\t\tthis.removeAllListeners();\n\t}\n\n\t/**\n\t * Snapshots the entire quorum\n\t * @returns a quorum snapshot\n\t */\n\tpublic snapshot(): IQuorumSnapshot {\n\t\tconst members = this.quorumClients.snapshot();\n\t\tconst { proposals, values } = this.quorumProposals.snapshot();\n\t\treturn {\n\t\t\tmembers,\n\t\t\tproposals,\n\t\t\tvalues,\n\t\t};\n\t}\n\n\t/**\n\t * Returns whether the quorum has achieved a consensus for the given key.\n\t */\n\tpublic has(key: string): boolean {\n\t\treturn this.quorumProposals.has(key);\n\t}\n\n\t/**\n\t * Returns the consensus value for the given key\n\t */\n\tpublic get(key: string): any {\n\t\treturn this.quorumProposals.get(key);\n\t}\n\n\t/**\n\t * Returns additional data about the approved consensus value\n\t * @deprecated Removed in recent protocol-definitions. Use get() instead.\n\t */\n\tpublic getApprovalData(key: string): ICommittedProposal | undefined {\n\t\treturn this.quorumProposals.getApprovalData(key);\n\t}\n\n\t/**\n\t * Adds a new client to the quorum\n\t */\n\tpublic addMember(clientId: string, details: ISequencedClient) {\n\t\tthis.quorumClients.addMember(clientId, details);\n\t}\n\n\t/**\n\t * Removes a client from the quorum\n\t */\n\tpublic removeMember(clientId: string) {\n\t\tthis.quorumClients.removeMember(clientId);\n\t}\n\n\t/**\n\t * Retrieves all the members in the quorum\n\t */\n\tpublic getMembers(): Map<string, ISequencedClient> {\n\t\treturn this.quorumClients.getMembers();\n\t}\n\n\t/**\n\t * Retrieves a specific member of the quorum\n\t */\n\tpublic getMember(clientId: string): ISequencedClient | undefined {\n\t\treturn this.quorumClients.getMember(clientId);\n\t}\n\n\t/**\n\t * Proposes a new value. Returns a promise that will resolve when the proposal is either accepted, or reject if\n\t * the proposal fails to send.\n\t */\n\tpublic async propose(key: string, value: any): Promise<void> {\n\t\treturn this.quorumProposals.propose(key, value);\n\t}\n\n\t/**\n\t * Begins tracking a new proposal\n\t */\n\tpublic addProposal(\n\t\tkey: string,\n\t\tvalue: any,\n\t\tsequenceNumber: number,\n\t\tlocal: boolean,\n\t\tclientSequenceNumber: number,\n\t) {\n\t\treturn this.quorumProposals.addProposal(\n\t\t\tkey,\n\t\t\tvalue,\n\t\t\tsequenceNumber,\n\t\t\tlocal,\n\t\t\tclientSequenceNumber,\n\t\t);\n\t}\n\n\t/**\n\t * Updates the minimum sequence number. If the MSN advances past the sequence number for any proposal then it\n\t * becomes an approved value.\n\t */\n\tpublic updateMinimumSequenceNumber(message: ISequencedDocumentMessage): void {\n\t\tthis.quorumProposals.updateMinimumSequenceNumber(message);\n\t}\n\n\tpublic setConnectionState(connected: boolean, clientId?: string) {\n\t\tthis.quorumProposals.setConnectionState(connected);\n\t}\n\n\tpublic dispose(): void {\n\t\tthrow new Error(\"Not implemented.\");\n\t\tthis.isDisposed = true;\n\t}\n}\n"]}
{"version":3,"file":"quorum.js","sourceRoot":"","sources":["../src/quorum.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,mCAAsC;AAEtC,+DAAyE;AAWzE;;GAEG;AACH,MAAM,eAAe;IACpB,YACiB,cAAsB,EACtB,GAAW,EACX,KAAU,EACV,KAAc;QAHd,mBAAc,GAAd,cAAc,CAAQ;QACtB,QAAG,GAAH,GAAG,CAAQ;QACX,UAAK,GAAL,KAAK,CAAK;QACV,UAAK,GAAL,KAAK,CAAS;IAC5B,CAAC;CACJ;AA4BD;;;GAGG;AACH,MAAa,aACZ,SAAQ,gCAAuC;IAK/C,IAAW,QAAQ;QAClB,OAAO,IAAI,CAAC,UAAU,CAAC;IACxB,CAAC;IAQD,YAAY,QAA+B;QAC1C,KAAK,EAAE,CAAC;QAZD,eAAU,GAAY,KAAK,CAAC;QAcnC,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACI,QAAQ;QACd,IAAI,CAAC,aAAa,KAAlB,IAAI,CAAC,aAAa,GAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAC;QAEhD,OAAO,IAAI,CAAC,aAAa,CAAC;IAC3B,CAAC;IAED;;OAEG;IACI,SAAS,CAAC,QAAgB,EAAE,OAAyB;QAC3D,IAAA,qBAAM,EAAC,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,yCAAyC,CAAC,CAAC;QACpE,IAAA,qBAAM,EAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACpE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAE1C,kBAAkB;QAClB,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;IAChC,CAAC;IAED;;OAEG;IACI,YAAY,CAAC,QAAgB;QACnC,IAAA,qBAAM,EAAC,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,yCAAyC,CAAC,CAAC;QACpE,IAAA,qBAAM,EAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACnE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;QAEpC,kBAAkB;QAClB,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;IAChC,CAAC;IAED;;OAEG;IACI,UAAU;QAChB,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED;;OAEG;IACI,SAAS,CAAC,QAAgB;QAChC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;IAEM,OAAO;QACb,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;IACxB,CAAC;CACD;AA5ED,sCA4EC;AAED;;;;GAIG;AACH,MAAa,eACZ,SAAQ,gCAAyC;IAMjD,IAAW,QAAQ;QAClB,OAAO,IAAI,CAAC,UAAU,CAAC;IACxB,CAAC;IAYD,YACC,QAAiC,EAChB,YAAiD;QAElE,KAAK,EAAE,CAAC;QAFS,iBAAY,GAAZ,YAAY,CAAqC;QAjB3D,eAAU,GAAY,KAAK,CAAC;QAKpC,sFAAsF;QACrE,gBAAW,GAAG,IAAI,qBAAY,EAAE,CAAC;QAejD,IAAI,CAAC,SAAS,GAAG,IAAI,GAAG,CACvB,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,EAAE;YACvC,OAAO;gBACN,QAAQ,CAAC,cAAc;gBACvB,IAAI,eAAe,CAClB,QAAQ,CAAC,cAAc,EACvB,QAAQ,CAAC,GAAG,EACZ,QAAQ,CAAC,KAAK,EACd,KAAK,CACL;aAC4B,CAAC;QAChC,CAAC,CAAC,CACF,CAAC;QACF,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,sBAAsB,GAAG,QAAQ,CAAC,SAAS,CAAC;QACjD,IAAI,CAAC,mBAAmB,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC5C,CAAC;IAED;;;OAGG;IACI,QAAQ;QACd,IAAI,CAAC,sBAAsB,KAA3B,IAAI,CAAC,sBAAsB,GAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAC7D,CAAC,CAAC,cAAc,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC;YAC/B,cAAc;YACd,EAAE,cAAc,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE;YAC5D,EAAE,EAAE,qCAAqC;SACzC,CACD,EAAC;QACF,IAAI,CAAC,mBAAmB,KAAxB,IAAI,CAAC,mBAAmB,GAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAC;QAErD,OAAO;YACN,SAAS,EAAE,IAAI,CAAC,sBAAsB;YACtC,MAAM,EAAE,IAAI,CAAC,mBAAmB;SAChC,CAAC;IACH,CAAC;IAED;;OAEG;IACI,GAAG,CAAC,GAAW;QACrB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED;;OAEG;IACI,GAAG,CAAC,GAAW;QACrB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;IACpC,CAAC;IAED;;;OAGG;IACI,eAAe,CAAC,GAAW;QACjC,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,OAAO,CAAC,GAAW,EAAE,KAAU;QAC3C,MAAM,oBAAoB,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC3D,IAAI,oBAAoB,GAAG,CAAC,EAAE;YAC7B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,6BAA6B,EAAE,GAAG,EAAE,CAAC,CAAC;YACtE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;SACvD;QAED,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC5C,uEAAuE;YACvE,6CAA6C;YAC7C,IAAI,0BAA8C,CAAC;YAEnD,mEAAmE;YACnE,sEAAsE;YACtE,8EAA8E;YAC9E,MAAM,6BAA6B,GAAG,CACrC,YAAoB,EACpB,cAAsB,EACrB,EAAE;gBACH,IAAI,YAAY,KAAK,oBAAoB,EAAE;oBAC1C,0BAA0B,GAAG,cAAc,CAAC;oBAC5C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,wBAAwB,EAAE,6BAA6B,CAAC,CAAC;oBAC9E,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;oBAC1D,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,uBAAuB,EAAE,4BAA4B,CAAC,CAAC;iBAC3E;YACF,CAAC,CAAC;YACF,MAAM,4BAA4B,GAAG,CAAC,cAAsB,EAAE,EAAE;gBAC/D,iFAAiF;gBACjF,IAAI,cAAc,KAAK,0BAA0B,EAAE;oBAClD,OAAO,EAAE,CAAC;oBACV,eAAe,EAAE,CAAC;iBAClB;YACF,CAAC,CAAC;YAEF,mEAAmE;YACnE,+FAA+F;YAC/F,sEAAsE;YACtE,4DAA4D;YAC5D,qGAAqG;YACrG,6BAA6B;YAC7B,MAAM,mBAAmB,GAAG,GAAG,EAAE;gBAChC,oGAAoG;gBACpG,IAAI,0BAA0B,KAAK,SAAS,EAAE;oBAC7C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;wBACvC,gFAAgF;wBAChF,IAAI,0BAA0B,KAAK,SAAS,EAAE;4BAC7C,MAAM,CACL,IAAI,KAAK,CACR,2DAA2D,CAC3D,CACD,CAAC;4BACF,eAAe,EAAE,CAAC;yBAClB;oBACF,CAAC,CAAC,CAAC;iBACH;YACF,CAAC,CAAC;YACF,uFAAuF;YACvF,qDAAqD;YACrD,MAAM,eAAe,GAAG,GAAG,EAAE;gBAC5B,MAAM,CAAC,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC,CAAC;gBAClD,eAAe,EAAE,CAAC;YACnB,CAAC,CAAC;YACF,kDAAkD;YAClD,MAAM,eAAe,GAAG,GAAG,EAAE;gBAC5B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,wBAAwB,EAAE,6BAA6B,CAAC,CAAC;gBAC9E,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,uBAAuB,EAAE,4BAA4B,CAAC,CAAC;gBAC5E,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;gBAC1D,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;YACnD,CAAC,CAAC;YACF,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,wBAAwB,EAAE,6BAA6B,CAAC,CAAC;YAC7E,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;YACzD,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;OAEG;IACI,WAAW,CACjB,GAAW,EACX,KAAU,EACV,cAAsB,EACtB,KAAc,EACd,oBAA4B;QAE5B,IAAA,qBAAM,EAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAElF,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,cAAc,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QACxE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;QAE7C,yGAAyG;QACzG,8BAA8B;QAC9B,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QAEnC,IAAI,KAAK,EAAE;YACV,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,wBAAwB,EAAE,oBAAoB,EAAE,cAAc,CAAC,CAAC;SACtF;QAED,2BAA2B;QAC3B,IAAI,CAAC,sBAAsB,GAAG,SAAS,CAAC;IACzC,CAAC;IAED;;;OAGG;IACI,2BAA2B,CAAC,OAAkC;QACpE,MAAM,GAAG,GAAG,OAAO,CAAC,qBAAqB,CAAC;QAE1C,kFAAkF;QAElF,2GAA2G;QAC3G,0EAA0E;QAC1E,MAAM,SAAS,GAAsB,EAAE,CAAC;QACxC,KAAK,MAAM,CAAC,cAAc,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE;YACxD,IAAI,cAAc,IAAI,GAAG,EAAE;gBAC1B,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;aACzB;SACD;QACD,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC,cAAc,CAAC,CAAC;QAE9D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;YACjC,MAAM,iBAAiB,GAAuB;gBAC7C,sBAAsB,EAAE,OAAO,CAAC,cAAc;gBAC9C,qFAAqF;gBACrF,wDAAwD;gBACxD,oBAAoB,EAAE,CAAC,CAAC;gBACxB,GAAG,EAAE,QAAQ,CAAC,GAAG;gBACjB,cAAc,EAAE,QAAQ,CAAC,cAAc;gBACvC,KAAK,EAAE,QAAQ,CAAC,KAAK;aACrB,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;YAE1D,yBAAyB;YACzB,IAAI,CAAC,mBAAmB,GAAG,SAAS,CAAC;YAErC,2DAA2D;YAC3D,IAAI,eAAe,GAAG,KAAK,CAAC;YAC5B,IAAI,eAAe,GAAG,KAAK,CAAC;YAC5B,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE;gBACnC,IAAI,CAAC,CAAC,GAAG,KAAK,iBAAiB,CAAC,GAAG,EAAE;oBACpC,IAAI,CAAC,eAAe,EAAE;wBACrB,2EAA2E;wBAC3E,eAAe,GAAG,IAAI,CAAC;qBACvB;yBAAM;wBACN,sEAAsE;wBACtE,eAAe,GAAG,KAAK,CAAC;wBACxB,MAAM;qBACN;oBACD,eAAe,GAAG,IAAI,CAAC;iBACvB;aACD;YAED,IAAI,CAAC,IAAI,CACR,iBAAiB,EACjB,iBAAiB,CAAC,cAAc,EAChC,iBAAiB,CAAC,GAAG,EACrB,iBAAiB,CAAC,KAAK,EACvB,iBAAiB,CAAC,sBAAsB,CACxC,CAAC;YAEF,wEAAwE;YACxE,IAAI,eAAe,EAAE;gBACpB,IAAI,CAAC,IAAI,CACR,yBAAyB,EACzB,iBAAiB,CAAC,cAAc,EAChC,iBAAiB,CAAC,GAAG,EACrB,iBAAiB,CAAC,KAAK,EACvB,iBAAiB,CAAC,sBAAsB,CACxC,CAAC;aACF;YAED,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;YAE/C,4BAA4B;YAC5B,IAAI,CAAC,sBAAsB,GAAG,SAAS,CAAC;YACxC,IAAI,QAAQ,CAAC,KAAK,EAAE;gBACnB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,uBAAuB,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;aACxE;SACD;IACF,CAAC;IAEM,kBAAkB,CAAC,SAAkB;QAC3C,IAAI,SAAS,EAAE;YACd,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;SACnC;aAAM;YACN,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;SACtC;IACF,CAAC;IAEM,OAAO;QACb,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACnC,CAAC;CACD;AA/RD,0CA+RC;AAED;;;;GAIG;AACH,MAAa,MAAO,SAAQ,gCAAgC;IAI3D,IAAW,QAAQ;QAClB,OAAO,IAAI,CAAC,UAAU,CAAC;IACxB,CAAC;IAED,YACC,OAA8B,EAC9B,SAA+C,EAC/C,MAAyC,EACzC,YAAiD;QAEjD,KAAK,EAAE,CAAC;QAXD,eAAU,GAAY,KAAK,CAAC;QAanC,IAAI,CAAC,aAAa,GAAG,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,QAAgB,EAAE,OAAyB,EAAE,EAAE;YAClF,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,QAAgB,EAAE,EAAE;YAC1D,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,eAAe,GAAG,IAAI,eAAe,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,YAAY,CAAC,CAAC;QAChF,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,aAAa,EAAE,CAAC,QAA4B,EAAE,EAAE;YACvE,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,eAAe,CAAC,EAAE,CACtB,iBAAiB,EACjB,CAAC,cAAsB,EAAE,GAAW,EAAE,KAAU,EAAE,sBAA8B,EAAE,EAAE;YACnF,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,cAAc,EAAE,GAAG,EAAE,KAAK,EAAE,sBAAsB,CAAC,CAAC;QAClF,CAAC,CACD,CAAC;IACH,CAAC;IAEM,KAAK;QACX,IAAI,CAAC,kBAAkB,EAAE,CAAC;IAC3B,CAAC;IAED;;;OAGG;IACI,QAAQ;QACd,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC;QAC9C,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,CAAC;QAC9D,OAAO;YACN,OAAO;YACP,SAAS;YACT,MAAM;SACN,CAAC;IACH,CAAC;IAED;;OAEG;IACI,GAAG,CAAC,GAAW;QACrB,OAAO,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC;IAED;;OAEG;IACI,GAAG,CAAC,GAAW;QACrB,OAAO,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC;IAED;;;OAGG;IACI,eAAe,CAAC,GAAW;QACjC,OAAO,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IAClD,CAAC;IAED;;OAEG;IACI,SAAS,CAAC,QAAgB,EAAE,OAAyB;QAC3D,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IAED;;OAEG;IACI,YAAY,CAAC,QAAgB;QACnC,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED;;OAEG;IACI,UAAU;QAChB,OAAO,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC;IACxC,CAAC;IAED;;OAEG;IACI,SAAS,CAAC,QAAgB;QAChC,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,OAAO,CAAC,GAAW,EAAE,KAAU;QAC3C,OAAO,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACjD,CAAC;IAED;;OAEG;IACI,WAAW,CACjB,GAAW,EACX,KAAU,EACV,cAAsB,EACtB,KAAc,EACd,oBAA4B;QAE5B,OAAO,IAAI,CAAC,eAAe,CAAC,WAAW,CACtC,GAAG,EACH,KAAK,EACL,cAAc,EACd,KAAK,EACL,oBAAoB,CACpB,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,2BAA2B,CAAC,OAAkC;QACpE,IAAI,CAAC,eAAe,CAAC,2BAA2B,CAAC,OAAO,CAAC,CAAC;IAC3D,CAAC;IAEM,kBAAkB,CAAC,SAAkB,EAAE,QAAiB;QAC9D,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;IAEM,OAAO;QACb,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACpC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;IACxB,CAAC;CACD;AAnJD,wBAmJC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { EventEmitter } from \"events\";\n\nimport { assert, TypedEventEmitter } from \"@fluidframework/common-utils\";\nimport {\n\tICommittedProposal,\n\tIQuorum,\n\tIQuorumClients,\n\tIQuorumProposals,\n\tISequencedClient,\n\tISequencedDocumentMessage,\n\tISequencedProposal,\n} from \"@fluidframework/protocol-definitions\";\n\n/**\n * Structure for tracking proposals that have been sequenced but not approved yet.\n */\nclass PendingProposal implements ISequencedProposal {\n\tconstructor(\n\t\tpublic readonly sequenceNumber: number,\n\t\tpublic readonly key: string,\n\t\tpublic readonly value: any,\n\t\tpublic readonly local: boolean,\n\t) {}\n}\n\n/**\n * Snapshot format for a QuorumClients\n * @alpha\n */\nexport type QuorumClientsSnapshot = [string, ISequencedClient][];\n\n/**\n * Snapshot format for a QuorumProposals\n * @alpha\n */\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport type QuorumProposalsSnapshot = {\n\tproposals: [number, ISequencedProposal, string[]][];\n\tvalues: [string, ICommittedProposal][];\n};\n\n/**\n * Snapshot format for a Quorum\n * @alpha\n */\nexport interface IQuorumSnapshot {\n\tmembers: QuorumClientsSnapshot;\n\tproposals: QuorumProposalsSnapshot[\"proposals\"];\n\tvalues: QuorumProposalsSnapshot[\"values\"];\n}\n\n/**\n * The QuorumClients is used to track members joining and leaving the collaboration session.\n * @internal\n */\nexport class QuorumClients\n\textends TypedEventEmitter<IQuorumClients[\"on\"]>\n\timplements IQuorumClients\n{\n\tprivate readonly members: Map<string, ISequencedClient>;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed() {\n\t\treturn this.isDisposed;\n\t}\n\n\t/**\n\t * Cached snapshot state, to avoid unnecessary deep clones on repeated snapshot calls.\n\t * Cleared immediately (set to undefined) when the cache becomes invalid.\n\t */\n\tprivate snapshotCache: QuorumClientsSnapshot | undefined;\n\n\tconstructor(snapshot: QuorumClientsSnapshot) {\n\t\tsuper();\n\n\t\tthis.members = new Map(snapshot);\n\t\tthis.snapshotCache = snapshot;\n\t}\n\n\t/**\n\t * Snapshots the current state of the QuorumClients\n\t * @returns a snapshot of the clients in the quorum\n\t */\n\tpublic snapshot(): QuorumClientsSnapshot {\n\t\tthis.snapshotCache ??= Array.from(this.members);\n\n\t\treturn this.snapshotCache;\n\t}\n\n\t/**\n\t * Adds a new client to the quorum\n\t */\n\tpublic addMember(clientId: string, details: ISequencedClient) {\n\t\tassert(!!clientId, 0x46f /* clientId has to be non-empty string */);\n\t\tassert(!this.members.has(clientId), 0x1ce /* clientId not found */);\n\t\tthis.members.set(clientId, details);\n\t\tthis.emit(\"addMember\", clientId, details);\n\n\t\t// clear the cache\n\t\tthis.snapshotCache = undefined;\n\t}\n\n\t/**\n\t * Removes a client from the quorum\n\t */\n\tpublic removeMember(clientId: string) {\n\t\tassert(!!clientId, 0x470 /* clientId has to be non-empty string */);\n\t\tassert(this.members.has(clientId), 0x1cf /* clientId not found */);\n\t\tthis.members.delete(clientId);\n\t\tthis.emit(\"removeMember\", clientId);\n\n\t\t// clear the cache\n\t\tthis.snapshotCache = undefined;\n\t}\n\n\t/**\n\t * Retrieves all the members in the quorum\n\t */\n\tpublic getMembers(): Map<string, ISequencedClient> {\n\t\treturn new Map(this.members);\n\t}\n\n\t/**\n\t * Retrieves a specific member of the quorum\n\t */\n\tpublic getMember(clientId: string): ISequencedClient | undefined {\n\t\treturn this.members.get(clientId);\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.isDisposed = true;\n\t}\n}\n\n/**\n * The QuorumProposals holds a key/value store. Proposed values become finalized in the store once all connected\n * clients have seen the proposal.\n * @internal\n */\nexport class QuorumProposals\n\textends TypedEventEmitter<IQuorumProposals[\"on\"]>\n\timplements IQuorumProposals\n{\n\tprivate readonly proposals: Map<number, PendingProposal>;\n\tprivate readonly values: Map<string, ICommittedProposal>;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed() {\n\t\treturn this.isDisposed;\n\t}\n\n\t// Event emitter for changes to the environment that affect pending proposal promises.\n\tprivate readonly stateEvents = new EventEmitter();\n\n\t/**\n\t * Cached snapshot state, to avoid unnecessary deep clones on repeated snapshot calls.\n\t * Cleared immediately (set to undefined) when the cache becomes invalid.\n\t */\n\tprivate proposalsSnapshotCache: QuorumProposalsSnapshot[\"proposals\"] | undefined;\n\tprivate valuesSnapshotCache: QuorumProposalsSnapshot[\"values\"] | undefined;\n\n\tconstructor(\n\t\tsnapshot: QuorumProposalsSnapshot,\n\t\tprivate readonly sendProposal: (key: string, value: any) => number,\n\t) {\n\t\tsuper();\n\n\t\tthis.proposals = new Map(\n\t\t\tsnapshot.proposals.map(([, proposal]) => {\n\t\t\t\treturn [\n\t\t\t\t\tproposal.sequenceNumber,\n\t\t\t\t\tnew PendingProposal(\n\t\t\t\t\t\tproposal.sequenceNumber,\n\t\t\t\t\t\tproposal.key,\n\t\t\t\t\t\tproposal.value,\n\t\t\t\t\t\tfalse, // local\n\t\t\t\t\t),\n\t\t\t\t] as [number, PendingProposal];\n\t\t\t}),\n\t\t);\n\t\tthis.values = new Map(snapshot.values);\n\t\tthis.proposalsSnapshotCache = snapshot.proposals;\n\t\tthis.valuesSnapshotCache = snapshot.values;\n\t}\n\n\t/**\n\t * Snapshots the current state of the QuorumProposals\n\t * @returns arrays of proposals and values\n\t */\n\tpublic snapshot(): QuorumProposalsSnapshot {\n\t\tthis.proposalsSnapshotCache ??= Array.from(this.proposals).map(\n\t\t\t([sequenceNumber, proposal]) => [\n\t\t\t\tsequenceNumber,\n\t\t\t\t{ sequenceNumber, key: proposal.key, value: proposal.value },\n\t\t\t\t[], // rejections, which has been removed\n\t\t\t],\n\t\t);\n\t\tthis.valuesSnapshotCache ??= Array.from(this.values);\n\n\t\treturn {\n\t\t\tproposals: this.proposalsSnapshotCache,\n\t\t\tvalues: this.valuesSnapshotCache,\n\t\t};\n\t}\n\n\t/**\n\t * Returns whether the quorum has achieved a consensus for the given key.\n\t */\n\tpublic has(key: string): boolean {\n\t\treturn this.values.has(key);\n\t}\n\n\t/**\n\t * Returns the consensus value for the given key\n\t */\n\tpublic get(key: string): any {\n\t\treturn this.values.get(key)?.value;\n\t}\n\n\t/**\n\t * Returns additional data about the approved consensus value\n\t * @deprecated Removed in recent protocol-definitions. Use get() instead.\n\t */\n\tpublic getApprovalData(key: string): ICommittedProposal | undefined {\n\t\treturn this.values.get(key);\n\t}\n\n\t/**\n\t * Proposes a new value. Returns a promise that will either:\n\t * - Resolve when the proposal is accepted\n\t * - Reject if the proposal fails to send or if the QuorumProposals is disposed\n\t */\n\tpublic async propose(key: string, value: any): Promise<void> {\n\t\tconst clientSequenceNumber = this.sendProposal(key, value);\n\t\tif (clientSequenceNumber < 0) {\n\t\t\tthis.emit(\"error\", { eventName: \"ProposalInDisconnectedState\", key });\n\t\t\tthrow new Error(\"Can't propose in disconnected state\");\n\t\t}\n\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\t// The sequence number that our proposal was assigned and went pending.\n\t\t\t// If undefined, then it's not sequenced yet.\n\t\t\tlet thisProposalSequenceNumber: number | undefined;\n\n\t\t\t// A proposal goes through two phases before this promise resolves:\n\t\t\t// 1. Sequencing - waiting for the proposal to be ack'd by the server.\n\t\t\t// 2. Approval - waiting for the proposal to be approved by connected clients.\n\t\t\tconst localProposalSequencedHandler = (\n\t\t\t\tsequencedCSN: number,\n\t\t\t\tsequenceNumber: number,\n\t\t\t) => {\n\t\t\t\tif (sequencedCSN === clientSequenceNumber) {\n\t\t\t\t\tthisProposalSequenceNumber = sequenceNumber;\n\t\t\t\t\tthis.stateEvents.off(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\t\t\tthis.stateEvents.off(\"disconnected\", disconnectedHandler);\n\t\t\t\t\tthis.stateEvents.on(\"localProposalApproved\", localProposalApprovedHandler);\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst localProposalApprovedHandler = (sequenceNumber: number) => {\n\t\t\t\t// Proposals can be uniquely identified by the sequenceNumber they were assigned.\n\t\t\t\tif (sequenceNumber === thisProposalSequenceNumber) {\n\t\t\t\t\tresolve();\n\t\t\t\t\tremoveListeners();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// There are two error flows we consider: disconnect and disposal.\n\t\t\t// If we get disconnected before the proposal is sequenced, it has one of two possible futures:\n\t\t\t// 1. We reconnect and see the proposal was sequenced in the meantime.\n\t\t\t// -> The promise can still resolve, once it is approved.\n\t\t\t// 2. We reconnect and see the proposal was not sequenced in the meantime, so it will never sequence.\n\t\t\t// -> The promise rejects.\n\t\t\tconst disconnectedHandler = () => {\n\t\t\t\t// If we haven't seen the ack by the time we disconnect, we hope to see it by the time we reconnect.\n\t\t\t\tif (thisProposalSequenceNumber === undefined) {\n\t\t\t\t\tthis.stateEvents.once(\"connected\", () => {\n\t\t\t\t\t\t// If we don't see the ack by the time reconnection finishes, it failed to send.\n\t\t\t\t\t\tif (thisProposalSequenceNumber === undefined) {\n\t\t\t\t\t\t\treject(\n\t\t\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t\t\t\"Client disconnected without successfully sending proposal\",\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tremoveListeners();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t};\n\t\t\t// If the QuorumProposals is disposed of, we assume something catastrophic has happened\n\t\t\t// All outstanding proposals are considered rejected.\n\t\t\tconst disposedHandler = () => {\n\t\t\t\treject(new Error(\"QuorumProposals was disposed\"));\n\t\t\t\tremoveListeners();\n\t\t\t};\n\t\t\t// Convenience function to clean up our listeners.\n\t\t\tconst removeListeners = () => {\n\t\t\t\tthis.stateEvents.off(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\t\tthis.stateEvents.off(\"localProposalApproved\", localProposalApprovedHandler);\n\t\t\t\tthis.stateEvents.off(\"disconnected\", disconnectedHandler);\n\t\t\t\tthis.stateEvents.off(\"disposed\", disposedHandler);\n\t\t\t};\n\t\t\tthis.stateEvents.on(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\tthis.stateEvents.on(\"disconnected\", disconnectedHandler);\n\t\t\tthis.stateEvents.on(\"disposed\", disposedHandler);\n\t\t});\n\t}\n\n\t/**\n\t * Begins tracking a new proposal\n\t */\n\tpublic addProposal(\n\t\tkey: string,\n\t\tvalue: any,\n\t\tsequenceNumber: number,\n\t\tlocal: boolean,\n\t\tclientSequenceNumber: number,\n\t) {\n\t\tassert(!this.proposals.has(sequenceNumber), 0x1d0 /* sequenceNumber not found */);\n\n\t\tconst proposal = new PendingProposal(sequenceNumber, key, value, local);\n\t\tthis.proposals.set(sequenceNumber, proposal);\n\n\t\t// Legacy event, from rejection support. May still have some use for clients to learn that a proposal is\n\t\t// likely to be approved soon.\n\t\tthis.emit(\"addProposal\", proposal);\n\n\t\tif (local) {\n\t\t\tthis.stateEvents.emit(\"localProposalSequenced\", clientSequenceNumber, sequenceNumber);\n\t\t}\n\n\t\t// clear the proposal cache\n\t\tthis.proposalsSnapshotCache = undefined;\n\t}\n\n\t/**\n\t * Updates the minimum sequence number. If the MSN advances past the sequence number for any proposal then it\n\t * becomes an approved value.\n\t */\n\tpublic updateMinimumSequenceNumber(message: ISequencedDocumentMessage): void {\n\t\tconst msn = message.minimumSequenceNumber;\n\n\t\t// Accept proposals proposals whose sequenceNumber is <= the minimumSequenceNumber\n\n\t\t// Return a sorted list of approved proposals. We sort so that we apply them in their sequence number order\n\t\t// TODO this can be optimized if necessary to avoid the linear search+sort\n\t\tconst completed: PendingProposal[] = [];\n\t\tfor (const [sequenceNumber, proposal] of this.proposals) {\n\t\t\tif (sequenceNumber <= msn) {\n\t\t\t\tcompleted.push(proposal);\n\t\t\t}\n\t\t}\n\t\tcompleted.sort((a, b) => a.sequenceNumber - b.sequenceNumber);\n\n\t\tfor (const proposal of completed) {\n\t\t\tconst committedProposal: ICommittedProposal = {\n\t\t\t\tapprovalSequenceNumber: message.sequenceNumber,\n\t\t\t\t// No longer used. We still stamp a -1 for compat with older versions of the quorum.\n\t\t\t\t// Can be removed after 0.1035 and higher is ubiquitous.\n\t\t\t\tcommitSequenceNumber: -1,\n\t\t\t\tkey: proposal.key,\n\t\t\t\tsequenceNumber: proposal.sequenceNumber,\n\t\t\t\tvalue: proposal.value,\n\t\t\t};\n\n\t\t\tthis.values.set(committedProposal.key, committedProposal);\n\n\t\t\t// clear the values cache\n\t\t\tthis.valuesSnapshotCache = undefined;\n\n\t\t\t// check if there are multiple proposals with matching keys\n\t\t\tlet proposalSettled = false;\n\t\t\tlet proposalKeySeen = false;\n\t\t\tfor (const [, p] of this.proposals) {\n\t\t\t\tif (p.key === committedProposal.key) {\n\t\t\t\t\tif (!proposalKeySeen) {\n\t\t\t\t\t\t// set proposalSettled to true if the proposal key match is unique thus far\n\t\t\t\t\t\tproposalSettled = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// set proposalSettled to false if matching proposal key is not unique\n\t\t\t\t\t\tproposalSettled = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tproposalKeySeen = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.emit(\n\t\t\t\t\"approveProposal\",\n\t\t\t\tcommittedProposal.sequenceNumber,\n\t\t\t\tcommittedProposal.key,\n\t\t\t\tcommittedProposal.value,\n\t\t\t\tcommittedProposal.approvalSequenceNumber,\n\t\t\t);\n\n\t\t\t// emit approveProposalComplete when all pending proposals are processed\n\t\t\tif (proposalSettled) {\n\t\t\t\tthis.emit(\n\t\t\t\t\t\"approveProposalComplete\",\n\t\t\t\t\tcommittedProposal.sequenceNumber,\n\t\t\t\t\tcommittedProposal.key,\n\t\t\t\t\tcommittedProposal.value,\n\t\t\t\t\tcommittedProposal.approvalSequenceNumber,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.proposals.delete(proposal.sequenceNumber);\n\n\t\t\t// clear the proposals cache\n\t\t\tthis.proposalsSnapshotCache = undefined;\n\t\t\tif (proposal.local) {\n\t\t\t\tthis.stateEvents.emit(\"localProposalApproved\", proposal.sequenceNumber);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic setConnectionState(connected: boolean) {\n\t\tif (connected) {\n\t\t\tthis.stateEvents.emit(\"connected\");\n\t\t} else {\n\t\t\tthis.stateEvents.emit(\"disconnected\");\n\t\t}\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.isDisposed = true;\n\t\tthis.stateEvents.emit(\"disposed\");\n\t}\n}\n\n/**\n * A quorum represents all clients currently within the collaboration window. As well as the values\n * they have agreed upon and any pending proposals.\n * @internal\n */\nexport class Quorum extends TypedEventEmitter<IQuorum[\"on\"]> implements IQuorum {\n\tprivate readonly quorumClients: QuorumClients;\n\tprivate readonly quorumProposals: QuorumProposals;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed() {\n\t\treturn this.isDisposed;\n\t}\n\n\tconstructor(\n\t\tmembers: QuorumClientsSnapshot,\n\t\tproposals: QuorumProposalsSnapshot[\"proposals\"],\n\t\tvalues: QuorumProposalsSnapshot[\"values\"],\n\t\tsendProposal: (key: string, value: any) => number,\n\t) {\n\t\tsuper();\n\n\t\tthis.quorumClients = new QuorumClients(members);\n\t\tthis.quorumClients.on(\"addMember\", (clientId: string, details: ISequencedClient) => {\n\t\t\tthis.emit(\"addMember\", clientId, details);\n\t\t});\n\t\tthis.quorumClients.on(\"removeMember\", (clientId: string) => {\n\t\t\tthis.emit(\"removeMember\", clientId);\n\t\t});\n\n\t\tthis.quorumProposals = new QuorumProposals({ proposals, values }, sendProposal);\n\t\tthis.quorumProposals.on(\"addProposal\", (proposal: ISequencedProposal) => {\n\t\t\tthis.emit(\"addProposal\", proposal);\n\t\t});\n\t\tthis.quorumProposals.on(\n\t\t\t\"approveProposal\",\n\t\t\t(sequenceNumber: number, key: string, value: any, approvalSequenceNumber: number) => {\n\t\t\t\tthis.emit(\"approveProposal\", sequenceNumber, key, value, approvalSequenceNumber);\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic close() {\n\t\tthis.removeAllListeners();\n\t}\n\n\t/**\n\t * Snapshots the entire quorum\n\t * @returns a quorum snapshot\n\t */\n\tpublic snapshot(): IQuorumSnapshot {\n\t\tconst members = this.quorumClients.snapshot();\n\t\tconst { proposals, values } = this.quorumProposals.snapshot();\n\t\treturn {\n\t\t\tmembers,\n\t\t\tproposals,\n\t\t\tvalues,\n\t\t};\n\t}\n\n\t/**\n\t * Returns whether the quorum has achieved a consensus for the given key.\n\t */\n\tpublic has(key: string): boolean {\n\t\treturn this.quorumProposals.has(key);\n\t}\n\n\t/**\n\t * Returns the consensus value for the given key\n\t */\n\tpublic get(key: string): any {\n\t\treturn this.quorumProposals.get(key);\n\t}\n\n\t/**\n\t * Returns additional data about the approved consensus value\n\t * @deprecated Removed in recent protocol-definitions. Use get() instead.\n\t */\n\tpublic getApprovalData(key: string): ICommittedProposal | undefined {\n\t\treturn this.quorumProposals.getApprovalData(key);\n\t}\n\n\t/**\n\t * Adds a new client to the quorum\n\t */\n\tpublic addMember(clientId: string, details: ISequencedClient) {\n\t\tthis.quorumClients.addMember(clientId, details);\n\t}\n\n\t/**\n\t * Removes a client from the quorum\n\t */\n\tpublic removeMember(clientId: string) {\n\t\tthis.quorumClients.removeMember(clientId);\n\t}\n\n\t/**\n\t * Retrieves all the members in the quorum\n\t */\n\tpublic getMembers(): Map<string, ISequencedClient> {\n\t\treturn this.quorumClients.getMembers();\n\t}\n\n\t/**\n\t * Retrieves a specific member of the quorum\n\t */\n\tpublic getMember(clientId: string): ISequencedClient | undefined {\n\t\treturn this.quorumClients.getMember(clientId);\n\t}\n\n\t/**\n\t * Proposes a new value. Returns a promise that will resolve when the proposal is either accepted, or reject if\n\t * the proposal fails to send.\n\t */\n\tpublic async propose(key: string, value: any): Promise<void> {\n\t\treturn this.quorumProposals.propose(key, value);\n\t}\n\n\t/**\n\t * Begins tracking a new proposal\n\t */\n\tpublic addProposal(\n\t\tkey: string,\n\t\tvalue: any,\n\t\tsequenceNumber: number,\n\t\tlocal: boolean,\n\t\tclientSequenceNumber: number,\n\t) {\n\t\treturn this.quorumProposals.addProposal(\n\t\t\tkey,\n\t\t\tvalue,\n\t\t\tsequenceNumber,\n\t\t\tlocal,\n\t\t\tclientSequenceNumber,\n\t\t);\n\t}\n\n\t/**\n\t * Updates the minimum sequence number. If the MSN advances past the sequence number for any proposal then it\n\t * becomes an approved value.\n\t */\n\tpublic updateMinimumSequenceNumber(message: ISequencedDocumentMessage): void {\n\t\tthis.quorumProposals.updateMinimumSequenceNumber(message);\n\t}\n\n\tpublic setConnectionState(connected: boolean, clientId?: string) {\n\t\tthis.quorumProposals.setConnectionState(connected);\n\t}\n\n\tpublic dispose(): void {\n\t\tthrow new Error(\"Not implemented.\");\n\t\tthis.isDisposed = true;\n\t}\n}\n"]}

@@ -12,2 +12,5 @@ /*!

export class ProtocolOpHandler {
get quorum() {
return this._quorum;
}
constructor(minimumSequenceNumber, sequenceNumber, members, proposals, values, sendProposal) {

@@ -18,5 +21,2 @@ this.minimumSequenceNumber = minimumSequenceNumber;

}
get quorum() {
return this._quorum;
}
get attributes() {

@@ -23,0 +23,0 @@ return {

@@ -1,1 +0,1 @@

{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tIDocumentAttributes,\n\tIClientJoin,\n\tICommittedProposal,\n\tIProcessMessageResult,\n\tIProposal,\n\tIQuorum,\n\tISequencedClient,\n\tISequencedDocumentMessage,\n\tISequencedDocumentSystemMessage,\n\tISequencedProposal,\n\tMessageType,\n} from \"@fluidframework/protocol-definitions\";\nimport { IQuorumSnapshot, Quorum } from \"./quorum\";\n\n/**\n * @alpha\n */\nexport interface IScribeProtocolState {\n\tsequenceNumber: number;\n\tminimumSequenceNumber: number;\n\tmembers: [string, ISequencedClient][];\n\tproposals: [number, ISequencedProposal, string[]][];\n\tvalues: [string, ICommittedProposal][];\n}\n\n/**\n * @alpha\n */\nexport interface IProtocolHandler {\n\treadonly quorum: IQuorum;\n\treadonly attributes: IDocumentAttributes;\n\n\tsetConnectionState(connected: boolean, clientId: string | undefined);\n\tsnapshot(): IQuorumSnapshot;\n\n\tclose(): void;\n\tprocessMessage(message: ISequencedDocumentMessage, local: boolean): IProcessMessageResult;\n\tgetProtocolState(): IScribeProtocolState;\n}\n\n/**\n * Handles protocol specific ops.\n * @internal\n */\nexport class ProtocolOpHandler implements IProtocolHandler {\n\tprivate readonly _quorum: Quorum;\n\tpublic get quorum(): Quorum {\n\t\treturn this._quorum;\n\t}\n\n\tconstructor(\n\t\tpublic minimumSequenceNumber: number,\n\t\tpublic sequenceNumber: number,\n\t\tmembers: [string, ISequencedClient][],\n\t\tproposals: [number, ISequencedProposal, string[]][],\n\t\tvalues: [string, ICommittedProposal][],\n\t\tsendProposal: (key: string, value: any) => number,\n\t) {\n\t\tthis._quorum = new Quorum(members, proposals, values, sendProposal);\n\t}\n\n\tpublic get attributes(): IDocumentAttributes {\n\t\treturn {\n\t\t\tminimumSequenceNumber: this.minimumSequenceNumber,\n\t\t\tsequenceNumber: this.sequenceNumber,\n\t\t};\n\t}\n\n\tsetConnectionState(connected: boolean, clientId: string | undefined) {\n\t\tthis._quorum.setConnectionState(connected, clientId);\n\t}\n\n\tsnapshot(): IQuorumSnapshot {\n\t\treturn this._quorum.snapshot();\n\t}\n\n\tpublic close() {\n\t\tthis._quorum.close();\n\t}\n\n\tpublic processMessage(\n\t\tmessage: ISequencedDocumentMessage,\n\t\tlocal: boolean,\n\t): IProcessMessageResult {\n\t\t// verify it's moving sequentially\n\t\tif (message.sequenceNumber !== this.sequenceNumber + 1) {\n\t\t\tthrow new Error(\n\t\t\t\t`Protocol state is not moving sequentially. ` +\n\t\t\t\t\t`Current is ${this.sequenceNumber}. Next is ${message.sequenceNumber}`,\n\t\t\t);\n\t\t}\n\n\t\t// Update tracked sequence numbers\n\t\tthis.sequenceNumber = message.sequenceNumber;\n\t\tthis.minimumSequenceNumber = message.minimumSequenceNumber;\n\n\t\tlet immediateNoOp = false;\n\n\t\tswitch (message.type) {\n\t\t\tcase MessageType.ClientJoin:\n\t\t\t\tconst systemJoinMessage = message as ISequencedDocumentSystemMessage;\n\t\t\t\tconst join = JSON.parse(systemJoinMessage.data) as IClientJoin;\n\t\t\t\tconst member: ISequencedClient = {\n\t\t\t\t\tclient: join.detail,\n\t\t\t\t\tsequenceNumber: systemJoinMessage.sequenceNumber,\n\t\t\t\t};\n\t\t\t\tthis._quorum.addMember(join.clientId, member);\n\t\t\t\tbreak;\n\n\t\t\tcase MessageType.ClientLeave:\n\t\t\t\tconst systemLeaveMessage = message as ISequencedDocumentSystemMessage;\n\t\t\t\tconst clientId = JSON.parse(systemLeaveMessage.data) as string;\n\t\t\t\tthis._quorum.removeMember(clientId);\n\t\t\t\tbreak;\n\n\t\t\tcase MessageType.Propose:\n\t\t\t\t// back-compat: ADO #1385: This should become unconditional eventually.\n\t\t\t\t// Can be done only after Container.processRemoteMessage() stops parsing content!\n\t\t\t\tif (typeof message.contents === \"string\") {\n\t\t\t\t\tmessage.contents = JSON.parse(message.contents);\n\t\t\t\t}\n\t\t\t\tconst proposal = message.contents as IProposal;\n\t\t\t\tthis._quorum.addProposal(\n\t\t\t\t\tproposal.key,\n\t\t\t\t\tproposal.value,\n\t\t\t\t\tmessage.sequenceNumber,\n\t\t\t\t\tlocal,\n\t\t\t\t\tmessage.clientSequenceNumber,\n\t\t\t\t);\n\n\t\t\t\t// On a quorum proposal, immediately send a response to expedite the approval.\n\t\t\t\timmediateNoOp = true;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t}\n\n\t\t// Notify the quorum of the MSN from the message. We rely on it to handle duplicate values but may\n\t\t// want to move that logic to this class.\n\t\tthis._quorum.updateMinimumSequenceNumber(message);\n\n\t\treturn { immediateNoOp };\n\t}\n\n\t/**\n\t * Gets the scribe protocol state\n\t * @param scrubUserData - whether to remove all user data from the quorum members. CAUTION: this will corrupt the quorum if used in a summary.\n\t */\n\tpublic getProtocolState(scrubUserData = false): IScribeProtocolState {\n\t\t// return a new object every time\n\t\t// this ensures future state changes will not affect outside callers\n\t\tconst snapshot = this._quorum.snapshot();\n\n\t\tif (scrubUserData) {\n\t\t\t// In place, remove any identifying client information\n\t\t\tsnapshot.members = snapshot.members.map(([id, sequencedClient]) => [\n\t\t\t\tid,\n\t\t\t\t{\n\t\t\t\t\t...sequencedClient,\n\t\t\t\t\tclient: {\n\t\t\t\t\t\t...sequencedClient.client,\n\t\t\t\t\t\tuser: { id: \"\" },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t]);\n\t\t}\n\n\t\treturn {\n\t\t\tsequenceNumber: this.sequenceNumber,\n\t\t\tminimumSequenceNumber: this.minimumSequenceNumber,\n\t\t\t...snapshot,\n\t\t};\n\t}\n}\n"]}
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tIDocumentAttributes,\n\tIClientJoin,\n\tICommittedProposal,\n\tIProcessMessageResult,\n\tIProposal,\n\tIQuorum,\n\tISequencedClient,\n\tISequencedDocumentMessage,\n\tISequencedDocumentSystemMessage,\n\tISequencedProposal,\n\tMessageType,\n} from \"@fluidframework/protocol-definitions\";\nimport { IQuorumSnapshot, Quorum } from \"./quorum\";\n\n/**\n * @alpha\n */\nexport interface IScribeProtocolState {\n\tsequenceNumber: number;\n\tminimumSequenceNumber: number;\n\tmembers: [string, ISequencedClient][];\n\tproposals: [number, ISequencedProposal, string[]][];\n\tvalues: [string, ICommittedProposal][];\n}\n\n/**\n * @alpha\n */\nexport interface IProtocolHandler {\n\treadonly quorum: IQuorum;\n\treadonly attributes: IDocumentAttributes;\n\n\tsetConnectionState(connected: boolean, clientId: string | undefined);\n\tsnapshot(): IQuorumSnapshot;\n\n\tclose(): void;\n\tprocessMessage(message: ISequencedDocumentMessage, local: boolean): IProcessMessageResult;\n\tgetProtocolState(): IScribeProtocolState;\n}\n\n/**\n * Handles protocol specific ops.\n * @internal\n */\nexport class ProtocolOpHandler implements IProtocolHandler {\n\tprivate readonly _quorum: Quorum;\n\tpublic get quorum(): Quorum {\n\t\treturn this._quorum;\n\t}\n\n\tconstructor(\n\t\tpublic minimumSequenceNumber: number,\n\t\tpublic sequenceNumber: number,\n\t\tmembers: [string, ISequencedClient][],\n\t\tproposals: [number, ISequencedProposal, string[]][],\n\t\tvalues: [string, ICommittedProposal][],\n\t\tsendProposal: (key: string, value: any) => number,\n\t) {\n\t\tthis._quorum = new Quorum(members, proposals, values, sendProposal);\n\t}\n\n\tpublic get attributes(): IDocumentAttributes {\n\t\treturn {\n\t\t\tminimumSequenceNumber: this.minimumSequenceNumber,\n\t\t\tsequenceNumber: this.sequenceNumber,\n\t\t};\n\t}\n\n\tsetConnectionState(connected: boolean, clientId: string | undefined) {\n\t\tthis._quorum.setConnectionState(connected, clientId);\n\t}\n\n\tsnapshot(): IQuorumSnapshot {\n\t\treturn this._quorum.snapshot();\n\t}\n\n\tpublic close() {\n\t\tthis._quorum.close();\n\t}\n\n\tpublic processMessage(\n\t\tmessage: ISequencedDocumentMessage,\n\t\tlocal: boolean,\n\t): IProcessMessageResult {\n\t\t// verify it's moving sequentially\n\t\tif (message.sequenceNumber !== this.sequenceNumber + 1) {\n\t\t\tthrow new Error(\n\t\t\t\t`Protocol state is not moving sequentially. ` +\n\t\t\t\t\t`Current is ${this.sequenceNumber}. Next is ${message.sequenceNumber}`,\n\t\t\t);\n\t\t}\n\n\t\t// Update tracked sequence numbers\n\t\tthis.sequenceNumber = message.sequenceNumber;\n\t\tthis.minimumSequenceNumber = message.minimumSequenceNumber;\n\n\t\tlet immediateNoOp = false;\n\n\t\tswitch (message.type) {\n\t\t\tcase MessageType.ClientJoin:\n\t\t\t\tconst systemJoinMessage = message as ISequencedDocumentSystemMessage;\n\t\t\t\tconst join = JSON.parse(systemJoinMessage.data) as IClientJoin;\n\t\t\t\tconst member: ISequencedClient = {\n\t\t\t\t\tclient: join.detail,\n\t\t\t\t\tsequenceNumber: systemJoinMessage.sequenceNumber,\n\t\t\t\t};\n\t\t\t\tthis._quorum.addMember(join.clientId, member);\n\t\t\t\tbreak;\n\n\t\t\tcase MessageType.ClientLeave:\n\t\t\t\tconst systemLeaveMessage = message as ISequencedDocumentSystemMessage;\n\t\t\t\tconst clientId = JSON.parse(systemLeaveMessage.data) as string;\n\t\t\t\tthis._quorum.removeMember(clientId);\n\t\t\t\tbreak;\n\n\t\t\tcase MessageType.Propose:\n\t\t\t\t// back-compat: ADO #1385: This should become unconditional eventually.\n\t\t\t\t// Can be done only after Container.processRemoteMessage() stops parsing content!\n\t\t\t\tif (typeof message.contents === \"string\") {\n\t\t\t\t\tmessage.contents = JSON.parse(message.contents);\n\t\t\t\t}\n\t\t\t\tconst proposal = message.contents as IProposal;\n\t\t\t\tthis._quorum.addProposal(\n\t\t\t\t\tproposal.key,\n\t\t\t\t\tproposal.value,\n\t\t\t\t\tmessage.sequenceNumber,\n\t\t\t\t\tlocal,\n\t\t\t\t\tmessage.clientSequenceNumber,\n\t\t\t\t);\n\n\t\t\t\t// On a quorum proposal, immediately send a response to expedite the approval.\n\t\t\t\timmediateNoOp = true;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t}\n\n\t\t// Notify the quorum of the MSN from the message. We rely on it to handle duplicate values but may\n\t\t// want to move that logic to this class.\n\t\tthis._quorum.updateMinimumSequenceNumber(message);\n\n\t\treturn { immediateNoOp };\n\t}\n\n\t/**\n\t * Gets the scribe protocol state\n\t * @param scrubUserData - whether to remove all user data from the quorum members. CAUTION: this will corrupt the quorum if used in a summary.\n\t */\n\tpublic getProtocolState(scrubUserData = false): IScribeProtocolState {\n\t\t// return a new object every time\n\t\t// this ensures future state changes will not affect outside callers\n\t\tconst snapshot = this._quorum.snapshot();\n\n\t\tif (scrubUserData) {\n\t\t\t// In place, remove any identifying client information\n\t\t\tsnapshot.members = snapshot.members.map(([id, sequencedClient]) => [\n\t\t\t\tid,\n\t\t\t\t{\n\t\t\t\t\t...sequencedClient,\n\t\t\t\t\tclient: {\n\t\t\t\t\t\t...sequencedClient.client,\n\t\t\t\t\t\tuser: { id: \"\" },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t]);\n\t\t}\n\n\t\treturn {\n\t\t\tsequenceNumber: this.sequenceNumber,\n\t\t\tminimumSequenceNumber: this.minimumSequenceNumber,\n\t\t\t...snapshot,\n\t\t};\n\t}\n}\n"]}

@@ -11,3 +11,3 @@ /*!

*/
export declare type QuorumClientsSnapshot = [string, ISequencedClient][];
export type QuorumClientsSnapshot = [string, ISequencedClient][];
/**

@@ -17,3 +17,3 @@ * Snapshot format for a QuorumProposals

*/
export declare type QuorumProposalsSnapshot = {
export type QuorumProposalsSnapshot = {
proposals: [number, ISequencedProposal, string[]][];

@@ -20,0 +20,0 @@ values: [string, ICommittedProposal][];

@@ -1,1 +0,1 @@

{"version":3,"file":"quorum.d.ts","sourceRoot":"","sources":["../src/quorum.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"quorum.d.ts","sourceRoot":"","sources":["../src/quorum.ts"],"names":[],"mappings":"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"}

@@ -23,2 +23,5 @@ /*!

export class QuorumClients extends TypedEventEmitter {
get disposed() {
return this.isDisposed;
}
constructor(snapshot) {

@@ -30,5 +33,2 @@ super();

}
get disposed() {
return this.isDisposed;
}
/**

@@ -86,2 +86,5 @@ * Snapshots the current state of the QuorumClients

export class QuorumProposals extends TypedEventEmitter {
get disposed() {
return this.isDisposed;
}
constructor(snapshot, sendProposal) {

@@ -103,5 +106,2 @@ super();

}
get disposed() {
return this.isDisposed;
}
/**

@@ -305,2 +305,5 @@ * Snapshots the current state of the QuorumProposals

export class Quorum extends TypedEventEmitter {
get disposed() {
return this.isDisposed;
}
constructor(members, proposals, values, sendProposal) {

@@ -324,5 +327,2 @@ super();

}
get disposed() {
return this.isDisposed;
}
close() {

@@ -329,0 +329,0 @@ this.removeAllListeners();

@@ -1,1 +0,1 @@

{"version":3,"file":"quorum.js","sourceRoot":"","sources":["../src/quorum.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { EventEmitter } from \"events\";\n\nimport { assert, TypedEventEmitter } from \"@fluidframework/common-utils\";\nimport {\n\tICommittedProposal,\n\tIQuorum,\n\tIQuorumClients,\n\tIQuorumProposals,\n\tISequencedClient,\n\tISequencedDocumentMessage,\n\tISequencedProposal,\n} from \"@fluidframework/protocol-definitions\";\n\n/**\n * Structure for tracking proposals that have been sequenced but not approved yet.\n */\nclass PendingProposal implements ISequencedProposal {\n\tconstructor(\n\t\tpublic readonly sequenceNumber: number,\n\t\tpublic readonly key: string,\n\t\tpublic readonly value: any,\n\t\tpublic readonly local: boolean,\n\t) {}\n}\n\n/**\n * Snapshot format for a QuorumClients\n * @alpha\n */\nexport type QuorumClientsSnapshot = [string, ISequencedClient][];\n\n/**\n * Snapshot format for a QuorumProposals\n * @alpha\n */\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport type QuorumProposalsSnapshot = {\n\tproposals: [number, ISequencedProposal, string[]][];\n\tvalues: [string, ICommittedProposal][];\n};\n\n/**\n * Snapshot format for a Quorum\n * @alpha\n */\nexport interface IQuorumSnapshot {\n\tmembers: QuorumClientsSnapshot;\n\tproposals: QuorumProposalsSnapshot[\"proposals\"];\n\tvalues: QuorumProposalsSnapshot[\"values\"];\n}\n\n/**\n * The QuorumClients is used to track members joining and leaving the collaboration session.\n * @internal\n */\nexport class QuorumClients\n\textends TypedEventEmitter<IQuorumClients[\"on\"]>\n\timplements IQuorumClients\n{\n\tprivate readonly members: Map<string, ISequencedClient>;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed() {\n\t\treturn this.isDisposed;\n\t}\n\n\t/**\n\t * Cached snapshot state, to avoid unnecessary deep clones on repeated snapshot calls.\n\t * Cleared immediately (set to undefined) when the cache becomes invalid.\n\t */\n\tprivate snapshotCache: QuorumClientsSnapshot | undefined;\n\n\tconstructor(snapshot: QuorumClientsSnapshot) {\n\t\tsuper();\n\n\t\tthis.members = new Map(snapshot);\n\t\tthis.snapshotCache = snapshot;\n\t}\n\n\t/**\n\t * Snapshots the current state of the QuorumClients\n\t * @returns a snapshot of the clients in the quorum\n\t */\n\tpublic snapshot(): QuorumClientsSnapshot {\n\t\tthis.snapshotCache ??= Array.from(this.members);\n\n\t\treturn this.snapshotCache;\n\t}\n\n\t/**\n\t * Adds a new client to the quorum\n\t */\n\tpublic addMember(clientId: string, details: ISequencedClient) {\n\t\tassert(!!clientId, 0x46f /* clientId has to be non-empty string */);\n\t\tassert(!this.members.has(clientId), 0x1ce /* clientId not found */);\n\t\tthis.members.set(clientId, details);\n\t\tthis.emit(\"addMember\", clientId, details);\n\n\t\t// clear the cache\n\t\tthis.snapshotCache = undefined;\n\t}\n\n\t/**\n\t * Removes a client from the quorum\n\t */\n\tpublic removeMember(clientId: string) {\n\t\tassert(!!clientId, 0x470 /* clientId has to be non-empty string */);\n\t\tassert(this.members.has(clientId), 0x1cf /* clientId not found */);\n\t\tthis.members.delete(clientId);\n\t\tthis.emit(\"removeMember\", clientId);\n\n\t\t// clear the cache\n\t\tthis.snapshotCache = undefined;\n\t}\n\n\t/**\n\t * Retrieves all the members in the quorum\n\t */\n\tpublic getMembers(): Map<string, ISequencedClient> {\n\t\treturn new Map(this.members);\n\t}\n\n\t/**\n\t * Retrieves a specific member of the quorum\n\t */\n\tpublic getMember(clientId: string): ISequencedClient | undefined {\n\t\treturn this.members.get(clientId);\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.isDisposed = true;\n\t}\n}\n\n/**\n * The QuorumProposals holds a key/value store. Proposed values become finalized in the store once all connected\n * clients have seen the proposal.\n * @internal\n */\nexport class QuorumProposals\n\textends TypedEventEmitter<IQuorumProposals[\"on\"]>\n\timplements IQuorumProposals\n{\n\tprivate readonly proposals: Map<number, PendingProposal>;\n\tprivate readonly values: Map<string, ICommittedProposal>;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed() {\n\t\treturn this.isDisposed;\n\t}\n\n\t// Event emitter for changes to the environment that affect pending proposal promises.\n\tprivate readonly stateEvents = new EventEmitter();\n\n\t/**\n\t * Cached snapshot state, to avoid unnecessary deep clones on repeated snapshot calls.\n\t * Cleared immediately (set to undefined) when the cache becomes invalid.\n\t */\n\tprivate proposalsSnapshotCache: QuorumProposalsSnapshot[\"proposals\"] | undefined;\n\tprivate valuesSnapshotCache: QuorumProposalsSnapshot[\"values\"] | undefined;\n\n\tconstructor(\n\t\tsnapshot: QuorumProposalsSnapshot,\n\t\tprivate readonly sendProposal: (key: string, value: any) => number,\n\t) {\n\t\tsuper();\n\n\t\tthis.proposals = new Map(\n\t\t\tsnapshot.proposals.map(([, proposal]) => {\n\t\t\t\treturn [\n\t\t\t\t\tproposal.sequenceNumber,\n\t\t\t\t\tnew PendingProposal(\n\t\t\t\t\t\tproposal.sequenceNumber,\n\t\t\t\t\t\tproposal.key,\n\t\t\t\t\t\tproposal.value,\n\t\t\t\t\t\tfalse, // local\n\t\t\t\t\t),\n\t\t\t\t] as [number, PendingProposal];\n\t\t\t}),\n\t\t);\n\t\tthis.values = new Map(snapshot.values);\n\t\tthis.proposalsSnapshotCache = snapshot.proposals;\n\t\tthis.valuesSnapshotCache = snapshot.values;\n\t}\n\n\t/**\n\t * Snapshots the current state of the QuorumProposals\n\t * @returns arrays of proposals and values\n\t */\n\tpublic snapshot(): QuorumProposalsSnapshot {\n\t\tthis.proposalsSnapshotCache ??= Array.from(this.proposals).map(\n\t\t\t([sequenceNumber, proposal]) => [\n\t\t\t\tsequenceNumber,\n\t\t\t\t{ sequenceNumber, key: proposal.key, value: proposal.value },\n\t\t\t\t[], // rejections, which has been removed\n\t\t\t],\n\t\t);\n\t\tthis.valuesSnapshotCache ??= Array.from(this.values);\n\n\t\treturn {\n\t\t\tproposals: this.proposalsSnapshotCache,\n\t\t\tvalues: this.valuesSnapshotCache,\n\t\t};\n\t}\n\n\t/**\n\t * Returns whether the quorum has achieved a consensus for the given key.\n\t */\n\tpublic has(key: string): boolean {\n\t\treturn this.values.has(key);\n\t}\n\n\t/**\n\t * Returns the consensus value for the given key\n\t */\n\tpublic get(key: string): any {\n\t\treturn this.values.get(key)?.value;\n\t}\n\n\t/**\n\t * Returns additional data about the approved consensus value\n\t * @deprecated Removed in recent protocol-definitions. Use get() instead.\n\t */\n\tpublic getApprovalData(key: string): ICommittedProposal | undefined {\n\t\treturn this.values.get(key);\n\t}\n\n\t/**\n\t * Proposes a new value. Returns a promise that will either:\n\t * - Resolve when the proposal is accepted\n\t * - Reject if the proposal fails to send or if the QuorumProposals is disposed\n\t */\n\tpublic async propose(key: string, value: any): Promise<void> {\n\t\tconst clientSequenceNumber = this.sendProposal(key, value);\n\t\tif (clientSequenceNumber < 0) {\n\t\t\tthis.emit(\"error\", { eventName: \"ProposalInDisconnectedState\", key });\n\t\t\tthrow new Error(\"Can't propose in disconnected state\");\n\t\t}\n\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\t// The sequence number that our proposal was assigned and went pending.\n\t\t\t// If undefined, then it's not sequenced yet.\n\t\t\tlet thisProposalSequenceNumber: number | undefined;\n\n\t\t\t// A proposal goes through two phases before this promise resolves:\n\t\t\t// 1. Sequencing - waiting for the proposal to be ack'd by the server.\n\t\t\t// 2. Approval - waiting for the proposal to be approved by connected clients.\n\t\t\tconst localProposalSequencedHandler = (\n\t\t\t\tsequencedCSN: number,\n\t\t\t\tsequenceNumber: number,\n\t\t\t) => {\n\t\t\t\tif (sequencedCSN === clientSequenceNumber) {\n\t\t\t\t\tthisProposalSequenceNumber = sequenceNumber;\n\t\t\t\t\tthis.stateEvents.off(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\t\t\tthis.stateEvents.off(\"disconnected\", disconnectedHandler);\n\t\t\t\t\tthis.stateEvents.on(\"localProposalApproved\", localProposalApprovedHandler);\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst localProposalApprovedHandler = (sequenceNumber: number) => {\n\t\t\t\t// Proposals can be uniquely identified by the sequenceNumber they were assigned.\n\t\t\t\tif (sequenceNumber === thisProposalSequenceNumber) {\n\t\t\t\t\tresolve();\n\t\t\t\t\tremoveListeners();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// There are two error flows we consider: disconnect and disposal.\n\t\t\t// If we get disconnected before the proposal is sequenced, it has one of two possible futures:\n\t\t\t// 1. We reconnect and see the proposal was sequenced in the meantime.\n\t\t\t// -> The promise can still resolve, once it is approved.\n\t\t\t// 2. We reconnect and see the proposal was not sequenced in the meantime, so it will never sequence.\n\t\t\t// -> The promise rejects.\n\t\t\tconst disconnectedHandler = () => {\n\t\t\t\t// If we haven't seen the ack by the time we disconnect, we hope to see it by the time we reconnect.\n\t\t\t\tif (thisProposalSequenceNumber === undefined) {\n\t\t\t\t\tthis.stateEvents.once(\"connected\", () => {\n\t\t\t\t\t\t// If we don't see the ack by the time reconnection finishes, it failed to send.\n\t\t\t\t\t\tif (thisProposalSequenceNumber === undefined) {\n\t\t\t\t\t\t\treject(\n\t\t\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t\t\t\"Client disconnected without successfully sending proposal\",\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tremoveListeners();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t};\n\t\t\t// If the QuorumProposals is disposed of, we assume something catastrophic has happened\n\t\t\t// All outstanding proposals are considered rejected.\n\t\t\tconst disposedHandler = () => {\n\t\t\t\treject(new Error(\"QuorumProposals was disposed\"));\n\t\t\t\tremoveListeners();\n\t\t\t};\n\t\t\t// Convenience function to clean up our listeners.\n\t\t\tconst removeListeners = () => {\n\t\t\t\tthis.stateEvents.off(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\t\tthis.stateEvents.off(\"localProposalApproved\", localProposalApprovedHandler);\n\t\t\t\tthis.stateEvents.off(\"disconnected\", disconnectedHandler);\n\t\t\t\tthis.stateEvents.off(\"disposed\", disposedHandler);\n\t\t\t};\n\t\t\tthis.stateEvents.on(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\tthis.stateEvents.on(\"disconnected\", disconnectedHandler);\n\t\t\tthis.stateEvents.on(\"disposed\", disposedHandler);\n\t\t});\n\t}\n\n\t/**\n\t * Begins tracking a new proposal\n\t */\n\tpublic addProposal(\n\t\tkey: string,\n\t\tvalue: any,\n\t\tsequenceNumber: number,\n\t\tlocal: boolean,\n\t\tclientSequenceNumber: number,\n\t) {\n\t\tassert(!this.proposals.has(sequenceNumber), 0x1d0 /* sequenceNumber not found */);\n\n\t\tconst proposal = new PendingProposal(sequenceNumber, key, value, local);\n\t\tthis.proposals.set(sequenceNumber, proposal);\n\n\t\t// Legacy event, from rejection support. May still have some use for clients to learn that a proposal is\n\t\t// likely to be approved soon.\n\t\tthis.emit(\"addProposal\", proposal);\n\n\t\tif (local) {\n\t\t\tthis.stateEvents.emit(\"localProposalSequenced\", clientSequenceNumber, sequenceNumber);\n\t\t}\n\n\t\t// clear the proposal cache\n\t\tthis.proposalsSnapshotCache = undefined;\n\t}\n\n\t/**\n\t * Updates the minimum sequence number. If the MSN advances past the sequence number for any proposal then it\n\t * becomes an approved value.\n\t */\n\tpublic updateMinimumSequenceNumber(message: ISequencedDocumentMessage): void {\n\t\tconst msn = message.minimumSequenceNumber;\n\n\t\t// Accept proposals proposals whose sequenceNumber is <= the minimumSequenceNumber\n\n\t\t// Return a sorted list of approved proposals. We sort so that we apply them in their sequence number order\n\t\t// TODO this can be optimized if necessary to avoid the linear search+sort\n\t\tconst completed: PendingProposal[] = [];\n\t\tfor (const [sequenceNumber, proposal] of this.proposals) {\n\t\t\tif (sequenceNumber <= msn) {\n\t\t\t\tcompleted.push(proposal);\n\t\t\t}\n\t\t}\n\t\tcompleted.sort((a, b) => a.sequenceNumber - b.sequenceNumber);\n\n\t\tfor (const proposal of completed) {\n\t\t\tconst committedProposal: ICommittedProposal = {\n\t\t\t\tapprovalSequenceNumber: message.sequenceNumber,\n\t\t\t\t// No longer used. We still stamp a -1 for compat with older versions of the quorum.\n\t\t\t\t// Can be removed after 0.1035 and higher is ubiquitous.\n\t\t\t\tcommitSequenceNumber: -1,\n\t\t\t\tkey: proposal.key,\n\t\t\t\tsequenceNumber: proposal.sequenceNumber,\n\t\t\t\tvalue: proposal.value,\n\t\t\t};\n\n\t\t\tthis.values.set(committedProposal.key, committedProposal);\n\n\t\t\t// clear the values cache\n\t\t\tthis.valuesSnapshotCache = undefined;\n\n\t\t\t// check if there are multiple proposals with matching keys\n\t\t\tlet proposalSettled = false;\n\t\t\tlet proposalKeySeen = false;\n\t\t\tfor (const [, p] of this.proposals) {\n\t\t\t\tif (p.key === committedProposal.key) {\n\t\t\t\t\tif (!proposalKeySeen) {\n\t\t\t\t\t\t// set proposalSettled to true if the proposal key match is unique thus far\n\t\t\t\t\t\tproposalSettled = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// set proposalSettled to false if matching proposal key is not unique\n\t\t\t\t\t\tproposalSettled = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tproposalKeySeen = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.emit(\n\t\t\t\t\"approveProposal\",\n\t\t\t\tcommittedProposal.sequenceNumber,\n\t\t\t\tcommittedProposal.key,\n\t\t\t\tcommittedProposal.value,\n\t\t\t\tcommittedProposal.approvalSequenceNumber,\n\t\t\t);\n\n\t\t\t// emit approveProposalComplete when all pending proposals are processed\n\t\t\tif (proposalSettled) {\n\t\t\t\tthis.emit(\n\t\t\t\t\t\"approveProposalComplete\",\n\t\t\t\t\tcommittedProposal.sequenceNumber,\n\t\t\t\t\tcommittedProposal.key,\n\t\t\t\t\tcommittedProposal.value,\n\t\t\t\t\tcommittedProposal.approvalSequenceNumber,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.proposals.delete(proposal.sequenceNumber);\n\n\t\t\t// clear the proposals cache\n\t\t\tthis.proposalsSnapshotCache = undefined;\n\t\t\tif (proposal.local) {\n\t\t\t\tthis.stateEvents.emit(\"localProposalApproved\", proposal.sequenceNumber);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic setConnectionState(connected: boolean) {\n\t\tif (connected) {\n\t\t\tthis.stateEvents.emit(\"connected\");\n\t\t} else {\n\t\t\tthis.stateEvents.emit(\"disconnected\");\n\t\t}\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.isDisposed = true;\n\t\tthis.stateEvents.emit(\"disposed\");\n\t}\n}\n\n/**\n * A quorum represents all clients currently within the collaboration window. As well as the values\n * they have agreed upon and any pending proposals.\n * @internal\n */\nexport class Quorum extends TypedEventEmitter<IQuorum[\"on\"]> implements IQuorum {\n\tprivate readonly quorumClients: QuorumClients;\n\tprivate readonly quorumProposals: QuorumProposals;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed() {\n\t\treturn this.isDisposed;\n\t}\n\n\tconstructor(\n\t\tmembers: QuorumClientsSnapshot,\n\t\tproposals: QuorumProposalsSnapshot[\"proposals\"],\n\t\tvalues: QuorumProposalsSnapshot[\"values\"],\n\t\tsendProposal: (key: string, value: any) => number,\n\t) {\n\t\tsuper();\n\n\t\tthis.quorumClients = new QuorumClients(members);\n\t\tthis.quorumClients.on(\"addMember\", (clientId: string, details: ISequencedClient) => {\n\t\t\tthis.emit(\"addMember\", clientId, details);\n\t\t});\n\t\tthis.quorumClients.on(\"removeMember\", (clientId: string) => {\n\t\t\tthis.emit(\"removeMember\", clientId);\n\t\t});\n\n\t\tthis.quorumProposals = new QuorumProposals({ proposals, values }, sendProposal);\n\t\tthis.quorumProposals.on(\"addProposal\", (proposal: ISequencedProposal) => {\n\t\t\tthis.emit(\"addProposal\", proposal);\n\t\t});\n\t\tthis.quorumProposals.on(\n\t\t\t\"approveProposal\",\n\t\t\t(sequenceNumber: number, key: string, value: any, approvalSequenceNumber: number) => {\n\t\t\t\tthis.emit(\"approveProposal\", sequenceNumber, key, value, approvalSequenceNumber);\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic close() {\n\t\tthis.removeAllListeners();\n\t}\n\n\t/**\n\t * Snapshots the entire quorum\n\t * @returns a quorum snapshot\n\t */\n\tpublic snapshot(): IQuorumSnapshot {\n\t\tconst members = this.quorumClients.snapshot();\n\t\tconst { proposals, values } = this.quorumProposals.snapshot();\n\t\treturn {\n\t\t\tmembers,\n\t\t\tproposals,\n\t\t\tvalues,\n\t\t};\n\t}\n\n\t/**\n\t * Returns whether the quorum has achieved a consensus for the given key.\n\t */\n\tpublic has(key: string): boolean {\n\t\treturn this.quorumProposals.has(key);\n\t}\n\n\t/**\n\t * Returns the consensus value for the given key\n\t */\n\tpublic get(key: string): any {\n\t\treturn this.quorumProposals.get(key);\n\t}\n\n\t/**\n\t * Returns additional data about the approved consensus value\n\t * @deprecated Removed in recent protocol-definitions. Use get() instead.\n\t */\n\tpublic getApprovalData(key: string): ICommittedProposal | undefined {\n\t\treturn this.quorumProposals.getApprovalData(key);\n\t}\n\n\t/**\n\t * Adds a new client to the quorum\n\t */\n\tpublic addMember(clientId: string, details: ISequencedClient) {\n\t\tthis.quorumClients.addMember(clientId, details);\n\t}\n\n\t/**\n\t * Removes a client from the quorum\n\t */\n\tpublic removeMember(clientId: string) {\n\t\tthis.quorumClients.removeMember(clientId);\n\t}\n\n\t/**\n\t * Retrieves all the members in the quorum\n\t */\n\tpublic getMembers(): Map<string, ISequencedClient> {\n\t\treturn this.quorumClients.getMembers();\n\t}\n\n\t/**\n\t * Retrieves a specific member of the quorum\n\t */\n\tpublic getMember(clientId: string): ISequencedClient | undefined {\n\t\treturn this.quorumClients.getMember(clientId);\n\t}\n\n\t/**\n\t * Proposes a new value. Returns a promise that will resolve when the proposal is either accepted, or reject if\n\t * the proposal fails to send.\n\t */\n\tpublic async propose(key: string, value: any): Promise<void> {\n\t\treturn this.quorumProposals.propose(key, value);\n\t}\n\n\t/**\n\t * Begins tracking a new proposal\n\t */\n\tpublic addProposal(\n\t\tkey: string,\n\t\tvalue: any,\n\t\tsequenceNumber: number,\n\t\tlocal: boolean,\n\t\tclientSequenceNumber: number,\n\t) {\n\t\treturn this.quorumProposals.addProposal(\n\t\t\tkey,\n\t\t\tvalue,\n\t\t\tsequenceNumber,\n\t\t\tlocal,\n\t\t\tclientSequenceNumber,\n\t\t);\n\t}\n\n\t/**\n\t * Updates the minimum sequence number. If the MSN advances past the sequence number for any proposal then it\n\t * becomes an approved value.\n\t */\n\tpublic updateMinimumSequenceNumber(message: ISequencedDocumentMessage): void {\n\t\tthis.quorumProposals.updateMinimumSequenceNumber(message);\n\t}\n\n\tpublic setConnectionState(connected: boolean, clientId?: string) {\n\t\tthis.quorumProposals.setConnectionState(connected);\n\t}\n\n\tpublic dispose(): void {\n\t\tthrow new Error(\"Not implemented.\");\n\t\tthis.isDisposed = true;\n\t}\n}\n"]}
{"version":3,"file":"quorum.js","sourceRoot":"","sources":["../src/quorum.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { EventEmitter } from \"events\";\n\nimport { assert, TypedEventEmitter } from \"@fluidframework/common-utils\";\nimport {\n\tICommittedProposal,\n\tIQuorum,\n\tIQuorumClients,\n\tIQuorumProposals,\n\tISequencedClient,\n\tISequencedDocumentMessage,\n\tISequencedProposal,\n} from \"@fluidframework/protocol-definitions\";\n\n/**\n * Structure for tracking proposals that have been sequenced but not approved yet.\n */\nclass PendingProposal implements ISequencedProposal {\n\tconstructor(\n\t\tpublic readonly sequenceNumber: number,\n\t\tpublic readonly key: string,\n\t\tpublic readonly value: any,\n\t\tpublic readonly local: boolean,\n\t) {}\n}\n\n/**\n * Snapshot format for a QuorumClients\n * @alpha\n */\nexport type QuorumClientsSnapshot = [string, ISequencedClient][];\n\n/**\n * Snapshot format for a QuorumProposals\n * @alpha\n */\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport type QuorumProposalsSnapshot = {\n\tproposals: [number, ISequencedProposal, string[]][];\n\tvalues: [string, ICommittedProposal][];\n};\n\n/**\n * Snapshot format for a Quorum\n * @alpha\n */\nexport interface IQuorumSnapshot {\n\tmembers: QuorumClientsSnapshot;\n\tproposals: QuorumProposalsSnapshot[\"proposals\"];\n\tvalues: QuorumProposalsSnapshot[\"values\"];\n}\n\n/**\n * The QuorumClients is used to track members joining and leaving the collaboration session.\n * @internal\n */\nexport class QuorumClients\n\textends TypedEventEmitter<IQuorumClients[\"on\"]>\n\timplements IQuorumClients\n{\n\tprivate readonly members: Map<string, ISequencedClient>;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed() {\n\t\treturn this.isDisposed;\n\t}\n\n\t/**\n\t * Cached snapshot state, to avoid unnecessary deep clones on repeated snapshot calls.\n\t * Cleared immediately (set to undefined) when the cache becomes invalid.\n\t */\n\tprivate snapshotCache: QuorumClientsSnapshot | undefined;\n\n\tconstructor(snapshot: QuorumClientsSnapshot) {\n\t\tsuper();\n\n\t\tthis.members = new Map(snapshot);\n\t\tthis.snapshotCache = snapshot;\n\t}\n\n\t/**\n\t * Snapshots the current state of the QuorumClients\n\t * @returns a snapshot of the clients in the quorum\n\t */\n\tpublic snapshot(): QuorumClientsSnapshot {\n\t\tthis.snapshotCache ??= Array.from(this.members);\n\n\t\treturn this.snapshotCache;\n\t}\n\n\t/**\n\t * Adds a new client to the quorum\n\t */\n\tpublic addMember(clientId: string, details: ISequencedClient) {\n\t\tassert(!!clientId, 0x46f /* clientId has to be non-empty string */);\n\t\tassert(!this.members.has(clientId), 0x1ce /* clientId not found */);\n\t\tthis.members.set(clientId, details);\n\t\tthis.emit(\"addMember\", clientId, details);\n\n\t\t// clear the cache\n\t\tthis.snapshotCache = undefined;\n\t}\n\n\t/**\n\t * Removes a client from the quorum\n\t */\n\tpublic removeMember(clientId: string) {\n\t\tassert(!!clientId, 0x470 /* clientId has to be non-empty string */);\n\t\tassert(this.members.has(clientId), 0x1cf /* clientId not found */);\n\t\tthis.members.delete(clientId);\n\t\tthis.emit(\"removeMember\", clientId);\n\n\t\t// clear the cache\n\t\tthis.snapshotCache = undefined;\n\t}\n\n\t/**\n\t * Retrieves all the members in the quorum\n\t */\n\tpublic getMembers(): Map<string, ISequencedClient> {\n\t\treturn new Map(this.members);\n\t}\n\n\t/**\n\t * Retrieves a specific member of the quorum\n\t */\n\tpublic getMember(clientId: string): ISequencedClient | undefined {\n\t\treturn this.members.get(clientId);\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.isDisposed = true;\n\t}\n}\n\n/**\n * The QuorumProposals holds a key/value store. Proposed values become finalized in the store once all connected\n * clients have seen the proposal.\n * @internal\n */\nexport class QuorumProposals\n\textends TypedEventEmitter<IQuorumProposals[\"on\"]>\n\timplements IQuorumProposals\n{\n\tprivate readonly proposals: Map<number, PendingProposal>;\n\tprivate readonly values: Map<string, ICommittedProposal>;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed() {\n\t\treturn this.isDisposed;\n\t}\n\n\t// Event emitter for changes to the environment that affect pending proposal promises.\n\tprivate readonly stateEvents = new EventEmitter();\n\n\t/**\n\t * Cached snapshot state, to avoid unnecessary deep clones on repeated snapshot calls.\n\t * Cleared immediately (set to undefined) when the cache becomes invalid.\n\t */\n\tprivate proposalsSnapshotCache: QuorumProposalsSnapshot[\"proposals\"] | undefined;\n\tprivate valuesSnapshotCache: QuorumProposalsSnapshot[\"values\"] | undefined;\n\n\tconstructor(\n\t\tsnapshot: QuorumProposalsSnapshot,\n\t\tprivate readonly sendProposal: (key: string, value: any) => number,\n\t) {\n\t\tsuper();\n\n\t\tthis.proposals = new Map(\n\t\t\tsnapshot.proposals.map(([, proposal]) => {\n\t\t\t\treturn [\n\t\t\t\t\tproposal.sequenceNumber,\n\t\t\t\t\tnew PendingProposal(\n\t\t\t\t\t\tproposal.sequenceNumber,\n\t\t\t\t\t\tproposal.key,\n\t\t\t\t\t\tproposal.value,\n\t\t\t\t\t\tfalse, // local\n\t\t\t\t\t),\n\t\t\t\t] as [number, PendingProposal];\n\t\t\t}),\n\t\t);\n\t\tthis.values = new Map(snapshot.values);\n\t\tthis.proposalsSnapshotCache = snapshot.proposals;\n\t\tthis.valuesSnapshotCache = snapshot.values;\n\t}\n\n\t/**\n\t * Snapshots the current state of the QuorumProposals\n\t * @returns arrays of proposals and values\n\t */\n\tpublic snapshot(): QuorumProposalsSnapshot {\n\t\tthis.proposalsSnapshotCache ??= Array.from(this.proposals).map(\n\t\t\t([sequenceNumber, proposal]) => [\n\t\t\t\tsequenceNumber,\n\t\t\t\t{ sequenceNumber, key: proposal.key, value: proposal.value },\n\t\t\t\t[], // rejections, which has been removed\n\t\t\t],\n\t\t);\n\t\tthis.valuesSnapshotCache ??= Array.from(this.values);\n\n\t\treturn {\n\t\t\tproposals: this.proposalsSnapshotCache,\n\t\t\tvalues: this.valuesSnapshotCache,\n\t\t};\n\t}\n\n\t/**\n\t * Returns whether the quorum has achieved a consensus for the given key.\n\t */\n\tpublic has(key: string): boolean {\n\t\treturn this.values.has(key);\n\t}\n\n\t/**\n\t * Returns the consensus value for the given key\n\t */\n\tpublic get(key: string): any {\n\t\treturn this.values.get(key)?.value;\n\t}\n\n\t/**\n\t * Returns additional data about the approved consensus value\n\t * @deprecated Removed in recent protocol-definitions. Use get() instead.\n\t */\n\tpublic getApprovalData(key: string): ICommittedProposal | undefined {\n\t\treturn this.values.get(key);\n\t}\n\n\t/**\n\t * Proposes a new value. Returns a promise that will either:\n\t * - Resolve when the proposal is accepted\n\t * - Reject if the proposal fails to send or if the QuorumProposals is disposed\n\t */\n\tpublic async propose(key: string, value: any): Promise<void> {\n\t\tconst clientSequenceNumber = this.sendProposal(key, value);\n\t\tif (clientSequenceNumber < 0) {\n\t\t\tthis.emit(\"error\", { eventName: \"ProposalInDisconnectedState\", key });\n\t\t\tthrow new Error(\"Can't propose in disconnected state\");\n\t\t}\n\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\t// The sequence number that our proposal was assigned and went pending.\n\t\t\t// If undefined, then it's not sequenced yet.\n\t\t\tlet thisProposalSequenceNumber: number | undefined;\n\n\t\t\t// A proposal goes through two phases before this promise resolves:\n\t\t\t// 1. Sequencing - waiting for the proposal to be ack'd by the server.\n\t\t\t// 2. Approval - waiting for the proposal to be approved by connected clients.\n\t\t\tconst localProposalSequencedHandler = (\n\t\t\t\tsequencedCSN: number,\n\t\t\t\tsequenceNumber: number,\n\t\t\t) => {\n\t\t\t\tif (sequencedCSN === clientSequenceNumber) {\n\t\t\t\t\tthisProposalSequenceNumber = sequenceNumber;\n\t\t\t\t\tthis.stateEvents.off(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\t\t\tthis.stateEvents.off(\"disconnected\", disconnectedHandler);\n\t\t\t\t\tthis.stateEvents.on(\"localProposalApproved\", localProposalApprovedHandler);\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst localProposalApprovedHandler = (sequenceNumber: number) => {\n\t\t\t\t// Proposals can be uniquely identified by the sequenceNumber they were assigned.\n\t\t\t\tif (sequenceNumber === thisProposalSequenceNumber) {\n\t\t\t\t\tresolve();\n\t\t\t\t\tremoveListeners();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// There are two error flows we consider: disconnect and disposal.\n\t\t\t// If we get disconnected before the proposal is sequenced, it has one of two possible futures:\n\t\t\t// 1. We reconnect and see the proposal was sequenced in the meantime.\n\t\t\t// -> The promise can still resolve, once it is approved.\n\t\t\t// 2. We reconnect and see the proposal was not sequenced in the meantime, so it will never sequence.\n\t\t\t// -> The promise rejects.\n\t\t\tconst disconnectedHandler = () => {\n\t\t\t\t// If we haven't seen the ack by the time we disconnect, we hope to see it by the time we reconnect.\n\t\t\t\tif (thisProposalSequenceNumber === undefined) {\n\t\t\t\t\tthis.stateEvents.once(\"connected\", () => {\n\t\t\t\t\t\t// If we don't see the ack by the time reconnection finishes, it failed to send.\n\t\t\t\t\t\tif (thisProposalSequenceNumber === undefined) {\n\t\t\t\t\t\t\treject(\n\t\t\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t\t\t\"Client disconnected without successfully sending proposal\",\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tremoveListeners();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t};\n\t\t\t// If the QuorumProposals is disposed of, we assume something catastrophic has happened\n\t\t\t// All outstanding proposals are considered rejected.\n\t\t\tconst disposedHandler = () => {\n\t\t\t\treject(new Error(\"QuorumProposals was disposed\"));\n\t\t\t\tremoveListeners();\n\t\t\t};\n\t\t\t// Convenience function to clean up our listeners.\n\t\t\tconst removeListeners = () => {\n\t\t\t\tthis.stateEvents.off(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\t\tthis.stateEvents.off(\"localProposalApproved\", localProposalApprovedHandler);\n\t\t\t\tthis.stateEvents.off(\"disconnected\", disconnectedHandler);\n\t\t\t\tthis.stateEvents.off(\"disposed\", disposedHandler);\n\t\t\t};\n\t\t\tthis.stateEvents.on(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\tthis.stateEvents.on(\"disconnected\", disconnectedHandler);\n\t\t\tthis.stateEvents.on(\"disposed\", disposedHandler);\n\t\t});\n\t}\n\n\t/**\n\t * Begins tracking a new proposal\n\t */\n\tpublic addProposal(\n\t\tkey: string,\n\t\tvalue: any,\n\t\tsequenceNumber: number,\n\t\tlocal: boolean,\n\t\tclientSequenceNumber: number,\n\t) {\n\t\tassert(!this.proposals.has(sequenceNumber), 0x1d0 /* sequenceNumber not found */);\n\n\t\tconst proposal = new PendingProposal(sequenceNumber, key, value, local);\n\t\tthis.proposals.set(sequenceNumber, proposal);\n\n\t\t// Legacy event, from rejection support. May still have some use for clients to learn that a proposal is\n\t\t// likely to be approved soon.\n\t\tthis.emit(\"addProposal\", proposal);\n\n\t\tif (local) {\n\t\t\tthis.stateEvents.emit(\"localProposalSequenced\", clientSequenceNumber, sequenceNumber);\n\t\t}\n\n\t\t// clear the proposal cache\n\t\tthis.proposalsSnapshotCache = undefined;\n\t}\n\n\t/**\n\t * Updates the minimum sequence number. If the MSN advances past the sequence number for any proposal then it\n\t * becomes an approved value.\n\t */\n\tpublic updateMinimumSequenceNumber(message: ISequencedDocumentMessage): void {\n\t\tconst msn = message.minimumSequenceNumber;\n\n\t\t// Accept proposals proposals whose sequenceNumber is <= the minimumSequenceNumber\n\n\t\t// Return a sorted list of approved proposals. We sort so that we apply them in their sequence number order\n\t\t// TODO this can be optimized if necessary to avoid the linear search+sort\n\t\tconst completed: PendingProposal[] = [];\n\t\tfor (const [sequenceNumber, proposal] of this.proposals) {\n\t\t\tif (sequenceNumber <= msn) {\n\t\t\t\tcompleted.push(proposal);\n\t\t\t}\n\t\t}\n\t\tcompleted.sort((a, b) => a.sequenceNumber - b.sequenceNumber);\n\n\t\tfor (const proposal of completed) {\n\t\t\tconst committedProposal: ICommittedProposal = {\n\t\t\t\tapprovalSequenceNumber: message.sequenceNumber,\n\t\t\t\t// No longer used. We still stamp a -1 for compat with older versions of the quorum.\n\t\t\t\t// Can be removed after 0.1035 and higher is ubiquitous.\n\t\t\t\tcommitSequenceNumber: -1,\n\t\t\t\tkey: proposal.key,\n\t\t\t\tsequenceNumber: proposal.sequenceNumber,\n\t\t\t\tvalue: proposal.value,\n\t\t\t};\n\n\t\t\tthis.values.set(committedProposal.key, committedProposal);\n\n\t\t\t// clear the values cache\n\t\t\tthis.valuesSnapshotCache = undefined;\n\n\t\t\t// check if there are multiple proposals with matching keys\n\t\t\tlet proposalSettled = false;\n\t\t\tlet proposalKeySeen = false;\n\t\t\tfor (const [, p] of this.proposals) {\n\t\t\t\tif (p.key === committedProposal.key) {\n\t\t\t\t\tif (!proposalKeySeen) {\n\t\t\t\t\t\t// set proposalSettled to true if the proposal key match is unique thus far\n\t\t\t\t\t\tproposalSettled = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// set proposalSettled to false if matching proposal key is not unique\n\t\t\t\t\t\tproposalSettled = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tproposalKeySeen = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.emit(\n\t\t\t\t\"approveProposal\",\n\t\t\t\tcommittedProposal.sequenceNumber,\n\t\t\t\tcommittedProposal.key,\n\t\t\t\tcommittedProposal.value,\n\t\t\t\tcommittedProposal.approvalSequenceNumber,\n\t\t\t);\n\n\t\t\t// emit approveProposalComplete when all pending proposals are processed\n\t\t\tif (proposalSettled) {\n\t\t\t\tthis.emit(\n\t\t\t\t\t\"approveProposalComplete\",\n\t\t\t\t\tcommittedProposal.sequenceNumber,\n\t\t\t\t\tcommittedProposal.key,\n\t\t\t\t\tcommittedProposal.value,\n\t\t\t\t\tcommittedProposal.approvalSequenceNumber,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.proposals.delete(proposal.sequenceNumber);\n\n\t\t\t// clear the proposals cache\n\t\t\tthis.proposalsSnapshotCache = undefined;\n\t\t\tif (proposal.local) {\n\t\t\t\tthis.stateEvents.emit(\"localProposalApproved\", proposal.sequenceNumber);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic setConnectionState(connected: boolean) {\n\t\tif (connected) {\n\t\t\tthis.stateEvents.emit(\"connected\");\n\t\t} else {\n\t\t\tthis.stateEvents.emit(\"disconnected\");\n\t\t}\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.isDisposed = true;\n\t\tthis.stateEvents.emit(\"disposed\");\n\t}\n}\n\n/**\n * A quorum represents all clients currently within the collaboration window. As well as the values\n * they have agreed upon and any pending proposals.\n * @internal\n */\nexport class Quorum extends TypedEventEmitter<IQuorum[\"on\"]> implements IQuorum {\n\tprivate readonly quorumClients: QuorumClients;\n\tprivate readonly quorumProposals: QuorumProposals;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed() {\n\t\treturn this.isDisposed;\n\t}\n\n\tconstructor(\n\t\tmembers: QuorumClientsSnapshot,\n\t\tproposals: QuorumProposalsSnapshot[\"proposals\"],\n\t\tvalues: QuorumProposalsSnapshot[\"values\"],\n\t\tsendProposal: (key: string, value: any) => number,\n\t) {\n\t\tsuper();\n\n\t\tthis.quorumClients = new QuorumClients(members);\n\t\tthis.quorumClients.on(\"addMember\", (clientId: string, details: ISequencedClient) => {\n\t\t\tthis.emit(\"addMember\", clientId, details);\n\t\t});\n\t\tthis.quorumClients.on(\"removeMember\", (clientId: string) => {\n\t\t\tthis.emit(\"removeMember\", clientId);\n\t\t});\n\n\t\tthis.quorumProposals = new QuorumProposals({ proposals, values }, sendProposal);\n\t\tthis.quorumProposals.on(\"addProposal\", (proposal: ISequencedProposal) => {\n\t\t\tthis.emit(\"addProposal\", proposal);\n\t\t});\n\t\tthis.quorumProposals.on(\n\t\t\t\"approveProposal\",\n\t\t\t(sequenceNumber: number, key: string, value: any, approvalSequenceNumber: number) => {\n\t\t\t\tthis.emit(\"approveProposal\", sequenceNumber, key, value, approvalSequenceNumber);\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic close() {\n\t\tthis.removeAllListeners();\n\t}\n\n\t/**\n\t * Snapshots the entire quorum\n\t * @returns a quorum snapshot\n\t */\n\tpublic snapshot(): IQuorumSnapshot {\n\t\tconst members = this.quorumClients.snapshot();\n\t\tconst { proposals, values } = this.quorumProposals.snapshot();\n\t\treturn {\n\t\t\tmembers,\n\t\t\tproposals,\n\t\t\tvalues,\n\t\t};\n\t}\n\n\t/**\n\t * Returns whether the quorum has achieved a consensus for the given key.\n\t */\n\tpublic has(key: string): boolean {\n\t\treturn this.quorumProposals.has(key);\n\t}\n\n\t/**\n\t * Returns the consensus value for the given key\n\t */\n\tpublic get(key: string): any {\n\t\treturn this.quorumProposals.get(key);\n\t}\n\n\t/**\n\t * Returns additional data about the approved consensus value\n\t * @deprecated Removed in recent protocol-definitions. Use get() instead.\n\t */\n\tpublic getApprovalData(key: string): ICommittedProposal | undefined {\n\t\treturn this.quorumProposals.getApprovalData(key);\n\t}\n\n\t/**\n\t * Adds a new client to the quorum\n\t */\n\tpublic addMember(clientId: string, details: ISequencedClient) {\n\t\tthis.quorumClients.addMember(clientId, details);\n\t}\n\n\t/**\n\t * Removes a client from the quorum\n\t */\n\tpublic removeMember(clientId: string) {\n\t\tthis.quorumClients.removeMember(clientId);\n\t}\n\n\t/**\n\t * Retrieves all the members in the quorum\n\t */\n\tpublic getMembers(): Map<string, ISequencedClient> {\n\t\treturn this.quorumClients.getMembers();\n\t}\n\n\t/**\n\t * Retrieves a specific member of the quorum\n\t */\n\tpublic getMember(clientId: string): ISequencedClient | undefined {\n\t\treturn this.quorumClients.getMember(clientId);\n\t}\n\n\t/**\n\t * Proposes a new value. Returns a promise that will resolve when the proposal is either accepted, or reject if\n\t * the proposal fails to send.\n\t */\n\tpublic async propose(key: string, value: any): Promise<void> {\n\t\treturn this.quorumProposals.propose(key, value);\n\t}\n\n\t/**\n\t * Begins tracking a new proposal\n\t */\n\tpublic addProposal(\n\t\tkey: string,\n\t\tvalue: any,\n\t\tsequenceNumber: number,\n\t\tlocal: boolean,\n\t\tclientSequenceNumber: number,\n\t) {\n\t\treturn this.quorumProposals.addProposal(\n\t\t\tkey,\n\t\t\tvalue,\n\t\t\tsequenceNumber,\n\t\t\tlocal,\n\t\t\tclientSequenceNumber,\n\t\t);\n\t}\n\n\t/**\n\t * Updates the minimum sequence number. If the MSN advances past the sequence number for any proposal then it\n\t * becomes an approved value.\n\t */\n\tpublic updateMinimumSequenceNumber(message: ISequencedDocumentMessage): void {\n\t\tthis.quorumProposals.updateMinimumSequenceNumber(message);\n\t}\n\n\tpublic setConnectionState(connected: boolean, clientId?: string) {\n\t\tthis.quorumProposals.setConnectionState(connected);\n\t}\n\n\tpublic dispose(): void {\n\t\tthrow new Error(\"Not implemented.\");\n\t\tthis.isDisposed = true;\n\t}\n}\n"]}
{
"name": "@fluidframework/protocol-base",
"version": "5.0.0-256582",
"version": "5.0.0-259221",
"description": "Fluid protocol base",

@@ -63,3 +63,3 @@ "homepage": "https://fluidframework.com",

"@fluidframework/common-utils": "^3.1.0",
"@fluidframework/gitresources": "5.0.0-256582",
"@fluidframework/gitresources": "5.0.0-259221",
"@fluidframework/protocol-definitions": "^3.2.0",

@@ -85,3 +85,3 @@ "events": "^3.1.0"

"rimraf": "^4.4.0",
"typescript": "~4.5.5"
"typescript": "~5.1.6"
},

@@ -88,0 +88,0 @@ "typeValidation": {