@fluid-experimental/pact-map 2.70.0-361092 → 2.70.0-361788
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pactMap.d.ts +4 -9
- package/dist/pactMap.d.ts.map +1 -1
- package/dist/pactMap.js +12 -11
- package/dist/pactMap.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pactMap.d.ts +4 -9
- package/lib/pactMap.d.ts.map +1 -1
- package/lib/pactMap.js +13 -12
- package/lib/pactMap.js.map +1 -1
- package/package.json +12 -12
- package/src/packageVersion.ts +1 -1
- package/src/pactMap.ts +33 -18
package/dist/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluid-experimental/pact-map";
|
|
8
|
-
export declare const pkgVersion = "2.70.0-
|
|
8
|
+
export declare const pkgVersion = "2.70.0-361788";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
package/dist/packageVersion.js
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.pkgVersion = exports.pkgName = void 0;
|
|
10
10
|
exports.pkgName = "@fluid-experimental/pact-map";
|
|
11
|
-
exports.pkgVersion = "2.70.0-
|
|
11
|
+
exports.pkgVersion = "2.70.0-361788";
|
|
12
12
|
//# sourceMappingURL=packageVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,8BAA8B,CAAC;AACzC,QAAA,UAAU,GAAG,eAAe,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluid-experimental/pact-map\";\nexport const pkgVersion = \"2.70.0-
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,8BAA8B,CAAC;AACzC,QAAA,UAAU,GAAG,eAAe,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluid-experimental/pact-map\";\nexport const pkgVersion = \"2.70.0-361788\";\n"]}
|
package/dist/pactMap.d.ts
CHANGED
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import type { IChannelAttributes, IFluidDataStoreRuntime, IChannelStorageService } from "@fluidframework/datastore-definitions/internal";
|
|
6
|
-
import {
|
|
7
|
-
import type { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions/internal";
|
|
6
|
+
import type { ISummaryTreeWithStats, IRuntimeMessageCollection } from "@fluidframework/runtime-definitions/internal";
|
|
8
7
|
import type { IFluidSerializer } from "@fluidframework/shared-object-base/internal";
|
|
9
8
|
import { SharedObject } from "@fluidframework/shared-object-base/internal";
|
|
10
9
|
import type { IAcceptedPact, IPactMap, IPactMapEvents } from "./interfaces.js";
|
|
@@ -79,14 +78,10 @@ export declare class PactMapClass<T = unknown> extends SharedObject<IPactMapEven
|
|
|
79
78
|
*/
|
|
80
79
|
protected reSubmitCore(content: unknown, localOpMetadata: unknown): void;
|
|
81
80
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* @param message - the message to prepare
|
|
85
|
-
* @param local - whether the message was sent by the local client
|
|
86
|
-
* @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.
|
|
87
|
-
* For messages from a remote client, this will be undefined.
|
|
81
|
+
* {@inheritDoc @fluidframework/shared-object-base#SharedObject.processMessagesCore}
|
|
88
82
|
*/
|
|
89
|
-
protected
|
|
83
|
+
protected processMessagesCore(messagesCollection: IRuntimeMessageCollection): void;
|
|
84
|
+
private processMessage;
|
|
90
85
|
protected applyStashedOp(): void;
|
|
91
86
|
}
|
|
92
87
|
//# sourceMappingURL=pactMap.d.ts.map
|
package/dist/pactMap.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pactMap.d.ts","sourceRoot":"","sources":["../src/pactMap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EACX,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,MAAM,gDAAgD,CAAC;
|
|
1
|
+
{"version":3,"file":"pactMap.d.ts","sourceRoot":"","sources":["../src/pactMap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EACX,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,MAAM,gDAAgD,CAAC;AAGxD,OAAO,KAAK,EACX,qBAAqB,EACrB,yBAAyB,EAGzB,MAAM,8CAA8C,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EACN,YAAY,EAEZ,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAyE/E;;GAEG;AACH,qBAAa,YAAY,CAAC,CAAC,GAAG,OAAO,CACpC,SAAQ,YAAY,CAAC,cAAc,CACnC,YAAW,QAAQ,CAAC,CAAC,CAAC;IAEtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8B;IAErD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoC;IAE/D;;;;;;OAMG;gBAEF,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,sBAAsB,EAC/B,UAAU,EAAE,kBAAkB;IAU/B;;OAEG;IACI,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAItC;;OAEG;IACI,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS;IAahE;;OAEG;IACI,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAItC;;OAEG;IACI,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAI7C;;OAEG;IACI,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,IAAI;IA4BnD;;OAEG;IACI,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAiBhC;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAsDhC;IAEF,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CA4BnC;IAEF,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAsBvC;IAEF;;;;OAIG;IACH,SAAS,CAAC,aAAa,CAAC,UAAU,EAAE,gBAAgB,GAAG,qBAAqB;IAK5E;;OAEG;cACa,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxE;;OAEG;IACH,SAAS,CAAC,mBAAmB,IAAI,IAAI;IAErC;;OAEG;IACH,SAAS,CAAC,YAAY,IAAI,IAAI;IAE9B;;OAEG;IACH,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,GAAG,IAAI;IAmBxE;;OAEG;IACH,SAAS,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,yBAAyB,GAAG,IAAI;IAOlF,OAAO,CAAC,cAAc;IAsCtB,SAAS,CAAC,cAAc,IAAI,IAAI;CAGhC"}
|
package/dist/pactMap.js
CHANGED
|
@@ -241,24 +241,25 @@ class PactMapClass extends internal_4.SharedObject {
|
|
|
241
241
|
this.submitLocalMessage(pactMapOp, localOpMetadata);
|
|
242
242
|
}
|
|
243
243
|
/**
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
* @param message - the message to prepare
|
|
247
|
-
* @param local - whether the message was sent by the local client
|
|
248
|
-
* @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.
|
|
249
|
-
* For messages from a remote client, this will be undefined.
|
|
244
|
+
* {@inheritDoc @fluidframework/shared-object-base#SharedObject.processMessagesCore}
|
|
250
245
|
*/
|
|
251
|
-
|
|
246
|
+
processMessagesCore(messagesCollection) {
|
|
247
|
+
const { envelope, local, messagesContent } = messagesCollection;
|
|
248
|
+
for (const messageContent of messagesContent) {
|
|
249
|
+
this.processMessage(envelope, messageContent, local);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
processMessage(messageEnvelope, messageContent, local) {
|
|
252
253
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
|
|
253
|
-
if (
|
|
254
|
-
const op =
|
|
254
|
+
if (messageEnvelope.type === internal_2.MessageType.Operation) {
|
|
255
|
+
const op = messageContent.contents;
|
|
255
256
|
switch (op.type) {
|
|
256
257
|
case "set": {
|
|
257
|
-
this.incomingOp.emit("set", op.key, op.value, op.refSeq,
|
|
258
|
+
this.incomingOp.emit("set", op.key, op.value, op.refSeq, messageEnvelope.sequenceNumber);
|
|
258
259
|
break;
|
|
259
260
|
}
|
|
260
261
|
case "accept": {
|
|
261
|
-
this.incomingOp.emit("accept", op.key,
|
|
262
|
+
this.incomingOp.emit("accept", op.key, messageEnvelope.clientId, messageEnvelope.sequenceNumber);
|
|
262
263
|
break;
|
|
263
264
|
}
|
|
264
265
|
default: {
|
package/dist/pactMap.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pactMap.js","sourceRoot":"","sources":["../src/pactMap.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 \"@fluid-internal/client-utils\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIChannelAttributes,\n\tIFluidDataStoreRuntime,\n\tIChannelStorageService,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport {\n\tMessageType,\n\ttype ISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { readAndParse } from \"@fluidframework/driver-utils/internal\";\nimport type { ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions/internal\";\nimport type { IFluidSerializer } from \"@fluidframework/shared-object-base/internal\";\nimport {\n\tSharedObject,\n\tcreateSingleBlobSummary,\n} from \"@fluidframework/shared-object-base/internal\";\n\nimport type { IAcceptedPact, IPactMap, IPactMapEvents } from \"./interfaces.js\";\n\n/**\n * The accepted pact information, if any.\n */\ninterface IAcceptedPactInternal<T> {\n\t/**\n\t * The accepted value of the given type or undefined (typically in case of delete).\n\t */\n\tvalue: T | undefined;\n\n\t/**\n\t * The sequence number when the value was accepted, which will normally coincide with one of two possibilities:\n\t * - The sequence number of the \"accept\" op from the final client we expected signoff from\n\t * - The sequence number of the ClientLeave of the final client we expected signoff from\n\t *\n\t * For values set in detached state, it will be 0.\n\t */\n\tsequenceNumber: number;\n}\n\n/**\n * The pending pact information, if any.\n */\ninterface IPendingPact<T> {\n\t/**\n\t * The pending value of the given type or undefined (typically in case of delete).\n\t */\n\tvalue: T | undefined;\n\t/**\n\t * The list of clientIds that we expect \"accept\" ops from. Clients are also removed from this list if they\n\t * disconnect without accepting. When this list empties, the pending value transitions to accepted.\n\t */\n\texpectedSignoffs: string[];\n}\n\n/**\n * Internal format of the values stored in the PactMap.\n */\ntype Pact<T> =\n\t| { accepted: IAcceptedPactInternal<T>; pending: undefined }\n\t| { accepted: undefined; pending: IPendingPact<T> }\n\t| { accepted: IAcceptedPactInternal<T>; pending: IPendingPact<T> };\n\n/**\n * PactMap operation formats\n */\ninterface IPactMapSetOperation<T> {\n\ttype: \"set\";\n\tkey: string;\n\tvalue: T | undefined;\n\n\t/**\n\t * A \"set\" is only valid if it is made with knowledge of the most-recent accepted proposal - its reference\n\t * sequence number is greater than or equal to the sequence number when that prior value was accepted.\n\t *\n\t * However, we can't trust the built-in referenceSequenceNumber of the op because of resubmit on reconnect,\n\t * which will update the referenceSequenceNumber on our behalf.\n\t *\n\t * Instead we need to separately stamp the real reference sequence number on the op itself.\n\t */\n\trefSeq: number;\n}\n\ninterface IPactMapAcceptOperation {\n\ttype: \"accept\";\n\tkey: string;\n}\n\ntype IPactMapOperation<T> = IPactMapSetOperation<T> | IPactMapAcceptOperation;\n\nconst snapshotFileName = \"header\";\n\n/**\n * {@inheritDoc PactMap}\n */\nexport class PactMapClass<T = unknown>\n\textends SharedObject<IPactMapEvents>\n\timplements IPactMap<T>\n{\n\tprivate readonly values = new Map<string, Pact<T>>();\n\n\tprivate readonly incomingOp: EventEmitter = new EventEmitter();\n\n\t/**\n\t * Constructs a new PactMap. If the object is non-local an id and service interfaces will\n\t * be provided\n\t *\n\t * @param runtime - data store runtime the PactMap belongs to\n\t * @param id - optional name of the PactMap\n\t */\n\tpublic constructor(\n\t\tid: string,\n\t\truntime: IFluidDataStoreRuntime,\n\t\tattributes: IChannelAttributes,\n\t) {\n\t\tsuper(id, runtime, attributes, \"fluid_pactMap_\");\n\n\t\tthis.incomingOp.on(\"set\", this.handleIncomingSet);\n\t\tthis.incomingOp.on(\"accept\", this.handleIncomingAccept);\n\n\t\tthis.runtime.getQuorum().on(\"removeMember\", this.handleQuorumRemoveMember);\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.get}\n\t */\n\tpublic get(key: string): T | undefined {\n\t\treturn this.values.get(key)?.accepted?.value;\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.getWithDetails}\n\t */\n\tpublic getWithDetails(key: string): IAcceptedPact<T> | undefined {\n\t\t// Note: We return type `IAcceptedPact` instead of `IAcceptedPactInternal` since we may want to diverge\n\t\t// the interfaces in the future.\n\t\tconst acceptedPact = this.values.get(key)?.accepted;\n\t\tif (acceptedPact === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn {\n\t\t\tvalue: acceptedPact.value,\n\t\t\tacceptedSequenceNumber: acceptedPact.sequenceNumber,\n\t\t};\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.isPending}\n\t */\n\tpublic isPending(key: string): boolean {\n\t\treturn this.values.get(key)?.pending !== undefined;\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.getPending}\n\t */\n\tpublic getPending(key: string): T | undefined {\n\t\treturn this.values.get(key)?.pending?.value;\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.set}\n\t */\n\tpublic set(key: string, value: T | undefined): void {\n\t\tconst currentValue = this.values.get(key);\n\t\t// Early-exit if we can't submit a valid proposal (there's already a pending proposal)\n\t\tif (currentValue?.pending !== undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If not attached, we basically pretend we got an ack immediately.\n\t\tif (!this.isAttached()) {\n\t\t\t// Queueing as a microtask to permit callers to complete their callstacks before the result of the set\n\t\t\t// takes effect. This more closely resembles the pattern in the attached state, where the ack will not\n\t\t\t// be received synchronously.\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tthis.handleIncomingSet(key, value, 0 /* refSeq */, 0 /* setSequenceNumber */);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst setOp: IPactMapSetOperation<T> = {\n\t\t\ttype: \"set\",\n\t\t\tkey,\n\t\t\tvalue,\n\t\t\trefSeq: this.deltaManager.lastSequenceNumber,\n\t\t};\n\n\t\tthis.submitLocalMessage(setOp);\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.delete}\n\t */\n\tpublic delete(key: string): void {\n\t\tconst currentValue = this.values.get(key);\n\t\t// Early-exit if:\n\t\tif (\n\t\t\t// there's nothing to delete\n\t\t\tcurrentValue === undefined ||\n\t\t\t// if something is pending (and so our proposal won't be valid)\n\t\t\tcurrentValue.pending !== undefined ||\n\t\t\t// or if the accepted value is undefined which is equivalent to already being deleted\n\t\t\tcurrentValue.accepted.value === undefined\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.set(key, undefined);\n\t}\n\n\t/**\n\t * Get a point-in-time list of clients who must sign off on values coming in for them to move from \"pending\" to\n\t * \"accepted\" state. This list is finalized for a value at the moment it goes pending (i.e. if more clients\n\t * join later, they are not added to the list of signoffs).\n\t * @returns The list of clientIds for clients who must sign off to accept the incoming pending value\n\t */\n\tprivate getSignoffClients(): string[] {\n\t\t// If detached, we don't need anyone to sign off. Otherwise, we need all currently connected clients.\n\t\treturn this.isAttached() ? [...this.runtime.getQuorum().getMembers().keys()] : [];\n\t}\n\n\tprivate readonly handleIncomingSet = (\n\t\tkey: string,\n\t\tvalue: T | undefined,\n\t\trefSeq: number,\n\t\tsetSequenceNumber: number,\n\t): void => {\n\t\tconst currentValue = this.values.get(key);\n\t\t// We use a consensus-like approach here, so a proposal is valid if the value is unset or if there is no\n\t\t// pending change and it was made with knowledge of the most recently accepted value. We'll drop invalid\n\t\t// proposals on the ground.\n\t\tconst proposalValid =\n\t\t\tcurrentValue === undefined ||\n\t\t\t(currentValue.pending === undefined && currentValue.accepted.sequenceNumber <= refSeq);\n\t\tif (!proposalValid) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst accepted = currentValue?.accepted;\n\n\t\t// We expect signoffs from all connected clients at the time the set was sequenced (including the client who\n\t\t// sent the set).\n\t\tconst expectedSignoffs = this.getSignoffClients();\n\n\t\tconst newPact: Pact<T> = {\n\t\t\taccepted,\n\t\t\tpending: {\n\t\t\t\tvalue,\n\t\t\t\texpectedSignoffs,\n\t\t\t},\n\t\t};\n\n\t\tthis.values.set(key, newPact);\n\n\t\tthis.emit(\"pending\", key);\n\n\t\tif (expectedSignoffs.length === 0) {\n\t\t\t// At least the submitting client should be amongst the expectedSignoffs, but keeping this check around\n\t\t\t// as extra protection and in case we bring back the \"submitting client implicitly accepts\" optimization.\n\t\t\tthis.values.set(key, {\n\t\t\t\taccepted: { value, sequenceNumber: setSequenceNumber },\n\t\t\t\tpending: undefined,\n\t\t\t});\n\t\t\tthis.emit(\"accepted\", key);\n\t\t} else if (\n\t\t\tthis.runtime.clientId !== undefined &&\n\t\t\texpectedSignoffs.includes(this.runtime.clientId)\n\t\t) {\n\t\t\t// Emit an accept upon a new key entering pending state if our accept is expected.\n\t\t\tconst acceptOp: IPactMapAcceptOperation = {\n\t\t\t\ttype: \"accept\",\n\t\t\t\tkey,\n\t\t\t};\n\t\t\tthis.submitLocalMessage(acceptOp);\n\t\t}\n\t};\n\n\tprivate readonly handleIncomingAccept = (\n\t\tkey: string,\n\t\tclientId: string,\n\t\tsequenceNumber: number,\n\t): void => {\n\t\tconst pending = this.values.get(key)?.pending;\n\t\tif (pending === undefined) {\n\t\t\t// If there is no pending value, we already accepted it, so we can ignore the accept op.\n\t\t\treturn;\n\t\t}\n\t\tassert(\n\t\t\tpending.expectedSignoffs.includes(clientId),\n\t\t\t0x2f9 /* Unexpected accept op, client not in expectedSignoffs */,\n\t\t);\n\n\t\t// Remove the client from the expected signoffs\n\t\tpending.expectedSignoffs = pending.expectedSignoffs.filter(\n\t\t\t(expectedClientId) => expectedClientId !== clientId,\n\t\t);\n\n\t\tif (pending.expectedSignoffs.length === 0) {\n\t\t\t// The pending value has settled\n\t\t\tthis.values.set(key, {\n\t\t\t\taccepted: { value: pending.value, sequenceNumber },\n\t\t\t\tpending: undefined,\n\t\t\t});\n\t\t\tthis.emit(\"accepted\", key);\n\t\t}\n\t};\n\n\tprivate readonly handleQuorumRemoveMember = (clientId: string): void => {\n\t\tfor (const [key, { pending }] of this.values) {\n\t\t\tif (pending !== undefined) {\n\t\t\t\tpending.expectedSignoffs = pending.expectedSignoffs.filter(\n\t\t\t\t\t(expectedClientId) => expectedClientId !== clientId,\n\t\t\t\t);\n\n\t\t\t\tif (pending.expectedSignoffs.length === 0) {\n\t\t\t\t\t// The pending value has settled\n\t\t\t\t\tconst clientLeaveSequenceNumber = this.deltaManager.lastSequenceNumber;\n\t\t\t\t\tthis.values.set(key, {\n\t\t\t\t\t\taccepted: {\n\t\t\t\t\t\t\tvalue: pending.value,\n\t\t\t\t\t\t\t// The sequence number of the ClientLeave message.\n\t\t\t\t\t\t\tsequenceNumber: clientLeaveSequenceNumber,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tpending: undefined,\n\t\t\t\t\t});\n\t\t\t\t\tthis.emit(\"accepted\", key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Create a summary for the PactMap\n\t *\n\t * @returns the summary of the current state of the PactMap\n\t */\n\tprotected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats {\n\t\tconst allEntries = [...this.values.entries()];\n\t\treturn createSingleBlobSummary(snapshotFileName, JSON.stringify(allEntries));\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}\n\t */\n\tprotected async loadCore(storage: IChannelStorageService): Promise<void> {\n\t\tconst content = await readAndParse<[string, Pact<T>][]>(storage, snapshotFileName);\n\t\tfor (const [key, value] of content) {\n\t\t\tthis.values.set(key, value);\n\t\t}\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.initializeLocalCore}\n\t */\n\tprotected initializeLocalCore(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.onDisconnect}\n\t */\n\tprotected onDisconnect(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.reSubmitCore}\n\t */\n\tprotected reSubmitCore(content: unknown, localOpMetadata: unknown): void {\n\t\tconst pactMapOp = content as IPactMapOperation<T>;\n\n\t\t// Filter out set messages that have no chance of being accepted because there's another value pending\n\t\t// or another value was accepted while we were disconnected.\n\t\tconst currentValue = this.values.get(pactMapOp.key);\n\t\tif (\n\t\t\tpactMapOp.type === \"set\" &&\n\t\t\tcurrentValue !== undefined &&\n\t\t\t(currentValue.pending !== undefined ||\n\t\t\t\tpactMapOp.refSeq < currentValue.accepted?.sequenceNumber)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Otherwise we can resubmit\n\t\tthis.submitLocalMessage(pactMapOp, localOpMetadata);\n\t}\n\n\t/**\n\t * Process a PactMap operation\n\t *\n\t * @param message - the message to prepare\n\t * @param local - whether the message was sent by the local client\n\t * @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.\n\t * For messages from a remote client, this will be undefined.\n\t */\n\tprotected processCore(\n\t\tmessage: ISequencedDocumentMessage,\n\t\tlocal: boolean,\n\t\tlocalOpMetadata: unknown,\n\t): void {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison\n\t\tif (message.type === MessageType.Operation) {\n\t\t\tconst op = message.contents as IPactMapOperation<T>;\n\n\t\t\tswitch (op.type) {\n\t\t\t\tcase \"set\": {\n\t\t\t\t\tthis.incomingOp.emit(\"set\", op.key, op.value, op.refSeq, message.sequenceNumber);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"accept\": {\n\t\t\t\t\tthis.incomingOp.emit(\"accept\", op.key, message.clientId, message.sequenceNumber);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault: {\n\t\t\t\t\tthrow new Error(\"Unknown operation\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected applyStashedOp(): void {\n\t\tthrow new Error(\"not implemented\");\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"pactMap.js","sourceRoot":"","sources":["../src/pactMap.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 \"@fluid-internal/client-utils\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIChannelAttributes,\n\tIFluidDataStoreRuntime,\n\tIChannelStorageService,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport { MessageType } from \"@fluidframework/driver-definitions/internal\";\nimport { readAndParse } from \"@fluidframework/driver-utils/internal\";\nimport type {\n\tISummaryTreeWithStats,\n\tIRuntimeMessageCollection,\n\tIRuntimeMessagesContent,\n\tISequencedMessageEnvelope,\n} from \"@fluidframework/runtime-definitions/internal\";\nimport type { IFluidSerializer } from \"@fluidframework/shared-object-base/internal\";\nimport {\n\tSharedObject,\n\tcreateSingleBlobSummary,\n} from \"@fluidframework/shared-object-base/internal\";\n\nimport type { IAcceptedPact, IPactMap, IPactMapEvents } from \"./interfaces.js\";\n\n/**\n * The accepted pact information, if any.\n */\ninterface IAcceptedPactInternal<T> {\n\t/**\n\t * The accepted value of the given type or undefined (typically in case of delete).\n\t */\n\tvalue: T | undefined;\n\n\t/**\n\t * The sequence number when the value was accepted, which will normally coincide with one of two possibilities:\n\t * - The sequence number of the \"accept\" op from the final client we expected signoff from\n\t * - The sequence number of the ClientLeave of the final client we expected signoff from\n\t *\n\t * For values set in detached state, it will be 0.\n\t */\n\tsequenceNumber: number;\n}\n\n/**\n * The pending pact information, if any.\n */\ninterface IPendingPact<T> {\n\t/**\n\t * The pending value of the given type or undefined (typically in case of delete).\n\t */\n\tvalue: T | undefined;\n\t/**\n\t * The list of clientIds that we expect \"accept\" ops from. Clients are also removed from this list if they\n\t * disconnect without accepting. When this list empties, the pending value transitions to accepted.\n\t */\n\texpectedSignoffs: string[];\n}\n\n/**\n * Internal format of the values stored in the PactMap.\n */\ntype Pact<T> =\n\t| { accepted: IAcceptedPactInternal<T>; pending: undefined }\n\t| { accepted: undefined; pending: IPendingPact<T> }\n\t| { accepted: IAcceptedPactInternal<T>; pending: IPendingPact<T> };\n\n/**\n * PactMap operation formats\n */\ninterface IPactMapSetOperation<T> {\n\ttype: \"set\";\n\tkey: string;\n\tvalue: T | undefined;\n\n\t/**\n\t * A \"set\" is only valid if it is made with knowledge of the most-recent accepted proposal - its reference\n\t * sequence number is greater than or equal to the sequence number when that prior value was accepted.\n\t *\n\t * However, we can't trust the built-in referenceSequenceNumber of the op because of resubmit on reconnect,\n\t * which will update the referenceSequenceNumber on our behalf.\n\t *\n\t * Instead we need to separately stamp the real reference sequence number on the op itself.\n\t */\n\trefSeq: number;\n}\n\ninterface IPactMapAcceptOperation {\n\ttype: \"accept\";\n\tkey: string;\n}\n\ntype IPactMapOperation<T> = IPactMapSetOperation<T> | IPactMapAcceptOperation;\n\nconst snapshotFileName = \"header\";\n\n/**\n * {@inheritDoc PactMap}\n */\nexport class PactMapClass<T = unknown>\n\textends SharedObject<IPactMapEvents>\n\timplements IPactMap<T>\n{\n\tprivate readonly values = new Map<string, Pact<T>>();\n\n\tprivate readonly incomingOp: EventEmitter = new EventEmitter();\n\n\t/**\n\t * Constructs a new PactMap. If the object is non-local an id and service interfaces will\n\t * be provided\n\t *\n\t * @param runtime - data store runtime the PactMap belongs to\n\t * @param id - optional name of the PactMap\n\t */\n\tpublic constructor(\n\t\tid: string,\n\t\truntime: IFluidDataStoreRuntime,\n\t\tattributes: IChannelAttributes,\n\t) {\n\t\tsuper(id, runtime, attributes, \"fluid_pactMap_\");\n\n\t\tthis.incomingOp.on(\"set\", this.handleIncomingSet);\n\t\tthis.incomingOp.on(\"accept\", this.handleIncomingAccept);\n\n\t\tthis.runtime.getQuorum().on(\"removeMember\", this.handleQuorumRemoveMember);\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.get}\n\t */\n\tpublic get(key: string): T | undefined {\n\t\treturn this.values.get(key)?.accepted?.value;\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.getWithDetails}\n\t */\n\tpublic getWithDetails(key: string): IAcceptedPact<T> | undefined {\n\t\t// Note: We return type `IAcceptedPact` instead of `IAcceptedPactInternal` since we may want to diverge\n\t\t// the interfaces in the future.\n\t\tconst acceptedPact = this.values.get(key)?.accepted;\n\t\tif (acceptedPact === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn {\n\t\t\tvalue: acceptedPact.value,\n\t\t\tacceptedSequenceNumber: acceptedPact.sequenceNumber,\n\t\t};\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.isPending}\n\t */\n\tpublic isPending(key: string): boolean {\n\t\treturn this.values.get(key)?.pending !== undefined;\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.getPending}\n\t */\n\tpublic getPending(key: string): T | undefined {\n\t\treturn this.values.get(key)?.pending?.value;\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.set}\n\t */\n\tpublic set(key: string, value: T | undefined): void {\n\t\tconst currentValue = this.values.get(key);\n\t\t// Early-exit if we can't submit a valid proposal (there's already a pending proposal)\n\t\tif (currentValue?.pending !== undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If not attached, we basically pretend we got an ack immediately.\n\t\tif (!this.isAttached()) {\n\t\t\t// Queueing as a microtask to permit callers to complete their callstacks before the result of the set\n\t\t\t// takes effect. This more closely resembles the pattern in the attached state, where the ack will not\n\t\t\t// be received synchronously.\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tthis.handleIncomingSet(key, value, 0 /* refSeq */, 0 /* setSequenceNumber */);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst setOp: IPactMapSetOperation<T> = {\n\t\t\ttype: \"set\",\n\t\t\tkey,\n\t\t\tvalue,\n\t\t\trefSeq: this.deltaManager.lastSequenceNumber,\n\t\t};\n\n\t\tthis.submitLocalMessage(setOp);\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.delete}\n\t */\n\tpublic delete(key: string): void {\n\t\tconst currentValue = this.values.get(key);\n\t\t// Early-exit if:\n\t\tif (\n\t\t\t// there's nothing to delete\n\t\t\tcurrentValue === undefined ||\n\t\t\t// if something is pending (and so our proposal won't be valid)\n\t\t\tcurrentValue.pending !== undefined ||\n\t\t\t// or if the accepted value is undefined which is equivalent to already being deleted\n\t\t\tcurrentValue.accepted.value === undefined\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.set(key, undefined);\n\t}\n\n\t/**\n\t * Get a point-in-time list of clients who must sign off on values coming in for them to move from \"pending\" to\n\t * \"accepted\" state. This list is finalized for a value at the moment it goes pending (i.e. if more clients\n\t * join later, they are not added to the list of signoffs).\n\t * @returns The list of clientIds for clients who must sign off to accept the incoming pending value\n\t */\n\tprivate getSignoffClients(): string[] {\n\t\t// If detached, we don't need anyone to sign off. Otherwise, we need all currently connected clients.\n\t\treturn this.isAttached() ? [...this.runtime.getQuorum().getMembers().keys()] : [];\n\t}\n\n\tprivate readonly handleIncomingSet = (\n\t\tkey: string,\n\t\tvalue: T | undefined,\n\t\trefSeq: number,\n\t\tsetSequenceNumber: number,\n\t): void => {\n\t\tconst currentValue = this.values.get(key);\n\t\t// We use a consensus-like approach here, so a proposal is valid if the value is unset or if there is no\n\t\t// pending change and it was made with knowledge of the most recently accepted value. We'll drop invalid\n\t\t// proposals on the ground.\n\t\tconst proposalValid =\n\t\t\tcurrentValue === undefined ||\n\t\t\t(currentValue.pending === undefined && currentValue.accepted.sequenceNumber <= refSeq);\n\t\tif (!proposalValid) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst accepted = currentValue?.accepted;\n\n\t\t// We expect signoffs from all connected clients at the time the set was sequenced (including the client who\n\t\t// sent the set).\n\t\tconst expectedSignoffs = this.getSignoffClients();\n\n\t\tconst newPact: Pact<T> = {\n\t\t\taccepted,\n\t\t\tpending: {\n\t\t\t\tvalue,\n\t\t\t\texpectedSignoffs,\n\t\t\t},\n\t\t};\n\n\t\tthis.values.set(key, newPact);\n\n\t\tthis.emit(\"pending\", key);\n\n\t\tif (expectedSignoffs.length === 0) {\n\t\t\t// At least the submitting client should be amongst the expectedSignoffs, but keeping this check around\n\t\t\t// as extra protection and in case we bring back the \"submitting client implicitly accepts\" optimization.\n\t\t\tthis.values.set(key, {\n\t\t\t\taccepted: { value, sequenceNumber: setSequenceNumber },\n\t\t\t\tpending: undefined,\n\t\t\t});\n\t\t\tthis.emit(\"accepted\", key);\n\t\t} else if (\n\t\t\tthis.runtime.clientId !== undefined &&\n\t\t\texpectedSignoffs.includes(this.runtime.clientId)\n\t\t) {\n\t\t\t// Emit an accept upon a new key entering pending state if our accept is expected.\n\t\t\tconst acceptOp: IPactMapAcceptOperation = {\n\t\t\t\ttype: \"accept\",\n\t\t\t\tkey,\n\t\t\t};\n\t\t\tthis.submitLocalMessage(acceptOp);\n\t\t}\n\t};\n\n\tprivate readonly handleIncomingAccept = (\n\t\tkey: string,\n\t\tclientId: string,\n\t\tsequenceNumber: number,\n\t): void => {\n\t\tconst pending = this.values.get(key)?.pending;\n\t\tif (pending === undefined) {\n\t\t\t// If there is no pending value, we already accepted it, so we can ignore the accept op.\n\t\t\treturn;\n\t\t}\n\t\tassert(\n\t\t\tpending.expectedSignoffs.includes(clientId),\n\t\t\t0x2f9 /* Unexpected accept op, client not in expectedSignoffs */,\n\t\t);\n\n\t\t// Remove the client from the expected signoffs\n\t\tpending.expectedSignoffs = pending.expectedSignoffs.filter(\n\t\t\t(expectedClientId) => expectedClientId !== clientId,\n\t\t);\n\n\t\tif (pending.expectedSignoffs.length === 0) {\n\t\t\t// The pending value has settled\n\t\t\tthis.values.set(key, {\n\t\t\t\taccepted: { value: pending.value, sequenceNumber },\n\t\t\t\tpending: undefined,\n\t\t\t});\n\t\t\tthis.emit(\"accepted\", key);\n\t\t}\n\t};\n\n\tprivate readonly handleQuorumRemoveMember = (clientId: string): void => {\n\t\tfor (const [key, { pending }] of this.values) {\n\t\t\tif (pending !== undefined) {\n\t\t\t\tpending.expectedSignoffs = pending.expectedSignoffs.filter(\n\t\t\t\t\t(expectedClientId) => expectedClientId !== clientId,\n\t\t\t\t);\n\n\t\t\t\tif (pending.expectedSignoffs.length === 0) {\n\t\t\t\t\t// The pending value has settled\n\t\t\t\t\tconst clientLeaveSequenceNumber = this.deltaManager.lastSequenceNumber;\n\t\t\t\t\tthis.values.set(key, {\n\t\t\t\t\t\taccepted: {\n\t\t\t\t\t\t\tvalue: pending.value,\n\t\t\t\t\t\t\t// The sequence number of the ClientLeave message.\n\t\t\t\t\t\t\tsequenceNumber: clientLeaveSequenceNumber,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tpending: undefined,\n\t\t\t\t\t});\n\t\t\t\t\tthis.emit(\"accepted\", key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Create a summary for the PactMap\n\t *\n\t * @returns the summary of the current state of the PactMap\n\t */\n\tprotected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats {\n\t\tconst allEntries = [...this.values.entries()];\n\t\treturn createSingleBlobSummary(snapshotFileName, JSON.stringify(allEntries));\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}\n\t */\n\tprotected async loadCore(storage: IChannelStorageService): Promise<void> {\n\t\tconst content = await readAndParse<[string, Pact<T>][]>(storage, snapshotFileName);\n\t\tfor (const [key, value] of content) {\n\t\t\tthis.values.set(key, value);\n\t\t}\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.initializeLocalCore}\n\t */\n\tprotected initializeLocalCore(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.onDisconnect}\n\t */\n\tprotected onDisconnect(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.reSubmitCore}\n\t */\n\tprotected reSubmitCore(content: unknown, localOpMetadata: unknown): void {\n\t\tconst pactMapOp = content as IPactMapOperation<T>;\n\n\t\t// Filter out set messages that have no chance of being accepted because there's another value pending\n\t\t// or another value was accepted while we were disconnected.\n\t\tconst currentValue = this.values.get(pactMapOp.key);\n\t\tif (\n\t\t\tpactMapOp.type === \"set\" &&\n\t\t\tcurrentValue !== undefined &&\n\t\t\t(currentValue.pending !== undefined ||\n\t\t\t\tpactMapOp.refSeq < currentValue.accepted?.sequenceNumber)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Otherwise we can resubmit\n\t\tthis.submitLocalMessage(pactMapOp, localOpMetadata);\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.processMessagesCore}\n\t */\n\tprotected processMessagesCore(messagesCollection: IRuntimeMessageCollection): void {\n\t\tconst { envelope, local, messagesContent } = messagesCollection;\n\t\tfor (const messageContent of messagesContent) {\n\t\t\tthis.processMessage(envelope, messageContent, local);\n\t\t}\n\t}\n\n\tprivate processMessage(\n\t\tmessageEnvelope: ISequencedMessageEnvelope,\n\t\tmessageContent: IRuntimeMessagesContent,\n\t\tlocal: boolean,\n\t): void {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison\n\t\tif (messageEnvelope.type === MessageType.Operation) {\n\t\t\tconst op = messageContent.contents as IPactMapOperation<T>;\n\n\t\t\tswitch (op.type) {\n\t\t\t\tcase \"set\": {\n\t\t\t\t\tthis.incomingOp.emit(\n\t\t\t\t\t\t\"set\",\n\t\t\t\t\t\top.key,\n\t\t\t\t\t\top.value,\n\t\t\t\t\t\top.refSeq,\n\t\t\t\t\t\tmessageEnvelope.sequenceNumber,\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"accept\": {\n\t\t\t\t\tthis.incomingOp.emit(\n\t\t\t\t\t\t\"accept\",\n\t\t\t\t\t\top.key,\n\t\t\t\t\t\tmessageEnvelope.clientId,\n\t\t\t\t\t\tmessageEnvelope.sequenceNumber,\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault: {\n\t\t\t\t\tthrow new Error(\"Unknown operation\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected applyStashedOp(): void {\n\t\tthrow new Error(\"not implemented\");\n\t}\n}\n"]}
|
package/lib/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluid-experimental/pact-map";
|
|
8
|
-
export declare const pkgVersion = "2.70.0-
|
|
8
|
+
export declare const pkgVersion = "2.70.0-361788";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
package/lib/packageVersion.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,8BAA8B,CAAC;AACtD,MAAM,CAAC,MAAM,UAAU,GAAG,eAAe,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluid-experimental/pact-map\";\nexport const pkgVersion = \"2.70.0-
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,8BAA8B,CAAC;AACtD,MAAM,CAAC,MAAM,UAAU,GAAG,eAAe,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluid-experimental/pact-map\";\nexport const pkgVersion = \"2.70.0-361788\";\n"]}
|
package/lib/pactMap.d.ts
CHANGED
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import type { IChannelAttributes, IFluidDataStoreRuntime, IChannelStorageService } from "@fluidframework/datastore-definitions/internal";
|
|
6
|
-
import {
|
|
7
|
-
import type { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions/internal";
|
|
6
|
+
import type { ISummaryTreeWithStats, IRuntimeMessageCollection } from "@fluidframework/runtime-definitions/internal";
|
|
8
7
|
import type { IFluidSerializer } from "@fluidframework/shared-object-base/internal";
|
|
9
8
|
import { SharedObject } from "@fluidframework/shared-object-base/internal";
|
|
10
9
|
import type { IAcceptedPact, IPactMap, IPactMapEvents } from "./interfaces.js";
|
|
@@ -79,14 +78,10 @@ export declare class PactMapClass<T = unknown> extends SharedObject<IPactMapEven
|
|
|
79
78
|
*/
|
|
80
79
|
protected reSubmitCore(content: unknown, localOpMetadata: unknown): void;
|
|
81
80
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* @param message - the message to prepare
|
|
85
|
-
* @param local - whether the message was sent by the local client
|
|
86
|
-
* @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.
|
|
87
|
-
* For messages from a remote client, this will be undefined.
|
|
81
|
+
* {@inheritDoc @fluidframework/shared-object-base#SharedObject.processMessagesCore}
|
|
88
82
|
*/
|
|
89
|
-
protected
|
|
83
|
+
protected processMessagesCore(messagesCollection: IRuntimeMessageCollection): void;
|
|
84
|
+
private processMessage;
|
|
90
85
|
protected applyStashedOp(): void;
|
|
91
86
|
}
|
|
92
87
|
//# sourceMappingURL=pactMap.d.ts.map
|
package/lib/pactMap.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pactMap.d.ts","sourceRoot":"","sources":["../src/pactMap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EACX,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,MAAM,gDAAgD,CAAC;
|
|
1
|
+
{"version":3,"file":"pactMap.d.ts","sourceRoot":"","sources":["../src/pactMap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EACX,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,MAAM,gDAAgD,CAAC;AAGxD,OAAO,KAAK,EACX,qBAAqB,EACrB,yBAAyB,EAGzB,MAAM,8CAA8C,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EACN,YAAY,EAEZ,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAyE/E;;GAEG;AACH,qBAAa,YAAY,CAAC,CAAC,GAAG,OAAO,CACpC,SAAQ,YAAY,CAAC,cAAc,CACnC,YAAW,QAAQ,CAAC,CAAC,CAAC;IAEtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8B;IAErD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoC;IAE/D;;;;;;OAMG;gBAEF,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,sBAAsB,EAC/B,UAAU,EAAE,kBAAkB;IAU/B;;OAEG;IACI,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAItC;;OAEG;IACI,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS;IAahE;;OAEG;IACI,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAItC;;OAEG;IACI,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAI7C;;OAEG;IACI,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,IAAI;IA4BnD;;OAEG;IACI,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAiBhC;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAsDhC;IAEF,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CA4BnC;IAEF,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAsBvC;IAEF;;;;OAIG;IACH,SAAS,CAAC,aAAa,CAAC,UAAU,EAAE,gBAAgB,GAAG,qBAAqB;IAK5E;;OAEG;cACa,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxE;;OAEG;IACH,SAAS,CAAC,mBAAmB,IAAI,IAAI;IAErC;;OAEG;IACH,SAAS,CAAC,YAAY,IAAI,IAAI;IAE9B;;OAEG;IACH,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,GAAG,IAAI;IAmBxE;;OAEG;IACH,SAAS,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,yBAAyB,GAAG,IAAI;IAOlF,OAAO,CAAC,cAAc;IAsCtB,SAAS,CAAC,cAAc,IAAI,IAAI;CAGhC"}
|
package/lib/pactMap.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { EventEmitter } from "@fluid-internal/client-utils";
|
|
6
6
|
import { assert } from "@fluidframework/core-utils/internal";
|
|
7
|
-
import { MessageType
|
|
7
|
+
import { MessageType } from "@fluidframework/driver-definitions/internal";
|
|
8
8
|
import { readAndParse } from "@fluidframework/driver-utils/internal";
|
|
9
9
|
import { SharedObject, createSingleBlobSummary, } from "@fluidframework/shared-object-base/internal";
|
|
10
10
|
const snapshotFileName = "header";
|
|
@@ -238,24 +238,25 @@ export class PactMapClass extends SharedObject {
|
|
|
238
238
|
this.submitLocalMessage(pactMapOp, localOpMetadata);
|
|
239
239
|
}
|
|
240
240
|
/**
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
* @param message - the message to prepare
|
|
244
|
-
* @param local - whether the message was sent by the local client
|
|
245
|
-
* @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.
|
|
246
|
-
* For messages from a remote client, this will be undefined.
|
|
241
|
+
* {@inheritDoc @fluidframework/shared-object-base#SharedObject.processMessagesCore}
|
|
247
242
|
*/
|
|
248
|
-
|
|
243
|
+
processMessagesCore(messagesCollection) {
|
|
244
|
+
const { envelope, local, messagesContent } = messagesCollection;
|
|
245
|
+
for (const messageContent of messagesContent) {
|
|
246
|
+
this.processMessage(envelope, messageContent, local);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
processMessage(messageEnvelope, messageContent, local) {
|
|
249
250
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
|
|
250
|
-
if (
|
|
251
|
-
const op =
|
|
251
|
+
if (messageEnvelope.type === MessageType.Operation) {
|
|
252
|
+
const op = messageContent.contents;
|
|
252
253
|
switch (op.type) {
|
|
253
254
|
case "set": {
|
|
254
|
-
this.incomingOp.emit("set", op.key, op.value, op.refSeq,
|
|
255
|
+
this.incomingOp.emit("set", op.key, op.value, op.refSeq, messageEnvelope.sequenceNumber);
|
|
255
256
|
break;
|
|
256
257
|
}
|
|
257
258
|
case "accept": {
|
|
258
|
-
this.incomingOp.emit("accept", op.key,
|
|
259
|
+
this.incomingOp.emit("accept", op.key, messageEnvelope.clientId, messageEnvelope.sequenceNumber);
|
|
259
260
|
break;
|
|
260
261
|
}
|
|
261
262
|
default: {
|
package/lib/pactMap.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pactMap.js","sourceRoot":"","sources":["../src/pactMap.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 \"@fluid-internal/client-utils\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIChannelAttributes,\n\tIFluidDataStoreRuntime,\n\tIChannelStorageService,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport {\n\tMessageType,\n\ttype ISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { readAndParse } from \"@fluidframework/driver-utils/internal\";\nimport type { ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions/internal\";\nimport type { IFluidSerializer } from \"@fluidframework/shared-object-base/internal\";\nimport {\n\tSharedObject,\n\tcreateSingleBlobSummary,\n} from \"@fluidframework/shared-object-base/internal\";\n\nimport type { IAcceptedPact, IPactMap, IPactMapEvents } from \"./interfaces.js\";\n\n/**\n * The accepted pact information, if any.\n */\ninterface IAcceptedPactInternal<T> {\n\t/**\n\t * The accepted value of the given type or undefined (typically in case of delete).\n\t */\n\tvalue: T | undefined;\n\n\t/**\n\t * The sequence number when the value was accepted, which will normally coincide with one of two possibilities:\n\t * - The sequence number of the \"accept\" op from the final client we expected signoff from\n\t * - The sequence number of the ClientLeave of the final client we expected signoff from\n\t *\n\t * For values set in detached state, it will be 0.\n\t */\n\tsequenceNumber: number;\n}\n\n/**\n * The pending pact information, if any.\n */\ninterface IPendingPact<T> {\n\t/**\n\t * The pending value of the given type or undefined (typically in case of delete).\n\t */\n\tvalue: T | undefined;\n\t/**\n\t * The list of clientIds that we expect \"accept\" ops from. Clients are also removed from this list if they\n\t * disconnect without accepting. When this list empties, the pending value transitions to accepted.\n\t */\n\texpectedSignoffs: string[];\n}\n\n/**\n * Internal format of the values stored in the PactMap.\n */\ntype Pact<T> =\n\t| { accepted: IAcceptedPactInternal<T>; pending: undefined }\n\t| { accepted: undefined; pending: IPendingPact<T> }\n\t| { accepted: IAcceptedPactInternal<T>; pending: IPendingPact<T> };\n\n/**\n * PactMap operation formats\n */\ninterface IPactMapSetOperation<T> {\n\ttype: \"set\";\n\tkey: string;\n\tvalue: T | undefined;\n\n\t/**\n\t * A \"set\" is only valid if it is made with knowledge of the most-recent accepted proposal - its reference\n\t * sequence number is greater than or equal to the sequence number when that prior value was accepted.\n\t *\n\t * However, we can't trust the built-in referenceSequenceNumber of the op because of resubmit on reconnect,\n\t * which will update the referenceSequenceNumber on our behalf.\n\t *\n\t * Instead we need to separately stamp the real reference sequence number on the op itself.\n\t */\n\trefSeq: number;\n}\n\ninterface IPactMapAcceptOperation {\n\ttype: \"accept\";\n\tkey: string;\n}\n\ntype IPactMapOperation<T> = IPactMapSetOperation<T> | IPactMapAcceptOperation;\n\nconst snapshotFileName = \"header\";\n\n/**\n * {@inheritDoc PactMap}\n */\nexport class PactMapClass<T = unknown>\n\textends SharedObject<IPactMapEvents>\n\timplements IPactMap<T>\n{\n\tprivate readonly values = new Map<string, Pact<T>>();\n\n\tprivate readonly incomingOp: EventEmitter = new EventEmitter();\n\n\t/**\n\t * Constructs a new PactMap. If the object is non-local an id and service interfaces will\n\t * be provided\n\t *\n\t * @param runtime - data store runtime the PactMap belongs to\n\t * @param id - optional name of the PactMap\n\t */\n\tpublic constructor(\n\t\tid: string,\n\t\truntime: IFluidDataStoreRuntime,\n\t\tattributes: IChannelAttributes,\n\t) {\n\t\tsuper(id, runtime, attributes, \"fluid_pactMap_\");\n\n\t\tthis.incomingOp.on(\"set\", this.handleIncomingSet);\n\t\tthis.incomingOp.on(\"accept\", this.handleIncomingAccept);\n\n\t\tthis.runtime.getQuorum().on(\"removeMember\", this.handleQuorumRemoveMember);\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.get}\n\t */\n\tpublic get(key: string): T | undefined {\n\t\treturn this.values.get(key)?.accepted?.value;\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.getWithDetails}\n\t */\n\tpublic getWithDetails(key: string): IAcceptedPact<T> | undefined {\n\t\t// Note: We return type `IAcceptedPact` instead of `IAcceptedPactInternal` since we may want to diverge\n\t\t// the interfaces in the future.\n\t\tconst acceptedPact = this.values.get(key)?.accepted;\n\t\tif (acceptedPact === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn {\n\t\t\tvalue: acceptedPact.value,\n\t\t\tacceptedSequenceNumber: acceptedPact.sequenceNumber,\n\t\t};\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.isPending}\n\t */\n\tpublic isPending(key: string): boolean {\n\t\treturn this.values.get(key)?.pending !== undefined;\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.getPending}\n\t */\n\tpublic getPending(key: string): T | undefined {\n\t\treturn this.values.get(key)?.pending?.value;\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.set}\n\t */\n\tpublic set(key: string, value: T | undefined): void {\n\t\tconst currentValue = this.values.get(key);\n\t\t// Early-exit if we can't submit a valid proposal (there's already a pending proposal)\n\t\tif (currentValue?.pending !== undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If not attached, we basically pretend we got an ack immediately.\n\t\tif (!this.isAttached()) {\n\t\t\t// Queueing as a microtask to permit callers to complete their callstacks before the result of the set\n\t\t\t// takes effect. This more closely resembles the pattern in the attached state, where the ack will not\n\t\t\t// be received synchronously.\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tthis.handleIncomingSet(key, value, 0 /* refSeq */, 0 /* setSequenceNumber */);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst setOp: IPactMapSetOperation<T> = {\n\t\t\ttype: \"set\",\n\t\t\tkey,\n\t\t\tvalue,\n\t\t\trefSeq: this.deltaManager.lastSequenceNumber,\n\t\t};\n\n\t\tthis.submitLocalMessage(setOp);\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.delete}\n\t */\n\tpublic delete(key: string): void {\n\t\tconst currentValue = this.values.get(key);\n\t\t// Early-exit if:\n\t\tif (\n\t\t\t// there's nothing to delete\n\t\t\tcurrentValue === undefined ||\n\t\t\t// if something is pending (and so our proposal won't be valid)\n\t\t\tcurrentValue.pending !== undefined ||\n\t\t\t// or if the accepted value is undefined which is equivalent to already being deleted\n\t\t\tcurrentValue.accepted.value === undefined\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.set(key, undefined);\n\t}\n\n\t/**\n\t * Get a point-in-time list of clients who must sign off on values coming in for them to move from \"pending\" to\n\t * \"accepted\" state. This list is finalized for a value at the moment it goes pending (i.e. if more clients\n\t * join later, they are not added to the list of signoffs).\n\t * @returns The list of clientIds for clients who must sign off to accept the incoming pending value\n\t */\n\tprivate getSignoffClients(): string[] {\n\t\t// If detached, we don't need anyone to sign off. Otherwise, we need all currently connected clients.\n\t\treturn this.isAttached() ? [...this.runtime.getQuorum().getMembers().keys()] : [];\n\t}\n\n\tprivate readonly handleIncomingSet = (\n\t\tkey: string,\n\t\tvalue: T | undefined,\n\t\trefSeq: number,\n\t\tsetSequenceNumber: number,\n\t): void => {\n\t\tconst currentValue = this.values.get(key);\n\t\t// We use a consensus-like approach here, so a proposal is valid if the value is unset or if there is no\n\t\t// pending change and it was made with knowledge of the most recently accepted value. We'll drop invalid\n\t\t// proposals on the ground.\n\t\tconst proposalValid =\n\t\t\tcurrentValue === undefined ||\n\t\t\t(currentValue.pending === undefined && currentValue.accepted.sequenceNumber <= refSeq);\n\t\tif (!proposalValid) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst accepted = currentValue?.accepted;\n\n\t\t// We expect signoffs from all connected clients at the time the set was sequenced (including the client who\n\t\t// sent the set).\n\t\tconst expectedSignoffs = this.getSignoffClients();\n\n\t\tconst newPact: Pact<T> = {\n\t\t\taccepted,\n\t\t\tpending: {\n\t\t\t\tvalue,\n\t\t\t\texpectedSignoffs,\n\t\t\t},\n\t\t};\n\n\t\tthis.values.set(key, newPact);\n\n\t\tthis.emit(\"pending\", key);\n\n\t\tif (expectedSignoffs.length === 0) {\n\t\t\t// At least the submitting client should be amongst the expectedSignoffs, but keeping this check around\n\t\t\t// as extra protection and in case we bring back the \"submitting client implicitly accepts\" optimization.\n\t\t\tthis.values.set(key, {\n\t\t\t\taccepted: { value, sequenceNumber: setSequenceNumber },\n\t\t\t\tpending: undefined,\n\t\t\t});\n\t\t\tthis.emit(\"accepted\", key);\n\t\t} else if (\n\t\t\tthis.runtime.clientId !== undefined &&\n\t\t\texpectedSignoffs.includes(this.runtime.clientId)\n\t\t) {\n\t\t\t// Emit an accept upon a new key entering pending state if our accept is expected.\n\t\t\tconst acceptOp: IPactMapAcceptOperation = {\n\t\t\t\ttype: \"accept\",\n\t\t\t\tkey,\n\t\t\t};\n\t\t\tthis.submitLocalMessage(acceptOp);\n\t\t}\n\t};\n\n\tprivate readonly handleIncomingAccept = (\n\t\tkey: string,\n\t\tclientId: string,\n\t\tsequenceNumber: number,\n\t): void => {\n\t\tconst pending = this.values.get(key)?.pending;\n\t\tif (pending === undefined) {\n\t\t\t// If there is no pending value, we already accepted it, so we can ignore the accept op.\n\t\t\treturn;\n\t\t}\n\t\tassert(\n\t\t\tpending.expectedSignoffs.includes(clientId),\n\t\t\t0x2f9 /* Unexpected accept op, client not in expectedSignoffs */,\n\t\t);\n\n\t\t// Remove the client from the expected signoffs\n\t\tpending.expectedSignoffs = pending.expectedSignoffs.filter(\n\t\t\t(expectedClientId) => expectedClientId !== clientId,\n\t\t);\n\n\t\tif (pending.expectedSignoffs.length === 0) {\n\t\t\t// The pending value has settled\n\t\t\tthis.values.set(key, {\n\t\t\t\taccepted: { value: pending.value, sequenceNumber },\n\t\t\t\tpending: undefined,\n\t\t\t});\n\t\t\tthis.emit(\"accepted\", key);\n\t\t}\n\t};\n\n\tprivate readonly handleQuorumRemoveMember = (clientId: string): void => {\n\t\tfor (const [key, { pending }] of this.values) {\n\t\t\tif (pending !== undefined) {\n\t\t\t\tpending.expectedSignoffs = pending.expectedSignoffs.filter(\n\t\t\t\t\t(expectedClientId) => expectedClientId !== clientId,\n\t\t\t\t);\n\n\t\t\t\tif (pending.expectedSignoffs.length === 0) {\n\t\t\t\t\t// The pending value has settled\n\t\t\t\t\tconst clientLeaveSequenceNumber = this.deltaManager.lastSequenceNumber;\n\t\t\t\t\tthis.values.set(key, {\n\t\t\t\t\t\taccepted: {\n\t\t\t\t\t\t\tvalue: pending.value,\n\t\t\t\t\t\t\t// The sequence number of the ClientLeave message.\n\t\t\t\t\t\t\tsequenceNumber: clientLeaveSequenceNumber,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tpending: undefined,\n\t\t\t\t\t});\n\t\t\t\t\tthis.emit(\"accepted\", key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Create a summary for the PactMap\n\t *\n\t * @returns the summary of the current state of the PactMap\n\t */\n\tprotected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats {\n\t\tconst allEntries = [...this.values.entries()];\n\t\treturn createSingleBlobSummary(snapshotFileName, JSON.stringify(allEntries));\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}\n\t */\n\tprotected async loadCore(storage: IChannelStorageService): Promise<void> {\n\t\tconst content = await readAndParse<[string, Pact<T>][]>(storage, snapshotFileName);\n\t\tfor (const [key, value] of content) {\n\t\t\tthis.values.set(key, value);\n\t\t}\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.initializeLocalCore}\n\t */\n\tprotected initializeLocalCore(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.onDisconnect}\n\t */\n\tprotected onDisconnect(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.reSubmitCore}\n\t */\n\tprotected reSubmitCore(content: unknown, localOpMetadata: unknown): void {\n\t\tconst pactMapOp = content as IPactMapOperation<T>;\n\n\t\t// Filter out set messages that have no chance of being accepted because there's another value pending\n\t\t// or another value was accepted while we were disconnected.\n\t\tconst currentValue = this.values.get(pactMapOp.key);\n\t\tif (\n\t\t\tpactMapOp.type === \"set\" &&\n\t\t\tcurrentValue !== undefined &&\n\t\t\t(currentValue.pending !== undefined ||\n\t\t\t\tpactMapOp.refSeq < currentValue.accepted?.sequenceNumber)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Otherwise we can resubmit\n\t\tthis.submitLocalMessage(pactMapOp, localOpMetadata);\n\t}\n\n\t/**\n\t * Process a PactMap operation\n\t *\n\t * @param message - the message to prepare\n\t * @param local - whether the message was sent by the local client\n\t * @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.\n\t * For messages from a remote client, this will be undefined.\n\t */\n\tprotected processCore(\n\t\tmessage: ISequencedDocumentMessage,\n\t\tlocal: boolean,\n\t\tlocalOpMetadata: unknown,\n\t): void {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison\n\t\tif (message.type === MessageType.Operation) {\n\t\t\tconst op = message.contents as IPactMapOperation<T>;\n\n\t\t\tswitch (op.type) {\n\t\t\t\tcase \"set\": {\n\t\t\t\t\tthis.incomingOp.emit(\"set\", op.key, op.value, op.refSeq, message.sequenceNumber);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"accept\": {\n\t\t\t\t\tthis.incomingOp.emit(\"accept\", op.key, message.clientId, message.sequenceNumber);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault: {\n\t\t\t\t\tthrow new Error(\"Unknown operation\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected applyStashedOp(): void {\n\t\tthrow new Error(\"not implemented\");\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"pactMap.js","sourceRoot":"","sources":["../src/pactMap.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 \"@fluid-internal/client-utils\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIChannelAttributes,\n\tIFluidDataStoreRuntime,\n\tIChannelStorageService,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport { MessageType } from \"@fluidframework/driver-definitions/internal\";\nimport { readAndParse } from \"@fluidframework/driver-utils/internal\";\nimport type {\n\tISummaryTreeWithStats,\n\tIRuntimeMessageCollection,\n\tIRuntimeMessagesContent,\n\tISequencedMessageEnvelope,\n} from \"@fluidframework/runtime-definitions/internal\";\nimport type { IFluidSerializer } from \"@fluidframework/shared-object-base/internal\";\nimport {\n\tSharedObject,\n\tcreateSingleBlobSummary,\n} from \"@fluidframework/shared-object-base/internal\";\n\nimport type { IAcceptedPact, IPactMap, IPactMapEvents } from \"./interfaces.js\";\n\n/**\n * The accepted pact information, if any.\n */\ninterface IAcceptedPactInternal<T> {\n\t/**\n\t * The accepted value of the given type or undefined (typically in case of delete).\n\t */\n\tvalue: T | undefined;\n\n\t/**\n\t * The sequence number when the value was accepted, which will normally coincide with one of two possibilities:\n\t * - The sequence number of the \"accept\" op from the final client we expected signoff from\n\t * - The sequence number of the ClientLeave of the final client we expected signoff from\n\t *\n\t * For values set in detached state, it will be 0.\n\t */\n\tsequenceNumber: number;\n}\n\n/**\n * The pending pact information, if any.\n */\ninterface IPendingPact<T> {\n\t/**\n\t * The pending value of the given type or undefined (typically in case of delete).\n\t */\n\tvalue: T | undefined;\n\t/**\n\t * The list of clientIds that we expect \"accept\" ops from. Clients are also removed from this list if they\n\t * disconnect without accepting. When this list empties, the pending value transitions to accepted.\n\t */\n\texpectedSignoffs: string[];\n}\n\n/**\n * Internal format of the values stored in the PactMap.\n */\ntype Pact<T> =\n\t| { accepted: IAcceptedPactInternal<T>; pending: undefined }\n\t| { accepted: undefined; pending: IPendingPact<T> }\n\t| { accepted: IAcceptedPactInternal<T>; pending: IPendingPact<T> };\n\n/**\n * PactMap operation formats\n */\ninterface IPactMapSetOperation<T> {\n\ttype: \"set\";\n\tkey: string;\n\tvalue: T | undefined;\n\n\t/**\n\t * A \"set\" is only valid if it is made with knowledge of the most-recent accepted proposal - its reference\n\t * sequence number is greater than or equal to the sequence number when that prior value was accepted.\n\t *\n\t * However, we can't trust the built-in referenceSequenceNumber of the op because of resubmit on reconnect,\n\t * which will update the referenceSequenceNumber on our behalf.\n\t *\n\t * Instead we need to separately stamp the real reference sequence number on the op itself.\n\t */\n\trefSeq: number;\n}\n\ninterface IPactMapAcceptOperation {\n\ttype: \"accept\";\n\tkey: string;\n}\n\ntype IPactMapOperation<T> = IPactMapSetOperation<T> | IPactMapAcceptOperation;\n\nconst snapshotFileName = \"header\";\n\n/**\n * {@inheritDoc PactMap}\n */\nexport class PactMapClass<T = unknown>\n\textends SharedObject<IPactMapEvents>\n\timplements IPactMap<T>\n{\n\tprivate readonly values = new Map<string, Pact<T>>();\n\n\tprivate readonly incomingOp: EventEmitter = new EventEmitter();\n\n\t/**\n\t * Constructs a new PactMap. If the object is non-local an id and service interfaces will\n\t * be provided\n\t *\n\t * @param runtime - data store runtime the PactMap belongs to\n\t * @param id - optional name of the PactMap\n\t */\n\tpublic constructor(\n\t\tid: string,\n\t\truntime: IFluidDataStoreRuntime,\n\t\tattributes: IChannelAttributes,\n\t) {\n\t\tsuper(id, runtime, attributes, \"fluid_pactMap_\");\n\n\t\tthis.incomingOp.on(\"set\", this.handleIncomingSet);\n\t\tthis.incomingOp.on(\"accept\", this.handleIncomingAccept);\n\n\t\tthis.runtime.getQuorum().on(\"removeMember\", this.handleQuorumRemoveMember);\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.get}\n\t */\n\tpublic get(key: string): T | undefined {\n\t\treturn this.values.get(key)?.accepted?.value;\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.getWithDetails}\n\t */\n\tpublic getWithDetails(key: string): IAcceptedPact<T> | undefined {\n\t\t// Note: We return type `IAcceptedPact` instead of `IAcceptedPactInternal` since we may want to diverge\n\t\t// the interfaces in the future.\n\t\tconst acceptedPact = this.values.get(key)?.accepted;\n\t\tif (acceptedPact === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn {\n\t\t\tvalue: acceptedPact.value,\n\t\t\tacceptedSequenceNumber: acceptedPact.sequenceNumber,\n\t\t};\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.isPending}\n\t */\n\tpublic isPending(key: string): boolean {\n\t\treturn this.values.get(key)?.pending !== undefined;\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.getPending}\n\t */\n\tpublic getPending(key: string): T | undefined {\n\t\treturn this.values.get(key)?.pending?.value;\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.set}\n\t */\n\tpublic set(key: string, value: T | undefined): void {\n\t\tconst currentValue = this.values.get(key);\n\t\t// Early-exit if we can't submit a valid proposal (there's already a pending proposal)\n\t\tif (currentValue?.pending !== undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If not attached, we basically pretend we got an ack immediately.\n\t\tif (!this.isAttached()) {\n\t\t\t// Queueing as a microtask to permit callers to complete their callstacks before the result of the set\n\t\t\t// takes effect. This more closely resembles the pattern in the attached state, where the ack will not\n\t\t\t// be received synchronously.\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tthis.handleIncomingSet(key, value, 0 /* refSeq */, 0 /* setSequenceNumber */);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst setOp: IPactMapSetOperation<T> = {\n\t\t\ttype: \"set\",\n\t\t\tkey,\n\t\t\tvalue,\n\t\t\trefSeq: this.deltaManager.lastSequenceNumber,\n\t\t};\n\n\t\tthis.submitLocalMessage(setOp);\n\t}\n\n\t/**\n\t * {@inheritDoc IPactMap.delete}\n\t */\n\tpublic delete(key: string): void {\n\t\tconst currentValue = this.values.get(key);\n\t\t// Early-exit if:\n\t\tif (\n\t\t\t// there's nothing to delete\n\t\t\tcurrentValue === undefined ||\n\t\t\t// if something is pending (and so our proposal won't be valid)\n\t\t\tcurrentValue.pending !== undefined ||\n\t\t\t// or if the accepted value is undefined which is equivalent to already being deleted\n\t\t\tcurrentValue.accepted.value === undefined\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.set(key, undefined);\n\t}\n\n\t/**\n\t * Get a point-in-time list of clients who must sign off on values coming in for them to move from \"pending\" to\n\t * \"accepted\" state. This list is finalized for a value at the moment it goes pending (i.e. if more clients\n\t * join later, they are not added to the list of signoffs).\n\t * @returns The list of clientIds for clients who must sign off to accept the incoming pending value\n\t */\n\tprivate getSignoffClients(): string[] {\n\t\t// If detached, we don't need anyone to sign off. Otherwise, we need all currently connected clients.\n\t\treturn this.isAttached() ? [...this.runtime.getQuorum().getMembers().keys()] : [];\n\t}\n\n\tprivate readonly handleIncomingSet = (\n\t\tkey: string,\n\t\tvalue: T | undefined,\n\t\trefSeq: number,\n\t\tsetSequenceNumber: number,\n\t): void => {\n\t\tconst currentValue = this.values.get(key);\n\t\t// We use a consensus-like approach here, so a proposal is valid if the value is unset or if there is no\n\t\t// pending change and it was made with knowledge of the most recently accepted value. We'll drop invalid\n\t\t// proposals on the ground.\n\t\tconst proposalValid =\n\t\t\tcurrentValue === undefined ||\n\t\t\t(currentValue.pending === undefined && currentValue.accepted.sequenceNumber <= refSeq);\n\t\tif (!proposalValid) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst accepted = currentValue?.accepted;\n\n\t\t// We expect signoffs from all connected clients at the time the set was sequenced (including the client who\n\t\t// sent the set).\n\t\tconst expectedSignoffs = this.getSignoffClients();\n\n\t\tconst newPact: Pact<T> = {\n\t\t\taccepted,\n\t\t\tpending: {\n\t\t\t\tvalue,\n\t\t\t\texpectedSignoffs,\n\t\t\t},\n\t\t};\n\n\t\tthis.values.set(key, newPact);\n\n\t\tthis.emit(\"pending\", key);\n\n\t\tif (expectedSignoffs.length === 0) {\n\t\t\t// At least the submitting client should be amongst the expectedSignoffs, but keeping this check around\n\t\t\t// as extra protection and in case we bring back the \"submitting client implicitly accepts\" optimization.\n\t\t\tthis.values.set(key, {\n\t\t\t\taccepted: { value, sequenceNumber: setSequenceNumber },\n\t\t\t\tpending: undefined,\n\t\t\t});\n\t\t\tthis.emit(\"accepted\", key);\n\t\t} else if (\n\t\t\tthis.runtime.clientId !== undefined &&\n\t\t\texpectedSignoffs.includes(this.runtime.clientId)\n\t\t) {\n\t\t\t// Emit an accept upon a new key entering pending state if our accept is expected.\n\t\t\tconst acceptOp: IPactMapAcceptOperation = {\n\t\t\t\ttype: \"accept\",\n\t\t\t\tkey,\n\t\t\t};\n\t\t\tthis.submitLocalMessage(acceptOp);\n\t\t}\n\t};\n\n\tprivate readonly handleIncomingAccept = (\n\t\tkey: string,\n\t\tclientId: string,\n\t\tsequenceNumber: number,\n\t): void => {\n\t\tconst pending = this.values.get(key)?.pending;\n\t\tif (pending === undefined) {\n\t\t\t// If there is no pending value, we already accepted it, so we can ignore the accept op.\n\t\t\treturn;\n\t\t}\n\t\tassert(\n\t\t\tpending.expectedSignoffs.includes(clientId),\n\t\t\t0x2f9 /* Unexpected accept op, client not in expectedSignoffs */,\n\t\t);\n\n\t\t// Remove the client from the expected signoffs\n\t\tpending.expectedSignoffs = pending.expectedSignoffs.filter(\n\t\t\t(expectedClientId) => expectedClientId !== clientId,\n\t\t);\n\n\t\tif (pending.expectedSignoffs.length === 0) {\n\t\t\t// The pending value has settled\n\t\t\tthis.values.set(key, {\n\t\t\t\taccepted: { value: pending.value, sequenceNumber },\n\t\t\t\tpending: undefined,\n\t\t\t});\n\t\t\tthis.emit(\"accepted\", key);\n\t\t}\n\t};\n\n\tprivate readonly handleQuorumRemoveMember = (clientId: string): void => {\n\t\tfor (const [key, { pending }] of this.values) {\n\t\t\tif (pending !== undefined) {\n\t\t\t\tpending.expectedSignoffs = pending.expectedSignoffs.filter(\n\t\t\t\t\t(expectedClientId) => expectedClientId !== clientId,\n\t\t\t\t);\n\n\t\t\t\tif (pending.expectedSignoffs.length === 0) {\n\t\t\t\t\t// The pending value has settled\n\t\t\t\t\tconst clientLeaveSequenceNumber = this.deltaManager.lastSequenceNumber;\n\t\t\t\t\tthis.values.set(key, {\n\t\t\t\t\t\taccepted: {\n\t\t\t\t\t\t\tvalue: pending.value,\n\t\t\t\t\t\t\t// The sequence number of the ClientLeave message.\n\t\t\t\t\t\t\tsequenceNumber: clientLeaveSequenceNumber,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tpending: undefined,\n\t\t\t\t\t});\n\t\t\t\t\tthis.emit(\"accepted\", key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Create a summary for the PactMap\n\t *\n\t * @returns the summary of the current state of the PactMap\n\t */\n\tprotected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats {\n\t\tconst allEntries = [...this.values.entries()];\n\t\treturn createSingleBlobSummary(snapshotFileName, JSON.stringify(allEntries));\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}\n\t */\n\tprotected async loadCore(storage: IChannelStorageService): Promise<void> {\n\t\tconst content = await readAndParse<[string, Pact<T>][]>(storage, snapshotFileName);\n\t\tfor (const [key, value] of content) {\n\t\t\tthis.values.set(key, value);\n\t\t}\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.initializeLocalCore}\n\t */\n\tprotected initializeLocalCore(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.onDisconnect}\n\t */\n\tprotected onDisconnect(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.reSubmitCore}\n\t */\n\tprotected reSubmitCore(content: unknown, localOpMetadata: unknown): void {\n\t\tconst pactMapOp = content as IPactMapOperation<T>;\n\n\t\t// Filter out set messages that have no chance of being accepted because there's another value pending\n\t\t// or another value was accepted while we were disconnected.\n\t\tconst currentValue = this.values.get(pactMapOp.key);\n\t\tif (\n\t\t\tpactMapOp.type === \"set\" &&\n\t\t\tcurrentValue !== undefined &&\n\t\t\t(currentValue.pending !== undefined ||\n\t\t\t\tpactMapOp.refSeq < currentValue.accepted?.sequenceNumber)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Otherwise we can resubmit\n\t\tthis.submitLocalMessage(pactMapOp, localOpMetadata);\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.processMessagesCore}\n\t */\n\tprotected processMessagesCore(messagesCollection: IRuntimeMessageCollection): void {\n\t\tconst { envelope, local, messagesContent } = messagesCollection;\n\t\tfor (const messageContent of messagesContent) {\n\t\t\tthis.processMessage(envelope, messageContent, local);\n\t\t}\n\t}\n\n\tprivate processMessage(\n\t\tmessageEnvelope: ISequencedMessageEnvelope,\n\t\tmessageContent: IRuntimeMessagesContent,\n\t\tlocal: boolean,\n\t): void {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison\n\t\tif (messageEnvelope.type === MessageType.Operation) {\n\t\t\tconst op = messageContent.contents as IPactMapOperation<T>;\n\n\t\t\tswitch (op.type) {\n\t\t\t\tcase \"set\": {\n\t\t\t\t\tthis.incomingOp.emit(\n\t\t\t\t\t\t\"set\",\n\t\t\t\t\t\top.key,\n\t\t\t\t\t\top.value,\n\t\t\t\t\t\top.refSeq,\n\t\t\t\t\t\tmessageEnvelope.sequenceNumber,\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"accept\": {\n\t\t\t\t\tthis.incomingOp.emit(\n\t\t\t\t\t\t\"accept\",\n\t\t\t\t\t\top.key,\n\t\t\t\t\t\tmessageEnvelope.clientId,\n\t\t\t\t\t\tmessageEnvelope.sequenceNumber,\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault: {\n\t\t\t\t\tthrow new Error(\"Unknown operation\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected applyStashedOp(): void {\n\t\tthrow new Error(\"not implemented\");\n\t}\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluid-experimental/pact-map",
|
|
3
|
-
"version": "2.70.0-
|
|
3
|
+
"version": "2.70.0-361788",
|
|
4
4
|
"description": "Distributed data structure for key-value pairs using pact consensus",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -49,25 +49,25 @@
|
|
|
49
49
|
"temp-directory": "nyc/.nyc_output"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@fluid-internal/client-utils": "2.70.0-
|
|
53
|
-
"@fluidframework/core-interfaces": "2.70.0-
|
|
54
|
-
"@fluidframework/core-utils": "2.70.0-
|
|
55
|
-
"@fluidframework/datastore-definitions": "2.70.0-
|
|
56
|
-
"@fluidframework/driver-definitions": "2.70.0-
|
|
57
|
-
"@fluidframework/driver-utils": "2.70.0-
|
|
58
|
-
"@fluidframework/runtime-definitions": "2.70.0-
|
|
59
|
-
"@fluidframework/shared-object-base": "2.70.0-
|
|
52
|
+
"@fluid-internal/client-utils": "2.70.0-361788",
|
|
53
|
+
"@fluidframework/core-interfaces": "2.70.0-361788",
|
|
54
|
+
"@fluidframework/core-utils": "2.70.0-361788",
|
|
55
|
+
"@fluidframework/datastore-definitions": "2.70.0-361788",
|
|
56
|
+
"@fluidframework/driver-definitions": "2.70.0-361788",
|
|
57
|
+
"@fluidframework/driver-utils": "2.70.0-361788",
|
|
58
|
+
"@fluidframework/runtime-definitions": "2.70.0-361788",
|
|
59
|
+
"@fluidframework/shared-object-base": "2.70.0-361788"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@arethetypeswrong/cli": "^0.17.1",
|
|
63
63
|
"@biomejs/biome": "~1.9.3",
|
|
64
|
-
"@fluid-internal/mocha-test-setup": "2.70.0-
|
|
65
|
-
"@fluid-private/test-dds-utils": "2.70.0-
|
|
64
|
+
"@fluid-internal/mocha-test-setup": "2.70.0-361788",
|
|
65
|
+
"@fluid-private/test-dds-utils": "2.70.0-361788",
|
|
66
66
|
"@fluid-tools/build-cli": "^0.58.3",
|
|
67
67
|
"@fluidframework/build-common": "^2.0.3",
|
|
68
68
|
"@fluidframework/build-tools": "^0.58.3",
|
|
69
69
|
"@fluidframework/eslint-config-fluid": "^6.1.0",
|
|
70
|
-
"@fluidframework/test-runtime-utils": "2.70.0-
|
|
70
|
+
"@fluidframework/test-runtime-utils": "2.70.0-361788",
|
|
71
71
|
"@microsoft/api-extractor": "7.52.11",
|
|
72
72
|
"@types/mocha": "^10.0.10",
|
|
73
73
|
"@types/node": "^18.19.0",
|
package/src/packageVersion.ts
CHANGED
package/src/pactMap.ts
CHANGED
|
@@ -10,12 +10,14 @@ import type {
|
|
|
10
10
|
IFluidDataStoreRuntime,
|
|
11
11
|
IChannelStorageService,
|
|
12
12
|
} from "@fluidframework/datastore-definitions/internal";
|
|
13
|
-
import {
|
|
14
|
-
MessageType,
|
|
15
|
-
type ISequencedDocumentMessage,
|
|
16
|
-
} from "@fluidframework/driver-definitions/internal";
|
|
13
|
+
import { MessageType } from "@fluidframework/driver-definitions/internal";
|
|
17
14
|
import { readAndParse } from "@fluidframework/driver-utils/internal";
|
|
18
|
-
import type {
|
|
15
|
+
import type {
|
|
16
|
+
ISummaryTreeWithStats,
|
|
17
|
+
IRuntimeMessageCollection,
|
|
18
|
+
IRuntimeMessagesContent,
|
|
19
|
+
ISequencedMessageEnvelope,
|
|
20
|
+
} from "@fluidframework/runtime-definitions/internal";
|
|
19
21
|
import type { IFluidSerializer } from "@fluidframework/shared-object-base/internal";
|
|
20
22
|
import {
|
|
21
23
|
SharedObject,
|
|
@@ -388,30 +390,43 @@ export class PactMapClass<T = unknown>
|
|
|
388
390
|
}
|
|
389
391
|
|
|
390
392
|
/**
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
* @param message - the message to prepare
|
|
394
|
-
* @param local - whether the message was sent by the local client
|
|
395
|
-
* @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.
|
|
396
|
-
* For messages from a remote client, this will be undefined.
|
|
393
|
+
* {@inheritDoc @fluidframework/shared-object-base#SharedObject.processMessagesCore}
|
|
397
394
|
*/
|
|
398
|
-
protected
|
|
399
|
-
|
|
395
|
+
protected processMessagesCore(messagesCollection: IRuntimeMessageCollection): void {
|
|
396
|
+
const { envelope, local, messagesContent } = messagesCollection;
|
|
397
|
+
for (const messageContent of messagesContent) {
|
|
398
|
+
this.processMessage(envelope, messageContent, local);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
private processMessage(
|
|
403
|
+
messageEnvelope: ISequencedMessageEnvelope,
|
|
404
|
+
messageContent: IRuntimeMessagesContent,
|
|
400
405
|
local: boolean,
|
|
401
|
-
localOpMetadata: unknown,
|
|
402
406
|
): void {
|
|
403
407
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
|
|
404
|
-
if (
|
|
405
|
-
const op =
|
|
408
|
+
if (messageEnvelope.type === MessageType.Operation) {
|
|
409
|
+
const op = messageContent.contents as IPactMapOperation<T>;
|
|
406
410
|
|
|
407
411
|
switch (op.type) {
|
|
408
412
|
case "set": {
|
|
409
|
-
this.incomingOp.emit(
|
|
413
|
+
this.incomingOp.emit(
|
|
414
|
+
"set",
|
|
415
|
+
op.key,
|
|
416
|
+
op.value,
|
|
417
|
+
op.refSeq,
|
|
418
|
+
messageEnvelope.sequenceNumber,
|
|
419
|
+
);
|
|
410
420
|
break;
|
|
411
421
|
}
|
|
412
422
|
|
|
413
423
|
case "accept": {
|
|
414
|
-
this.incomingOp.emit(
|
|
424
|
+
this.incomingOp.emit(
|
|
425
|
+
"accept",
|
|
426
|
+
op.key,
|
|
427
|
+
messageEnvelope.clientId,
|
|
428
|
+
messageEnvelope.sequenceNumber,
|
|
429
|
+
);
|
|
415
430
|
break;
|
|
416
431
|
}
|
|
417
432
|
|