@fluid-experimental/pact-map 3.4.0 → 3.6.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @fluid-experimental/pact-map
2
2
 
3
+ ## 3.6.0
4
+
5
+ Dependency updates only.
6
+
7
+ ## 3.5.0
8
+
9
+ Dependency updates only.
10
+
3
11
  ## 3.4.0
4
12
 
5
13
  Dependency updates only.
@@ -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 = "3.4.0";
8
+ export declare const pkgVersion = "3.6.0";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -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 = "3.4.0";
11
+ exports.pkgVersion = "3.6.0";
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,OAAO,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 = \"3.4.0\";\n"]}
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,OAAO,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 = \"3.6.0\";\n"]}
package/dist/pactMap.d.ts CHANGED
@@ -21,29 +21,11 @@ export declare class PactMapClass<T = unknown> extends SharedObject<IPactMapEven
21
21
  * @param id - optional name of the PactMap
22
22
  */
23
23
  constructor(id: string, runtime: IFluidDataStoreRuntime, attributes: IChannelAttributes);
24
- /**
25
- * {@inheritDoc IPactMap.get}
26
- */
27
24
  get(key: string): T | undefined;
28
- /**
29
- * {@inheritDoc IPactMap.getWithDetails}
30
- */
31
25
  getWithDetails(key: string): IAcceptedPact<T> | undefined;
32
- /**
33
- * {@inheritDoc IPactMap.isPending}
34
- */
35
26
  isPending(key: string): boolean;
36
- /**
37
- * {@inheritDoc IPactMap.getPending}
38
- */
39
27
  getPending(key: string): T | undefined;
40
- /**
41
- * {@inheritDoc IPactMap.set}
42
- */
43
28
  set(key: string, value: T | undefined): void;
44
- /**
45
- * {@inheritDoc IPactMap.delete}
46
- */
47
29
  delete(key: string): void;
48
30
  /**
49
31
  * Get a point-in-time list of clients who must sign off on values coming in for them to move from "pending" to
@@ -61,21 +43,9 @@ export declare class PactMapClass<T = unknown> extends SharedObject<IPactMapEven
61
43
  * @returns the summary of the current state of the PactMap
62
44
  */
63
45
  protected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats;
64
- /**
65
- * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}
66
- */
67
46
  protected loadCore(storage: IChannelStorageService): Promise<void>;
68
- /**
69
- * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.initializeLocalCore}
70
- */
71
47
  protected initializeLocalCore(): void;
72
- /**
73
- * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.onDisconnect}
74
- */
75
48
  protected onDisconnect(): void;
76
- /**
77
- * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.reSubmitCore}
78
- */
79
49
  protected reSubmitCore(content: unknown, localOpMetadata: unknown): void;
80
50
  protected processMessagesCore(messagesCollection: IRuntimeMessageCollection): void;
81
51
  private processMessage;
@@ -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;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;cAmBrD,mBAAmB,CAAC,kBAAkB,EAAE,yBAAyB,GAAG,IAAI;IAO3F,OAAO,CAAC,cAAc;IAsCtB,SAAS,CAAC,cAAc,IAAI,IAAI;CAGhC"}
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;IAUxB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAI/B,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS;IAazD,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI/B,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAItC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,IAAI;IA4B5C,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;cAK5D,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxE,SAAS,CAAC,mBAAmB,IAAI,IAAI;IAErC,SAAS,CAAC,YAAY,IAAI,IAAI;IAE9B,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,GAAG,IAAI;cAmBrD,mBAAmB,CAAC,kBAAkB,EAAE,yBAAyB,GAAG,IAAI;IAO3F,OAAO,CAAC,cAAc;IAsCtB,SAAS,CAAC,cAAc,IAAI,IAAI;CAGhC"}
package/dist/pactMap.js CHANGED
@@ -30,15 +30,9 @@ class PactMapClass extends internal_4.SharedObject {
30
30
  this.incomingOp.on("accept", this.handleIncomingAccept);
31
31
  this.runtime.getQuorum().on("removeMember", this.handleQuorumRemoveMember);
32
32
  }
33
- /**
34
- * {@inheritDoc IPactMap.get}
35
- */
36
33
  get(key) {
37
34
  return this.values.get(key)?.accepted?.value;
38
35
  }
39
- /**
40
- * {@inheritDoc IPactMap.getWithDetails}
41
- */
42
36
  getWithDetails(key) {
43
37
  // Note: We return type `IAcceptedPact` instead of `IAcceptedPactInternal` since we may want to diverge
44
38
  // the interfaces in the future.
@@ -51,21 +45,12 @@ class PactMapClass extends internal_4.SharedObject {
51
45
  acceptedSequenceNumber: acceptedPact.sequenceNumber,
52
46
  };
53
47
  }
54
- /**
55
- * {@inheritDoc IPactMap.isPending}
56
- */
57
48
  isPending(key) {
58
49
  return this.values.get(key)?.pending !== undefined;
59
50
  }
60
- /**
61
- * {@inheritDoc IPactMap.getPending}
62
- */
63
51
  getPending(key) {
64
52
  return this.values.get(key)?.pending?.value;
65
53
  }
66
- /**
67
- * {@inheritDoc IPactMap.set}
68
- */
69
54
  set(key, value) {
70
55
  const currentValue = this.values.get(key);
71
56
  // Early-exit if we can't submit a valid proposal (there's already a pending proposal)
@@ -90,9 +75,6 @@ class PactMapClass extends internal_4.SharedObject {
90
75
  };
91
76
  this.submitLocalMessage(setOp);
92
77
  }
93
- /**
94
- * {@inheritDoc IPactMap.delete}
95
- */
96
78
  delete(key) {
97
79
  const currentValue = this.values.get(key);
98
80
  // Early-exit if:
@@ -206,26 +188,14 @@ class PactMapClass extends internal_4.SharedObject {
206
188
  const allEntries = [...this.values.entries()];
207
189
  return (0, internal_4.createSingleBlobSummary)(snapshotFileName, JSON.stringify(allEntries));
208
190
  }
209
- /**
210
- * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}
211
- */
212
191
  async loadCore(storage) {
213
192
  const content = await (0, internal_3.readAndParse)(storage, snapshotFileName);
214
193
  for (const [key, value] of content) {
215
194
  this.values.set(key, value);
216
195
  }
217
196
  }
218
- /**
219
- * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.initializeLocalCore}
220
- */
221
197
  initializeLocalCore() { }
222
- /**
223
- * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.onDisconnect}
224
- */
225
198
  onDisconnect() { }
226
- /**
227
- * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.reSubmitCore}
228
- */
229
199
  reSubmitCore(content, localOpMetadata) {
230
200
  const pactMapOp = content;
231
201
  // Filter out set messages that have no chance of being accepted because there's another value pending
@@ -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 { 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\tprotected override 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"]}
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\tpublic get(key: string): T | undefined {\n\t\treturn this.values.get(key)?.accepted?.value;\n\t}\n\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\tpublic isPending(key: string): boolean {\n\t\treturn this.values.get(key)?.pending !== undefined;\n\t}\n\n\tpublic getPending(key: string): T | undefined {\n\t\treturn this.values.get(key)?.pending?.value;\n\t}\n\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\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\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\tprotected initializeLocalCore(): void {}\n\n\tprotected onDisconnect(): void {}\n\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\tprotected override 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"]}
@@ -12,9 +12,6 @@ export declare class PactMapFactory implements IChannelFactory<IPactMap> {
12
12
  static readonly Attributes: IChannelAttributes;
13
13
  get type(): string;
14
14
  get attributes(): IChannelAttributes;
15
- /**
16
- * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.load}
17
- */
18
15
  load(runtime: IFluidDataStoreRuntime, id: string, services: IChannelServices, attributes: IChannelAttributes): Promise<IPactMap>;
19
16
  create(document: IFluidDataStoreRuntime, id: string): IPactMap;
20
17
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pactMapFactory.d.ts","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,kBAAkB,EAClB,eAAe,EACf,sBAAsB,EACtB,gBAAgB,EAChB,MAAM,gDAAgD,CAAC;AAGxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhD;;GAEG;AACH,qBAAa,cAAe,YAAW,eAAe,CAAC,QAAQ,CAAC;IAI/D,gBAAuB,IAAI,gDAAgD;IAE3E,gBAAuB,UAAU,EAAE,kBAAkB,CAInD;IAEF,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,IAAW,UAAU,IAAI,kBAAkB,CAE1C;IAED;;OAEG;IACU,IAAI,CAChB,OAAO,EAAE,sBAAsB,EAC/B,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,gBAAgB,EAC1B,UAAU,EAAE,kBAAkB,GAC5B,OAAO,CAAC,QAAQ,CAAC;IAMb,MAAM,CAAC,QAAQ,EAAE,sBAAsB,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ;CAKrE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,eAAO,MAAM,OAAO,4PAAyC,CAAC"}
1
+ {"version":3,"file":"pactMapFactory.d.ts","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,kBAAkB,EAClB,eAAe,EACf,sBAAsB,EACtB,gBAAgB,EAChB,MAAM,gDAAgD,CAAC;AAGxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhD;;GAEG;AACH,qBAAa,cAAe,YAAW,eAAe,CAAC,QAAQ,CAAC;IAI/D,gBAAuB,IAAI,gDAAgD;IAE3E,gBAAuB,UAAU,EAAE,kBAAkB,CAInD;IAEF,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,IAAW,UAAU,IAAI,kBAAkB,CAE1C;IAEY,IAAI,CAChB,OAAO,EAAE,sBAAsB,EAC/B,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,gBAAgB,EAC1B,UAAU,EAAE,kBAAkB,GAC5B,OAAO,CAAC,QAAQ,CAAC;IAMb,MAAM,CAAC,QAAQ,EAAE,sBAAsB,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ;CAKrE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,eAAO,MAAM,OAAO,4PAAyC,CAAC"}
@@ -27,9 +27,6 @@ class PactMapFactory {
27
27
  get attributes() {
28
28
  return PactMapFactory.Attributes;
29
29
  }
30
- /**
31
- * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.load}
32
- */
33
30
  async load(runtime, id, services, attributes) {
34
31
  const pactMap = new pactMap_js_1.PactMapClass(id, runtime, attributes);
35
32
  await pactMap.load(services);
@@ -1 +1 @@
1
- {"version":3,"file":"pactMapFactory.js","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAQH,0EAAqF;AAGrF,2DAAiD;AACjD,6CAA4C;AAE5C;;GAEG;AACH,MAAa,cAAc;IAC1B,uGAAuG;IACvG,qFAAqF;IACrF,4CAA4C;IACrC,MAAM,CAAU,IAAI,GAAG,4CAA4C,CAAC;IAEpE,MAAM,CAAU,UAAU,GAAuB;QACvD,IAAI,EAAE,cAAc,CAAC,IAAI;QACzB,qBAAqB,EAAE,KAAK;QAC5B,cAAc,EAAE,8BAAU;KAC1B,CAAC;IAEF,IAAW,IAAI;QACd,OAAO,cAAc,CAAC,IAAI,CAAC;IAC5B,CAAC;IAED,IAAW,UAAU;QACpB,OAAO,cAAc,CAAC,UAAU,CAAC;IAClC,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,IAAI,CAChB,OAA+B,EAC/B,EAAU,EACV,QAA0B,EAC1B,UAA8B;QAE9B,MAAM,OAAO,GAAG,IAAI,yBAAY,CAAC,EAAE,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAC1D,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,OAAO,CAAC;IAChB,CAAC;IAEM,MAAM,CAAC,QAAgC,EAAE,EAAU;QACzD,MAAM,OAAO,GAAG,IAAI,yBAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAChE,OAAO,CAAC,eAAe,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC;IAChB,CAAC;;AAtCF,wCAuCC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACU,QAAA,OAAO,GAAG,IAAA,iCAAsB,EAAC,cAAc,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tIChannelAttributes,\n\tIChannelFactory,\n\tIFluidDataStoreRuntime,\n\tIChannelServices,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport { createSharedObjectKind } from \"@fluidframework/shared-object-base/internal\";\n\nimport type { IPactMap } from \"./interfaces.js\";\nimport { pkgVersion } from \"./packageVersion.js\";\nimport { PactMapClass } from \"./pactMap.js\";\n\n/**\n * The factory that produces the PactMap\n */\nexport class PactMapFactory implements IChannelFactory<IPactMap> {\n\t// New type string, to be activated once the migration has been fully shipped dark and is safe to flip.\n\t// See LegacyTypeAwareRegistry in packages/runtime/datastore/src/dataStoreRuntime.ts.\n\t// public static readonly Type = \"pact-map\";\n\tpublic static readonly Type = \"https://graph.microsoft.com/types/pact-map\";\n\n\tpublic static readonly Attributes: IChannelAttributes = {\n\t\ttype: PactMapFactory.Type,\n\t\tsnapshotFormatVersion: \"0.1\",\n\t\tpackageVersion: pkgVersion,\n\t};\n\n\tpublic get type(): string {\n\t\treturn PactMapFactory.Type;\n\t}\n\n\tpublic get attributes(): IChannelAttributes {\n\t\treturn PactMapFactory.Attributes;\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.load}\n\t */\n\tpublic async load(\n\t\truntime: IFluidDataStoreRuntime,\n\t\tid: string,\n\t\tservices: IChannelServices,\n\t\tattributes: IChannelAttributes,\n\t): Promise<IPactMap> {\n\t\tconst pactMap = new PactMapClass(id, runtime, attributes);\n\t\tawait pactMap.load(services);\n\t\treturn pactMap;\n\t}\n\n\tpublic create(document: IFluidDataStoreRuntime, id: string): IPactMap {\n\t\tconst pactMap = new PactMapClass(id, document, this.attributes);\n\t\tpactMap.initializeLocal();\n\t\treturn pactMap;\n\t}\n}\n\n/**\n * The PactMap distributed data structure provides key/value storage with a cautious conflict resolution strategy.\n * This strategy optimizes for all clients being aware of the change prior to considering the value as accepted.\n *\n * It is still experimental and under development. Please do try it out, but expect breaking changes in the future.\n *\n * @remarks\n * ### Creation\n *\n * To create a `PactMap`, call the static create method:\n *\n * ```typescript\n * const pactMap = PactMap.create(this.runtime, id);\n * ```\n *\n * ### Usage\n *\n * Setting and reading values is somewhat similar to a `SharedMap`. However, because the acceptance strategy\n * cannot be resolved until other clients have witnessed the set, the new value will only be reflected in the data\n * after the consensus is reached.\n *\n * ```typescript\n * pactMap.on(\"pending\", (key: string) => {\n * console.log(pactMap.getPending(key));\n * });\n * pactMap.on(\"accepted\", (key: string) => {\n * console.log(pactMap.get(key));\n * });\n * pactMap.set(\"myKey\", \"myValue\");\n *\n * // Reading from the pact map prior to the async operation's completion will still return the old value.\n * console.log(pactMap.get(\"myKey\"));\n * ```\n *\n * The acceptance process has two stages. When an op indicating a client's attempt to set a value is sequenced,\n * we first verify that it was set with knowledge of the most recently accepted value (consensus-like FWW). If it\n * meets this bar, then the value is \"pending\". During this time, clients may observe the pending value and act\n * upon it, but should be aware that not all other clients may have witnessed the value yet. Once all clients\n * that were connected at the time of the value being set have explicitly acknowledged the new value, the value\n * becomes \"accepted\". Once the value is accepted, it once again becomes possible to set the value, again with\n * consensus-like FWW resolution.\n *\n * Since all connected clients must explicitly accept the new value, it is important that all connected clients\n * have the PactMap loaded, including e.g. the summarizing client. Otherwise, those clients who have not loaded\n * the PactMap will not be responding to proposals and delay their acceptance (until they disconnect, which implicitly\n * removes them from consideration). The easiest way to ensure all clients load the PactMap is to instantiate it\n * as part of instantiating the IRuntime for the container (containerHasInitialized if using Aqueduct).\n *\n * ### Eventing\n *\n * `PactMap` is an `EventEmitter`, and will emit events when a new value is accepted for a key.\n *\n * ```typescript\n * pactMap.on(\"accept\", (key: string) => {\n * console.log(`New value was accepted for key: ${ key }, value: ${ pactMap.get(key) }`);\n * });\n * ```\n * @internal\n */\nexport const PactMap = createSharedObjectKind(PactMapFactory);\n"]}
1
+ {"version":3,"file":"pactMapFactory.js","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAQH,0EAAqF;AAGrF,2DAAiD;AACjD,6CAA4C;AAE5C;;GAEG;AACH,MAAa,cAAc;IAC1B,uGAAuG;IACvG,qFAAqF;IACrF,4CAA4C;IACrC,MAAM,CAAU,IAAI,GAAG,4CAA4C,CAAC;IAEpE,MAAM,CAAU,UAAU,GAAuB;QACvD,IAAI,EAAE,cAAc,CAAC,IAAI;QACzB,qBAAqB,EAAE,KAAK;QAC5B,cAAc,EAAE,8BAAU;KAC1B,CAAC;IAEF,IAAW,IAAI;QACd,OAAO,cAAc,CAAC,IAAI,CAAC;IAC5B,CAAC;IAED,IAAW,UAAU;QACpB,OAAO,cAAc,CAAC,UAAU,CAAC;IAClC,CAAC;IAEM,KAAK,CAAC,IAAI,CAChB,OAA+B,EAC/B,EAAU,EACV,QAA0B,EAC1B,UAA8B;QAE9B,MAAM,OAAO,GAAG,IAAI,yBAAY,CAAC,EAAE,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAC1D,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,OAAO,CAAC;IAChB,CAAC;IAEM,MAAM,CAAC,QAAgC,EAAE,EAAU;QACzD,MAAM,OAAO,GAAG,IAAI,yBAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAChE,OAAO,CAAC,eAAe,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC;IAChB,CAAC;;AAnCF,wCAoCC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACU,QAAA,OAAO,GAAG,IAAA,iCAAsB,EAAC,cAAc,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tIChannelAttributes,\n\tIChannelFactory,\n\tIFluidDataStoreRuntime,\n\tIChannelServices,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport { createSharedObjectKind } from \"@fluidframework/shared-object-base/internal\";\n\nimport type { IPactMap } from \"./interfaces.js\";\nimport { pkgVersion } from \"./packageVersion.js\";\nimport { PactMapClass } from \"./pactMap.js\";\n\n/**\n * The factory that produces the PactMap\n */\nexport class PactMapFactory implements IChannelFactory<IPactMap> {\n\t// New type string, to be activated once the migration has been fully shipped dark and is safe to flip.\n\t// See LegacyTypeAwareRegistry in packages/runtime/datastore/src/dataStoreRuntime.ts.\n\t// public static readonly Type = \"pact-map\";\n\tpublic static readonly Type = \"https://graph.microsoft.com/types/pact-map\";\n\n\tpublic static readonly Attributes: IChannelAttributes = {\n\t\ttype: PactMapFactory.Type,\n\t\tsnapshotFormatVersion: \"0.1\",\n\t\tpackageVersion: pkgVersion,\n\t};\n\n\tpublic get type(): string {\n\t\treturn PactMapFactory.Type;\n\t}\n\n\tpublic get attributes(): IChannelAttributes {\n\t\treturn PactMapFactory.Attributes;\n\t}\n\n\tpublic async load(\n\t\truntime: IFluidDataStoreRuntime,\n\t\tid: string,\n\t\tservices: IChannelServices,\n\t\tattributes: IChannelAttributes,\n\t): Promise<IPactMap> {\n\t\tconst pactMap = new PactMapClass(id, runtime, attributes);\n\t\tawait pactMap.load(services);\n\t\treturn pactMap;\n\t}\n\n\tpublic create(document: IFluidDataStoreRuntime, id: string): IPactMap {\n\t\tconst pactMap = new PactMapClass(id, document, this.attributes);\n\t\tpactMap.initializeLocal();\n\t\treturn pactMap;\n\t}\n}\n\n/**\n * The PactMap distributed data structure provides key/value storage with a cautious conflict resolution strategy.\n * This strategy optimizes for all clients being aware of the change prior to considering the value as accepted.\n *\n * It is still experimental and under development. Please do try it out, but expect breaking changes in the future.\n *\n * @remarks\n * ### Creation\n *\n * To create a `PactMap`, call the static create method:\n *\n * ```typescript\n * const pactMap = PactMap.create(this.runtime, id);\n * ```\n *\n * ### Usage\n *\n * Setting and reading values is somewhat similar to a `SharedMap`. However, because the acceptance strategy\n * cannot be resolved until other clients have witnessed the set, the new value will only be reflected in the data\n * after the consensus is reached.\n *\n * ```typescript\n * pactMap.on(\"pending\", (key: string) => {\n * console.log(pactMap.getPending(key));\n * });\n * pactMap.on(\"accepted\", (key: string) => {\n * console.log(pactMap.get(key));\n * });\n * pactMap.set(\"myKey\", \"myValue\");\n *\n * // Reading from the pact map prior to the async operation's completion will still return the old value.\n * console.log(pactMap.get(\"myKey\"));\n * ```\n *\n * The acceptance process has two stages. When an op indicating a client's attempt to set a value is sequenced,\n * we first verify that it was set with knowledge of the most recently accepted value (consensus-like FWW). If it\n * meets this bar, then the value is \"pending\". During this time, clients may observe the pending value and act\n * upon it, but should be aware that not all other clients may have witnessed the value yet. Once all clients\n * that were connected at the time of the value being set have explicitly acknowledged the new value, the value\n * becomes \"accepted\". Once the value is accepted, it once again becomes possible to set the value, again with\n * consensus-like FWW resolution.\n *\n * Since all connected clients must explicitly accept the new value, it is important that all connected clients\n * have the PactMap loaded, including e.g. the summarizing client. Otherwise, those clients who have not loaded\n * the PactMap will not be responding to proposals and delay their acceptance (until they disconnect, which implicitly\n * removes them from consideration). The easiest way to ensure all clients load the PactMap is to instantiate it\n * as part of instantiating the IRuntime for the container (containerHasInitialized if using Aqueduct).\n *\n * ### Eventing\n *\n * `PactMap` is an `EventEmitter`, and will emit events when a new value is accepted for a key.\n *\n * ```typescript\n * pactMap.on(\"accept\", (key: string) => {\n * console.log(`New value was accepted for key: ${ key }, value: ${ pactMap.get(key) }`);\n * });\n * ```\n * @internal\n */\nexport const PactMap = createSharedObjectKind(PactMapFactory);\n"]}
@@ -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 = "3.4.0";
8
+ export declare const pkgVersion = "3.6.0";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluid-experimental/pact-map";
8
- export const pkgVersion = "3.4.0";
8
+ export const pkgVersion = "3.6.0";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -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,OAAO,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 = \"3.4.0\";\n"]}
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,OAAO,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 = \"3.6.0\";\n"]}
package/lib/pactMap.d.ts CHANGED
@@ -21,29 +21,11 @@ export declare class PactMapClass<T = unknown> extends SharedObject<IPactMapEven
21
21
  * @param id - optional name of the PactMap
22
22
  */
23
23
  constructor(id: string, runtime: IFluidDataStoreRuntime, attributes: IChannelAttributes);
24
- /**
25
- * {@inheritDoc IPactMap.get}
26
- */
27
24
  get(key: string): T | undefined;
28
- /**
29
- * {@inheritDoc IPactMap.getWithDetails}
30
- */
31
25
  getWithDetails(key: string): IAcceptedPact<T> | undefined;
32
- /**
33
- * {@inheritDoc IPactMap.isPending}
34
- */
35
26
  isPending(key: string): boolean;
36
- /**
37
- * {@inheritDoc IPactMap.getPending}
38
- */
39
27
  getPending(key: string): T | undefined;
40
- /**
41
- * {@inheritDoc IPactMap.set}
42
- */
43
28
  set(key: string, value: T | undefined): void;
44
- /**
45
- * {@inheritDoc IPactMap.delete}
46
- */
47
29
  delete(key: string): void;
48
30
  /**
49
31
  * Get a point-in-time list of clients who must sign off on values coming in for them to move from "pending" to
@@ -61,21 +43,9 @@ export declare class PactMapClass<T = unknown> extends SharedObject<IPactMapEven
61
43
  * @returns the summary of the current state of the PactMap
62
44
  */
63
45
  protected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats;
64
- /**
65
- * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}
66
- */
67
46
  protected loadCore(storage: IChannelStorageService): Promise<void>;
68
- /**
69
- * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.initializeLocalCore}
70
- */
71
47
  protected initializeLocalCore(): void;
72
- /**
73
- * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.onDisconnect}
74
- */
75
48
  protected onDisconnect(): void;
76
- /**
77
- * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.reSubmitCore}
78
- */
79
49
  protected reSubmitCore(content: unknown, localOpMetadata: unknown): void;
80
50
  protected processMessagesCore(messagesCollection: IRuntimeMessageCollection): void;
81
51
  private processMessage;
@@ -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;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;cAmBrD,mBAAmB,CAAC,kBAAkB,EAAE,yBAAyB,GAAG,IAAI;IAO3F,OAAO,CAAC,cAAc;IAsCtB,SAAS,CAAC,cAAc,IAAI,IAAI;CAGhC"}
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;IAUxB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAI/B,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS;IAazD,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI/B,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAItC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,IAAI;IA4B5C,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;cAK5D,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxE,SAAS,CAAC,mBAAmB,IAAI,IAAI;IAErC,SAAS,CAAC,YAAY,IAAI,IAAI;IAE9B,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,GAAG,IAAI;cAmBrD,mBAAmB,CAAC,kBAAkB,EAAE,yBAAyB,GAAG,IAAI;IAO3F,OAAO,CAAC,cAAc;IAsCtB,SAAS,CAAC,cAAc,IAAI,IAAI;CAGhC"}
package/lib/pactMap.js CHANGED
@@ -27,15 +27,9 @@ export class PactMapClass extends SharedObject {
27
27
  this.incomingOp.on("accept", this.handleIncomingAccept);
28
28
  this.runtime.getQuorum().on("removeMember", this.handleQuorumRemoveMember);
29
29
  }
30
- /**
31
- * {@inheritDoc IPactMap.get}
32
- */
33
30
  get(key) {
34
31
  return this.values.get(key)?.accepted?.value;
35
32
  }
36
- /**
37
- * {@inheritDoc IPactMap.getWithDetails}
38
- */
39
33
  getWithDetails(key) {
40
34
  // Note: We return type `IAcceptedPact` instead of `IAcceptedPactInternal` since we may want to diverge
41
35
  // the interfaces in the future.
@@ -48,21 +42,12 @@ export class PactMapClass extends SharedObject {
48
42
  acceptedSequenceNumber: acceptedPact.sequenceNumber,
49
43
  };
50
44
  }
51
- /**
52
- * {@inheritDoc IPactMap.isPending}
53
- */
54
45
  isPending(key) {
55
46
  return this.values.get(key)?.pending !== undefined;
56
47
  }
57
- /**
58
- * {@inheritDoc IPactMap.getPending}
59
- */
60
48
  getPending(key) {
61
49
  return this.values.get(key)?.pending?.value;
62
50
  }
63
- /**
64
- * {@inheritDoc IPactMap.set}
65
- */
66
51
  set(key, value) {
67
52
  const currentValue = this.values.get(key);
68
53
  // Early-exit if we can't submit a valid proposal (there's already a pending proposal)
@@ -87,9 +72,6 @@ export class PactMapClass extends SharedObject {
87
72
  };
88
73
  this.submitLocalMessage(setOp);
89
74
  }
90
- /**
91
- * {@inheritDoc IPactMap.delete}
92
- */
93
75
  delete(key) {
94
76
  const currentValue = this.values.get(key);
95
77
  // Early-exit if:
@@ -203,26 +185,14 @@ export class PactMapClass extends SharedObject {
203
185
  const allEntries = [...this.values.entries()];
204
186
  return createSingleBlobSummary(snapshotFileName, JSON.stringify(allEntries));
205
187
  }
206
- /**
207
- * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}
208
- */
209
188
  async loadCore(storage) {
210
189
  const content = await readAndParse(storage, snapshotFileName);
211
190
  for (const [key, value] of content) {
212
191
  this.values.set(key, value);
213
192
  }
214
193
  }
215
- /**
216
- * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.initializeLocalCore}
217
- */
218
194
  initializeLocalCore() { }
219
- /**
220
- * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.onDisconnect}
221
- */
222
195
  onDisconnect() { }
223
- /**
224
- * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.reSubmitCore}
225
- */
226
196
  reSubmitCore(content, localOpMetadata) {
227
197
  const pactMapOp = content;
228
198
  // Filter out set messages that have no chance of being accepted because there's another value pending
@@ -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 { 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\tprotected override 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"]}
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\tpublic get(key: string): T | undefined {\n\t\treturn this.values.get(key)?.accepted?.value;\n\t}\n\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\tpublic isPending(key: string): boolean {\n\t\treturn this.values.get(key)?.pending !== undefined;\n\t}\n\n\tpublic getPending(key: string): T | undefined {\n\t\treturn this.values.get(key)?.pending?.value;\n\t}\n\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\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\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\tprotected initializeLocalCore(): void {}\n\n\tprotected onDisconnect(): void {}\n\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\tprotected override 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"]}
@@ -12,9 +12,6 @@ export declare class PactMapFactory implements IChannelFactory<IPactMap> {
12
12
  static readonly Attributes: IChannelAttributes;
13
13
  get type(): string;
14
14
  get attributes(): IChannelAttributes;
15
- /**
16
- * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.load}
17
- */
18
15
  load(runtime: IFluidDataStoreRuntime, id: string, services: IChannelServices, attributes: IChannelAttributes): Promise<IPactMap>;
19
16
  create(document: IFluidDataStoreRuntime, id: string): IPactMap;
20
17
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pactMapFactory.d.ts","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,kBAAkB,EAClB,eAAe,EACf,sBAAsB,EACtB,gBAAgB,EAChB,MAAM,gDAAgD,CAAC;AAGxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhD;;GAEG;AACH,qBAAa,cAAe,YAAW,eAAe,CAAC,QAAQ,CAAC;IAI/D,gBAAuB,IAAI,gDAAgD;IAE3E,gBAAuB,UAAU,EAAE,kBAAkB,CAInD;IAEF,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,IAAW,UAAU,IAAI,kBAAkB,CAE1C;IAED;;OAEG;IACU,IAAI,CAChB,OAAO,EAAE,sBAAsB,EAC/B,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,gBAAgB,EAC1B,UAAU,EAAE,kBAAkB,GAC5B,OAAO,CAAC,QAAQ,CAAC;IAMb,MAAM,CAAC,QAAQ,EAAE,sBAAsB,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ;CAKrE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,eAAO,MAAM,OAAO,wLAAyC,CAAC"}
1
+ {"version":3,"file":"pactMapFactory.d.ts","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,kBAAkB,EAClB,eAAe,EACf,sBAAsB,EACtB,gBAAgB,EAChB,MAAM,gDAAgD,CAAC;AAGxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhD;;GAEG;AACH,qBAAa,cAAe,YAAW,eAAe,CAAC,QAAQ,CAAC;IAI/D,gBAAuB,IAAI,gDAAgD;IAE3E,gBAAuB,UAAU,EAAE,kBAAkB,CAInD;IAEF,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,IAAW,UAAU,IAAI,kBAAkB,CAE1C;IAEY,IAAI,CAChB,OAAO,EAAE,sBAAsB,EAC/B,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,gBAAgB,EAC1B,UAAU,EAAE,kBAAkB,GAC5B,OAAO,CAAC,QAAQ,CAAC;IAMb,MAAM,CAAC,QAAQ,EAAE,sBAAsB,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ;CAKrE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,eAAO,MAAM,OAAO,wLAAyC,CAAC"}
@@ -24,9 +24,6 @@ export class PactMapFactory {
24
24
  get attributes() {
25
25
  return PactMapFactory.Attributes;
26
26
  }
27
- /**
28
- * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.load}
29
- */
30
27
  async load(runtime, id, services, attributes) {
31
28
  const pactMap = new PactMapClass(id, runtime, attributes);
32
29
  await pactMap.load(services);
@@ -1 +1 @@
1
- {"version":3,"file":"pactMapFactory.js","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AAGrF,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C;;GAEG;AACH,MAAM,OAAO,cAAc;IAC1B,uGAAuG;IACvG,qFAAqF;IACrF,4CAA4C;IACrC,MAAM,CAAU,IAAI,GAAG,4CAA4C,CAAC;IAEpE,MAAM,CAAU,UAAU,GAAuB;QACvD,IAAI,EAAE,cAAc,CAAC,IAAI;QACzB,qBAAqB,EAAE,KAAK;QAC5B,cAAc,EAAE,UAAU;KAC1B,CAAC;IAEF,IAAW,IAAI;QACd,OAAO,cAAc,CAAC,IAAI,CAAC;IAC5B,CAAC;IAED,IAAW,UAAU;QACpB,OAAO,cAAc,CAAC,UAAU,CAAC;IAClC,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,IAAI,CAChB,OAA+B,EAC/B,EAAU,EACV,QAA0B,EAC1B,UAA8B;QAE9B,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,EAAE,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAC1D,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,OAAO,CAAC;IAChB,CAAC;IAEM,MAAM,CAAC,QAAgC,EAAE,EAAU;QACzD,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAChE,OAAO,CAAC,eAAe,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC;IAChB,CAAC;;AAGF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,sBAAsB,CAAC,cAAc,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tIChannelAttributes,\n\tIChannelFactory,\n\tIFluidDataStoreRuntime,\n\tIChannelServices,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport { createSharedObjectKind } from \"@fluidframework/shared-object-base/internal\";\n\nimport type { IPactMap } from \"./interfaces.js\";\nimport { pkgVersion } from \"./packageVersion.js\";\nimport { PactMapClass } from \"./pactMap.js\";\n\n/**\n * The factory that produces the PactMap\n */\nexport class PactMapFactory implements IChannelFactory<IPactMap> {\n\t// New type string, to be activated once the migration has been fully shipped dark and is safe to flip.\n\t// See LegacyTypeAwareRegistry in packages/runtime/datastore/src/dataStoreRuntime.ts.\n\t// public static readonly Type = \"pact-map\";\n\tpublic static readonly Type = \"https://graph.microsoft.com/types/pact-map\";\n\n\tpublic static readonly Attributes: IChannelAttributes = {\n\t\ttype: PactMapFactory.Type,\n\t\tsnapshotFormatVersion: \"0.1\",\n\t\tpackageVersion: pkgVersion,\n\t};\n\n\tpublic get type(): string {\n\t\treturn PactMapFactory.Type;\n\t}\n\n\tpublic get attributes(): IChannelAttributes {\n\t\treturn PactMapFactory.Attributes;\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.load}\n\t */\n\tpublic async load(\n\t\truntime: IFluidDataStoreRuntime,\n\t\tid: string,\n\t\tservices: IChannelServices,\n\t\tattributes: IChannelAttributes,\n\t): Promise<IPactMap> {\n\t\tconst pactMap = new PactMapClass(id, runtime, attributes);\n\t\tawait pactMap.load(services);\n\t\treturn pactMap;\n\t}\n\n\tpublic create(document: IFluidDataStoreRuntime, id: string): IPactMap {\n\t\tconst pactMap = new PactMapClass(id, document, this.attributes);\n\t\tpactMap.initializeLocal();\n\t\treturn pactMap;\n\t}\n}\n\n/**\n * The PactMap distributed data structure provides key/value storage with a cautious conflict resolution strategy.\n * This strategy optimizes for all clients being aware of the change prior to considering the value as accepted.\n *\n * It is still experimental and under development. Please do try it out, but expect breaking changes in the future.\n *\n * @remarks\n * ### Creation\n *\n * To create a `PactMap`, call the static create method:\n *\n * ```typescript\n * const pactMap = PactMap.create(this.runtime, id);\n * ```\n *\n * ### Usage\n *\n * Setting and reading values is somewhat similar to a `SharedMap`. However, because the acceptance strategy\n * cannot be resolved until other clients have witnessed the set, the new value will only be reflected in the data\n * after the consensus is reached.\n *\n * ```typescript\n * pactMap.on(\"pending\", (key: string) => {\n * console.log(pactMap.getPending(key));\n * });\n * pactMap.on(\"accepted\", (key: string) => {\n * console.log(pactMap.get(key));\n * });\n * pactMap.set(\"myKey\", \"myValue\");\n *\n * // Reading from the pact map prior to the async operation's completion will still return the old value.\n * console.log(pactMap.get(\"myKey\"));\n * ```\n *\n * The acceptance process has two stages. When an op indicating a client's attempt to set a value is sequenced,\n * we first verify that it was set with knowledge of the most recently accepted value (consensus-like FWW). If it\n * meets this bar, then the value is \"pending\". During this time, clients may observe the pending value and act\n * upon it, but should be aware that not all other clients may have witnessed the value yet. Once all clients\n * that were connected at the time of the value being set have explicitly acknowledged the new value, the value\n * becomes \"accepted\". Once the value is accepted, it once again becomes possible to set the value, again with\n * consensus-like FWW resolution.\n *\n * Since all connected clients must explicitly accept the new value, it is important that all connected clients\n * have the PactMap loaded, including e.g. the summarizing client. Otherwise, those clients who have not loaded\n * the PactMap will not be responding to proposals and delay their acceptance (until they disconnect, which implicitly\n * removes them from consideration). The easiest way to ensure all clients load the PactMap is to instantiate it\n * as part of instantiating the IRuntime for the container (containerHasInitialized if using Aqueduct).\n *\n * ### Eventing\n *\n * `PactMap` is an `EventEmitter`, and will emit events when a new value is accepted for a key.\n *\n * ```typescript\n * pactMap.on(\"accept\", (key: string) => {\n * console.log(`New value was accepted for key: ${ key }, value: ${ pactMap.get(key) }`);\n * });\n * ```\n * @internal\n */\nexport const PactMap = createSharedObjectKind(PactMapFactory);\n"]}
1
+ {"version":3,"file":"pactMapFactory.js","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AAGrF,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C;;GAEG;AACH,MAAM,OAAO,cAAc;IAC1B,uGAAuG;IACvG,qFAAqF;IACrF,4CAA4C;IACrC,MAAM,CAAU,IAAI,GAAG,4CAA4C,CAAC;IAEpE,MAAM,CAAU,UAAU,GAAuB;QACvD,IAAI,EAAE,cAAc,CAAC,IAAI;QACzB,qBAAqB,EAAE,KAAK;QAC5B,cAAc,EAAE,UAAU;KAC1B,CAAC;IAEF,IAAW,IAAI;QACd,OAAO,cAAc,CAAC,IAAI,CAAC;IAC5B,CAAC;IAED,IAAW,UAAU;QACpB,OAAO,cAAc,CAAC,UAAU,CAAC;IAClC,CAAC;IAEM,KAAK,CAAC,IAAI,CAChB,OAA+B,EAC/B,EAAU,EACV,QAA0B,EAC1B,UAA8B;QAE9B,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,EAAE,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAC1D,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,OAAO,CAAC;IAChB,CAAC;IAEM,MAAM,CAAC,QAAgC,EAAE,EAAU;QACzD,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAChE,OAAO,CAAC,eAAe,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC;IAChB,CAAC;;AAGF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,sBAAsB,CAAC,cAAc,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tIChannelAttributes,\n\tIChannelFactory,\n\tIFluidDataStoreRuntime,\n\tIChannelServices,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport { createSharedObjectKind } from \"@fluidframework/shared-object-base/internal\";\n\nimport type { IPactMap } from \"./interfaces.js\";\nimport { pkgVersion } from \"./packageVersion.js\";\nimport { PactMapClass } from \"./pactMap.js\";\n\n/**\n * The factory that produces the PactMap\n */\nexport class PactMapFactory implements IChannelFactory<IPactMap> {\n\t// New type string, to be activated once the migration has been fully shipped dark and is safe to flip.\n\t// See LegacyTypeAwareRegistry in packages/runtime/datastore/src/dataStoreRuntime.ts.\n\t// public static readonly Type = \"pact-map\";\n\tpublic static readonly Type = \"https://graph.microsoft.com/types/pact-map\";\n\n\tpublic static readonly Attributes: IChannelAttributes = {\n\t\ttype: PactMapFactory.Type,\n\t\tsnapshotFormatVersion: \"0.1\",\n\t\tpackageVersion: pkgVersion,\n\t};\n\n\tpublic get type(): string {\n\t\treturn PactMapFactory.Type;\n\t}\n\n\tpublic get attributes(): IChannelAttributes {\n\t\treturn PactMapFactory.Attributes;\n\t}\n\n\tpublic async load(\n\t\truntime: IFluidDataStoreRuntime,\n\t\tid: string,\n\t\tservices: IChannelServices,\n\t\tattributes: IChannelAttributes,\n\t): Promise<IPactMap> {\n\t\tconst pactMap = new PactMapClass(id, runtime, attributes);\n\t\tawait pactMap.load(services);\n\t\treturn pactMap;\n\t}\n\n\tpublic create(document: IFluidDataStoreRuntime, id: string): IPactMap {\n\t\tconst pactMap = new PactMapClass(id, document, this.attributes);\n\t\tpactMap.initializeLocal();\n\t\treturn pactMap;\n\t}\n}\n\n/**\n * The PactMap distributed data structure provides key/value storage with a cautious conflict resolution strategy.\n * This strategy optimizes for all clients being aware of the change prior to considering the value as accepted.\n *\n * It is still experimental and under development. Please do try it out, but expect breaking changes in the future.\n *\n * @remarks\n * ### Creation\n *\n * To create a `PactMap`, call the static create method:\n *\n * ```typescript\n * const pactMap = PactMap.create(this.runtime, id);\n * ```\n *\n * ### Usage\n *\n * Setting and reading values is somewhat similar to a `SharedMap`. However, because the acceptance strategy\n * cannot be resolved until other clients have witnessed the set, the new value will only be reflected in the data\n * after the consensus is reached.\n *\n * ```typescript\n * pactMap.on(\"pending\", (key: string) => {\n * console.log(pactMap.getPending(key));\n * });\n * pactMap.on(\"accepted\", (key: string) => {\n * console.log(pactMap.get(key));\n * });\n * pactMap.set(\"myKey\", \"myValue\");\n *\n * // Reading from the pact map prior to the async operation's completion will still return the old value.\n * console.log(pactMap.get(\"myKey\"));\n * ```\n *\n * The acceptance process has two stages. When an op indicating a client's attempt to set a value is sequenced,\n * we first verify that it was set with knowledge of the most recently accepted value (consensus-like FWW). If it\n * meets this bar, then the value is \"pending\". During this time, clients may observe the pending value and act\n * upon it, but should be aware that not all other clients may have witnessed the value yet. Once all clients\n * that were connected at the time of the value being set have explicitly acknowledged the new value, the value\n * becomes \"accepted\". Once the value is accepted, it once again becomes possible to set the value, again with\n * consensus-like FWW resolution.\n *\n * Since all connected clients must explicitly accept the new value, it is important that all connected clients\n * have the PactMap loaded, including e.g. the summarizing client. Otherwise, those clients who have not loaded\n * the PactMap will not be responding to proposals and delay their acceptance (until they disconnect, which implicitly\n * removes them from consideration). The easiest way to ensure all clients load the PactMap is to instantiate it\n * as part of instantiating the IRuntime for the container (containerHasInitialized if using Aqueduct).\n *\n * ### Eventing\n *\n * `PactMap` is an `EventEmitter`, and will emit events when a new value is accepted for a key.\n *\n * ```typescript\n * pactMap.on(\"accept\", (key: string) => {\n * console.log(`New value was accepted for key: ${ key }, value: ${ pactMap.get(key) }`);\n * });\n * ```\n * @internal\n */\nexport const PactMap = createSharedObjectKind(PactMapFactory);\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluid-experimental/pact-map",
3
- "version": "3.4.0",
3
+ "version": "3.6.0",
4
4
  "description": "Distributed data structure for key-value pairs using pact consensus",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -41,24 +41,24 @@
41
41
  "temp-directory": "nyc/.nyc_output"
42
42
  },
43
43
  "dependencies": {
44
- "@fluid-internal/client-utils": "~3.4.0",
45
- "@fluidframework/core-utils": "~3.4.0",
46
- "@fluidframework/datastore-definitions": "~3.4.0",
47
- "@fluidframework/driver-definitions": "~3.4.0",
48
- "@fluidframework/driver-utils": "~3.4.0",
49
- "@fluidframework/runtime-definitions": "~3.4.0",
50
- "@fluidframework/shared-object-base": "~3.4.0"
44
+ "@fluid-internal/client-utils": "~3.6.0",
45
+ "@fluidframework/core-utils": "~3.6.0",
46
+ "@fluidframework/datastore-definitions": "~3.6.0",
47
+ "@fluidframework/driver-definitions": "~3.6.0",
48
+ "@fluidframework/driver-utils": "~3.6.0",
49
+ "@fluidframework/runtime-definitions": "~3.6.0",
50
+ "@fluidframework/shared-object-base": "~3.6.0"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@arethetypeswrong/cli": "^0.18.5",
54
54
  "@biomejs/biome": "~2.4.5",
55
- "@fluid-internal/mocha-test-setup": "~3.4.0",
56
- "@fluid-private/test-dds-utils": "~3.4.0",
57
- "@fluid-tools/build-cli": "^0.67.0",
55
+ "@fluid-internal/mocha-test-setup": "~3.6.0",
56
+ "@fluid-private/test-dds-utils": "~3.6.0",
57
+ "@fluid-tools/build-cli": "^0.68.0",
58
58
  "@fluidframework/build-common": "^2.0.3",
59
- "@fluidframework/build-tools": "^0.67.0",
59
+ "@fluidframework/build-tools": "^0.68.0",
60
60
  "@fluidframework/eslint-config-fluid": "^14.0.0",
61
- "@fluidframework/test-runtime-utils": "~3.4.0",
61
+ "@fluidframework/test-runtime-utils": "~3.6.0",
62
62
  "@microsoft/api-extractor": "7.58.1",
63
63
  "@types/mocha": "^10.0.10",
64
64
  "@types/node": "~22.19.17",
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluid-experimental/pact-map";
9
- export const pkgVersion = "3.4.0";
9
+ export const pkgVersion = "3.6.0";
package/src/pactMap.ts CHANGED
@@ -128,16 +128,10 @@ export class PactMapClass<T = unknown>
128
128
  this.runtime.getQuorum().on("removeMember", this.handleQuorumRemoveMember);
129
129
  }
130
130
 
131
- /**
132
- * {@inheritDoc IPactMap.get}
133
- */
134
131
  public get(key: string): T | undefined {
135
132
  return this.values.get(key)?.accepted?.value;
136
133
  }
137
134
 
138
- /**
139
- * {@inheritDoc IPactMap.getWithDetails}
140
- */
141
135
  public getWithDetails(key: string): IAcceptedPact<T> | undefined {
142
136
  // Note: We return type `IAcceptedPact` instead of `IAcceptedPactInternal` since we may want to diverge
143
137
  // the interfaces in the future.
@@ -151,23 +145,14 @@ export class PactMapClass<T = unknown>
151
145
  };
152
146
  }
153
147
 
154
- /**
155
- * {@inheritDoc IPactMap.isPending}
156
- */
157
148
  public isPending(key: string): boolean {
158
149
  return this.values.get(key)?.pending !== undefined;
159
150
  }
160
151
 
161
- /**
162
- * {@inheritDoc IPactMap.getPending}
163
- */
164
152
  public getPending(key: string): T | undefined {
165
153
  return this.values.get(key)?.pending?.value;
166
154
  }
167
155
 
168
- /**
169
- * {@inheritDoc IPactMap.set}
170
- */
171
156
  public set(key: string, value: T | undefined): void {
172
157
  const currentValue = this.values.get(key);
173
158
  // Early-exit if we can't submit a valid proposal (there's already a pending proposal)
@@ -196,9 +181,6 @@ export class PactMapClass<T = unknown>
196
181
  this.submitLocalMessage(setOp);
197
182
  }
198
183
 
199
- /**
200
- * {@inheritDoc IPactMap.delete}
201
- */
202
184
  public delete(key: string): void {
203
185
  const currentValue = this.values.get(key);
204
186
  // Early-exit if:
@@ -347,9 +329,6 @@ export class PactMapClass<T = unknown>
347
329
  return createSingleBlobSummary(snapshotFileName, JSON.stringify(allEntries));
348
330
  }
349
331
 
350
- /**
351
- * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}
352
- */
353
332
  protected async loadCore(storage: IChannelStorageService): Promise<void> {
354
333
  const content = await readAndParse<[string, Pact<T>][]>(storage, snapshotFileName);
355
334
  for (const [key, value] of content) {
@@ -357,19 +336,10 @@ export class PactMapClass<T = unknown>
357
336
  }
358
337
  }
359
338
 
360
- /**
361
- * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.initializeLocalCore}
362
- */
363
339
  protected initializeLocalCore(): void {}
364
340
 
365
- /**
366
- * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.onDisconnect}
367
- */
368
341
  protected onDisconnect(): void {}
369
342
 
370
- /**
371
- * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.reSubmitCore}
372
- */
373
343
  protected reSubmitCore(content: unknown, localOpMetadata: unknown): void {
374
344
  const pactMapOp = content as IPactMapOperation<T>;
375
345
 
@@ -38,9 +38,6 @@ export class PactMapFactory implements IChannelFactory<IPactMap> {
38
38
  return PactMapFactory.Attributes;
39
39
  }
40
40
 
41
- /**
42
- * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.load}
43
- */
44
41
  public async load(
45
42
  runtime: IFluidDataStoreRuntime,
46
43
  id: string,