@fluid-experimental/pact-map 2.0.0-internal.6.3.2 → 2.0.0-internal.6.4.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/.eslintrc.js CHANGED
@@ -18,7 +18,7 @@ module.exports = {
18
18
  files: ["*.spec.ts", "src/test/**"],
19
19
  rules: {
20
20
  // Test files are run in node only so additional node libraries can be used.
21
- "import/no-nodejs-modules": ["error", { allow: ["assert", "events"] }],
21
+ "import/no-nodejs-modules": ["error", { allow: ["node:assert"] }],
22
22
  },
23
23
  },
24
24
  ],
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @fluid-experimental/pact-map
2
2
 
3
+ ## 2.0.0-internal.6.4.0
4
+
5
+ Dependency updates only.
6
+
3
7
  ## 2.0.0-internal.6.3.0
4
8
 
5
9
  Dependency updates only.
package/dist/index.d.ts CHANGED
@@ -2,6 +2,6 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- export { IPactMap, IPactMapEvents, IAcceptedPact } from "./interfaces";
5
+ export type { IPactMap, IPactMapEvents, IAcceptedPact } from "./interfaces";
6
6
  export { PactMap } from "./pactMap";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,qCAAoC;AAA3B,kGAAA,OAAO,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { IPactMap, IPactMapEvents, IAcceptedPact } from \"./interfaces\";\nexport { PactMap } from \"./pactMap\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,qCAAoC;AAA3B,kGAAA,OAAO,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport type { IPactMap, IPactMapEvents, IAcceptedPact } from \"./interfaces\";\nexport { PactMap } from \"./pactMap\";\n"]}
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { ISharedObject, ISharedObjectEvents } from "@fluidframework/shared-object-base";
5
+ import { type ISharedObject, type ISharedObjectEvents } from "@fluidframework/shared-object-base";
6
6
  /**
7
7
  * IPactMapEvents are the events fired by an IPactMap.
8
8
  */
@@ -1 +1 @@
1
- {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAExF;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,mBAAmB;IAC1D;;OAEG;IACH,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,OAAE;CACjE;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC/B;;OAEG;IACH,KAAK,EAAE,CAAC,GAAG,SAAS,CAAC;IAErB;;;;OAIG;IACH,sBAAsB,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,aAAa,CAAC,cAAc,CAAC;IAC3E;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;IAEhC;;;OAGG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAE1D;;;;OAIG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAEhC;;;OAGG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;IAEvC;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;IAE7C;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B"}
1
+ {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAElG;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,mBAAmB;IAC1D;;OAEG;IACH,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,OAAE;CACjE;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC/B;;OAEG;IACH,KAAK,EAAE,CAAC,GAAG,SAAS,CAAC;IAErB;;;;OAIG;IACH,sBAAsB,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,aAAa,CAAC,cAAc,CAAC;IAC3E;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;IAEhC;;;OAGG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAE1D;;;;OAIG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAEhC;;;OAGG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;IAEvC;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;IAE7C;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B"}
@@ -1 +1 @@
1
- {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ISharedObject, ISharedObjectEvents } from \"@fluidframework/shared-object-base\";\n\n/**\n * IPactMapEvents are the events fired by an IPactMap.\n */\nexport interface IPactMapEvents extends ISharedObjectEvents {\n\t/**\n\t * Notifies when a new value goes pending or has been accepted.\n\t */\n\t(event: \"pending\" | \"accepted\", listener: (key: string) => void);\n}\n\n/**\n * Details of the accepted pact.\n */\nexport interface IAcceptedPact<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.\n\t *\n\t * For values set in detached state, it will be 0.\n\t */\n\tacceptedSequenceNumber: number;\n}\n\n/**\n * An IPactMap is a key-value storage, in which setting a value is done via a proposal system. All collaborators\n * who were connected at the time of the proposal must accept the change before it is considered accepted (or, if\n * those clients disconnect they are considered to have implicitly accepted). As a result, the value goes through\n * two phases:\n * 1. \"pending\" state where the proposal has been sequenced, but there are still outstanding acceptances\n * 2. \"accepted\" state where all clients who were connected at the time the proposal was made have either accepted\n * or disconnected.\n */\nexport interface IPactMap<T = unknown> extends ISharedObject<IPactMapEvents> {\n\t/**\n\t * Gets the accepted value for the given key.\n\t * @param key - The key to retrieve from\n\t */\n\tget(key: string): T | undefined;\n\n\t/**\n\t * Gets the accepted value and details for the given key.\n\t * @param key - The key to retrieve from\n\t */\n\tgetWithDetails(key: string): IAcceptedPact<T> | undefined;\n\n\t/**\n\t * Returns whether there is a pending value for the given key. Can be used to distinguish a pending delete vs.\n\t * nothing pending when getPending would just return undefined.\n\t * @param key - The key to check\n\t */\n\tisPending(key: string): boolean;\n\n\t/**\n\t * Gets the pending value for the given key.\n\t * @param key - The key to retrieve from\n\t */\n\tgetPending(key: string): T | undefined;\n\n\t/**\n\t * Sets the value for the given key. After setting the value, it will be in \"pending\" state until all connected\n\t * clients have approved the change. The accepted value remains unchanged until that time.\n\t * @param key - The key to set\n\t * @param value - The value to store\n\t */\n\tset(key: string, value: T | undefined): void;\n\n\t/**\n\t * Deletes the key/value pair at the given key. After issuing the delete, the delete is in \"pending\" state until\n\t * all connected clients have approved the delete. The accepted value remains unchanged until that time.\n\t * @param key - the key to delete\n\t */\n\tdelete(key: string): void;\n}\n"]}
1
+ {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { type ISharedObject, type ISharedObjectEvents } from \"@fluidframework/shared-object-base\";\n\n/**\n * IPactMapEvents are the events fired by an IPactMap.\n */\nexport interface IPactMapEvents extends ISharedObjectEvents {\n\t/**\n\t * Notifies when a new value goes pending or has been accepted.\n\t */\n\t(event: \"pending\" | \"accepted\", listener: (key: string) => void);\n}\n\n/**\n * Details of the accepted pact.\n */\nexport interface IAcceptedPact<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.\n\t *\n\t * For values set in detached state, it will be 0.\n\t */\n\tacceptedSequenceNumber: number;\n}\n\n/**\n * An IPactMap is a key-value storage, in which setting a value is done via a proposal system. All collaborators\n * who were connected at the time of the proposal must accept the change before it is considered accepted (or, if\n * those clients disconnect they are considered to have implicitly accepted). As a result, the value goes through\n * two phases:\n * 1. \"pending\" state where the proposal has been sequenced, but there are still outstanding acceptances\n * 2. \"accepted\" state where all clients who were connected at the time the proposal was made have either accepted\n * or disconnected.\n */\nexport interface IPactMap<T = unknown> extends ISharedObject<IPactMapEvents> {\n\t/**\n\t * Gets the accepted value for the given key.\n\t * @param key - The key to retrieve from\n\t */\n\tget(key: string): T | undefined;\n\n\t/**\n\t * Gets the accepted value and details for the given key.\n\t * @param key - The key to retrieve from\n\t */\n\tgetWithDetails(key: string): IAcceptedPact<T> | undefined;\n\n\t/**\n\t * Returns whether there is a pending value for the given key. Can be used to distinguish a pending delete vs.\n\t * nothing pending when getPending would just return undefined.\n\t * @param key - The key to check\n\t */\n\tisPending(key: string): boolean;\n\n\t/**\n\t * Gets the pending value for the given key.\n\t * @param key - The key to retrieve from\n\t */\n\tgetPending(key: string): T | undefined;\n\n\t/**\n\t * Sets the value for the given key. After setting the value, it will be in \"pending\" state until all connected\n\t * clients have approved the change. The accepted value remains unchanged until that time.\n\t * @param key - The key to set\n\t * @param value - The value to store\n\t */\n\tset(key: string, value: T | undefined): void;\n\n\t/**\n\t * Deletes the key/value pair at the given key. After issuing the delete, the delete is in \"pending\" state until\n\t * all connected clients have approved the delete. The accepted value remains unchanged until that time.\n\t * @param key - the key to delete\n\t */\n\tdelete(key: string): void;\n}\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 = "2.0.0-internal.6.3.2";
8
+ export declare const pkgVersion = "2.0.0-internal.6.4.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 = "2.0.0-internal.6.3.2";
11
+ exports.pkgVersion = "2.0.0-internal.6.4.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,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluid-experimental/pact-map\";\nexport const pkgVersion = \"2.0.0-internal.6.3.2\";\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,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluid-experimental/pact-map\";\nexport const pkgVersion = \"2.0.0-internal.6.4.0\";\n"]}
package/dist/pactMap.d.ts CHANGED
@@ -2,11 +2,11 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
6
- import { IChannelAttributes, IFluidDataStoreRuntime, IChannelStorageService, IChannelFactory } from "@fluidframework/datastore-definitions";
7
- import { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
8
- import { IFluidSerializer, SharedObject } from "@fluidframework/shared-object-base";
9
- import { IAcceptedPact, IPactMap, IPactMapEvents } from "./interfaces";
5
+ import { type ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
6
+ import { type IChannelAttributes, type IFluidDataStoreRuntime, type IChannelStorageService, type IChannelFactory } from "@fluidframework/datastore-definitions";
7
+ import { type ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
8
+ import { type IFluidSerializer, SharedObject } from "@fluidframework/shared-object-base";
9
+ import { type IAcceptedPact, type IPactMap, type IPactMapEvents } from "./interfaces";
10
10
  /**
11
11
  * The PactMap distributed data structure provides key/value storage with a cautious conflict resolution strategy.
12
12
  * This strategy optimizes for all clients being aware of the change prior to considering the value as accepted.
@@ -1 +1 @@
1
- {"version":3,"file":"pactMap.d.ts","sourceRoot":"","sources":["../src/pactMap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EAAE,yBAAyB,EAAe,MAAM,sCAAsC,CAAC;AAC9F,OAAO,EACN,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,eAAe,EACf,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAE5E,OAAO,EAEN,gBAAgB,EAChB,YAAY,EACZ,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAyEvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,qBAAa,OAAO,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,YAAY,CAAC,cAAc,CAAE,YAAW,QAAQ,CAAC,CAAC,CAAC;IAC5F;;;;;;OAMG;WACW,MAAM,CAAC,OAAO,EAAE,sBAAsB,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;IAI3E;;;;OAIG;WACW,UAAU,IAAI,eAAe;IAI3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAE1D,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,CA0BnC;IAEF,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAsBvC;IAEF;;;;;OAKG;IACH,SAAS,CAAC,aAAa,CAAC,UAAU,EAAE,gBAAgB,GAAG,qBAAqB;IAK5E;;;OAGG;cACa,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxE;;;OAGG;IACH,SAAS,CAAC,mBAAmB,IAAI,IAAI;IAErC;;;OAGG;IACH,SAAS,CAAC,YAAY,IAAI,IAAI;IAE9B;;;OAGG;IACH,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,GAAG,IAAI;IAuBxE;;;;;;;;OAQG;IACH,SAAS,CAAC,WAAW,CACpB,OAAO,EAAE,yBAAyB,EAClC,KAAK,EAAE,OAAO,EACd,eAAe,EAAE,OAAO,GACtB,IAAI;IA8BA,cAAc,IAAI,IAAI;CAG7B"}
1
+ {"version":3,"file":"pactMap.d.ts","sourceRoot":"","sources":["../src/pactMap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,OAAO,EAAE,KAAK,yBAAyB,EAAe,MAAM,sCAAsC,CAAC;AACnG,OAAO,EACN,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,eAAe,EACpB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAEjF,OAAO,EAEN,KAAK,gBAAgB,EACrB,YAAY,EACZ,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAyEtF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,qBAAa,OAAO,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,YAAY,CAAC,cAAc,CAAE,YAAW,QAAQ,CAAC,CAAC,CAAC;IAC5F;;;;;;OAMG;WACW,MAAM,CAAC,OAAO,EAAE,sBAAsB,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;IAI3E;;;;OAIG;WACW,UAAU,IAAI,eAAe;IAI3C,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,CA0BnC;IAEF,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAsBvC;IAEF;;;;;OAKG;IACH,SAAS,CAAC,aAAa,CAAC,UAAU,EAAE,gBAAgB,GAAG,qBAAqB;IAK5E;;;OAGG;cACa,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxE;;;OAGG;IACH,SAAS,CAAC,mBAAmB,IAAI,IAAI;IAErC;;;OAGG;IACH,SAAS,CAAC,YAAY,IAAI,IAAI;IAE9B;;;OAGG;IACH,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,GAAG,IAAI;IAuBxE;;;;;;;;OAQG;IACH,SAAS,CAAC,WAAW,CACpB,OAAO,EAAE,yBAAyB,EAClC,KAAK,EAAE,OAAO,EACd,eAAe,EAAE,OAAO,GACtB,IAAI;IAiCA,cAAc,IAAI,IAAI;CAG7B"}
package/dist/pactMap.js CHANGED
@@ -6,6 +6,8 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.PactMap = void 0;
8
8
  /* eslint-disable unicorn/numeric-separators-style */
9
+ // False positive: this is an import from the `events` package, not from Node.
10
+ // eslint-disable-next-line unicorn/prefer-node-protocol
9
11
  const events_1 = require("events");
10
12
  const core_utils_1 = require("@fluidframework/core-utils");
11
13
  const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
@@ -335,14 +337,17 @@ class PactMap extends shared_object_base_1.SharedObject {
335
337
  if (message.type === protocol_definitions_1.MessageType.Operation) {
336
338
  const op = message.contents;
337
339
  switch (op.type) {
338
- case "set":
340
+ case "set": {
339
341
  this.incomingOp.emit("set", op.key, op.value, op.refSeq, message.sequenceNumber);
340
342
  break;
341
- case "accept":
343
+ }
344
+ case "accept": {
342
345
  this.incomingOp.emit("accept", op.key, message.clientId, message.sequenceNumber);
343
346
  break;
344
- default:
347
+ }
348
+ default: {
345
349
  throw new Error("Unknown operation");
350
+ }
346
351
  }
347
352
  }
348
353
  }
@@ -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\n/* eslint-disable unicorn/numeric-separators-style */\n\nimport { EventEmitter } from \"events\";\n\nimport { assert } from \"@fluidframework/core-utils\";\nimport { ISequencedDocumentMessage, MessageType } from \"@fluidframework/protocol-definitions\";\nimport {\n\tIChannelAttributes,\n\tIFluidDataStoreRuntime,\n\tIChannelStorageService,\n\tIChannelFactory,\n} from \"@fluidframework/datastore-definitions\";\nimport { ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions\";\nimport { readAndParse } from \"@fluidframework/driver-utils\";\nimport {\n\tcreateSingleBlobSummary,\n\tIFluidSerializer,\n\tSharedObject,\n} from \"@fluidframework/shared-object-base\";\nimport { PactMapFactory } from \"./pactMapFactory\";\nimport { IAcceptedPact, IPactMap, IPactMapEvents } from \"./interfaces\";\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 * 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 */\nexport class PactMap<T = unknown> extends SharedObject<IPactMapEvents> implements IPactMap<T> {\n\t/**\n\t * Create a new PactMap\n\t *\n\t * @param runtime - data store runtime the new PactMap belongs to\n\t * @param id - optional name of the PactMap\n\t * @returns newly created PactMap (but not attached yet)\n\t */\n\tpublic static create(runtime: IFluidDataStoreRuntime, id?: string): PactMap {\n\t\treturn runtime.createChannel(id, PactMapFactory.Type) as PactMap;\n\t}\n\n\t/**\n\t * Get a factory for PactMap to register with the data store.\n\t *\n\t * @returns a factory that creates and loads PactMaps\n\t */\n\tpublic static getFactory(): IChannelFactory {\n\t\treturn new PactMapFactory();\n\t}\n\n\tprivate readonly values: Map<string, Pact<T>> = new Map();\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.runtime.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\t// We don't resubmit accepts on reconnect so this should only run for expected accepts.\n\t\tassert(pending !== undefined, 0x2f8 /* Unexpected accept op, nothing pending */);\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.runtime.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 * @internal\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 * @internal\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 * @internal\n\t */\n\tprotected initializeLocalCore(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.onDisconnect}\n\t * @internal\n\t */\n\tprotected onDisconnect(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.reSubmitCore}\n\t * @internal\n\t */\n\tprotected reSubmitCore(content: unknown, localOpMetadata: unknown): void {\n\t\tconst pactMapOp = content as IPactMapOperation<T>;\n\t\t// Filter out accept messages - if we're coming back from a disconnect, our acceptance is never required\n\t\t// because we're implicitly removed from the list of expected accepts.\n\t\tif (pactMapOp.type === \"accept\") {\n\t\t\treturn;\n\t\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\tcurrentValue !== undefined &&\n\t\t\t(currentValue.pending !== undefined ||\n\t\t\t\tpactMapOp.refSeq < currentValue.accepted?.sequenceNumber)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Otherwise we can resubmit\n\t\tthis.submitLocalMessage(pactMapOp, localOpMetadata);\n\t}\n\n\t/**\n\t * Process a PactMap operation\n\t *\n\t * @param message - the message to prepare\n\t * @param local - whether the message was sent by the local client\n\t * @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.\n\t * For messages from a remote client, this will be undefined.\n\t * @internal\n\t */\n\tprotected processCore(\n\t\tmessage: ISequencedDocumentMessage,\n\t\tlocal: boolean,\n\t\tlocalOpMetadata: unknown,\n\t): void {\n\t\tif (message.type === MessageType.Operation) {\n\t\t\tconst op = message.contents as IPactMapOperation<T>;\n\n\t\t\tswitch (op.type) {\n\t\t\t\tcase \"set\":\n\t\t\t\t\tthis.incomingOp.emit(\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\tmessage.sequenceNumber,\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\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\tmessage.clientId,\n\t\t\t\t\t\tmessage.sequenceNumber,\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(\"Unknown operation\");\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic 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\n/* eslint-disable unicorn/numeric-separators-style */\n\n// False positive: this is an import from the `events` package, not from Node.\n// eslint-disable-next-line unicorn/prefer-node-protocol\nimport { EventEmitter } from \"events\";\n\nimport { assert } from \"@fluidframework/core-utils\";\nimport { type ISequencedDocumentMessage, MessageType } from \"@fluidframework/protocol-definitions\";\nimport {\n\ttype IChannelAttributes,\n\ttype IFluidDataStoreRuntime,\n\ttype IChannelStorageService,\n\ttype IChannelFactory,\n} from \"@fluidframework/datastore-definitions\";\nimport { type ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions\";\nimport { readAndParse } from \"@fluidframework/driver-utils\";\nimport {\n\tcreateSingleBlobSummary,\n\ttype IFluidSerializer,\n\tSharedObject,\n} from \"@fluidframework/shared-object-base\";\nimport { PactMapFactory } from \"./pactMapFactory\";\nimport { type IAcceptedPact, type IPactMap, type IPactMapEvents } from \"./interfaces\";\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 * 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 */\nexport class PactMap<T = unknown> extends SharedObject<IPactMapEvents> implements IPactMap<T> {\n\t/**\n\t * Create a new PactMap\n\t *\n\t * @param runtime - data store runtime the new PactMap belongs to\n\t * @param id - optional name of the PactMap\n\t * @returns newly created PactMap (but not attached yet)\n\t */\n\tpublic static create(runtime: IFluidDataStoreRuntime, id?: string): PactMap {\n\t\treturn runtime.createChannel(id, PactMapFactory.Type) as PactMap;\n\t}\n\n\t/**\n\t * Get a factory for PactMap to register with the data store.\n\t *\n\t * @returns a factory that creates and loads PactMaps\n\t */\n\tpublic static getFactory(): IChannelFactory {\n\t\treturn new PactMapFactory();\n\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.runtime.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\t// We don't resubmit accepts on reconnect so this should only run for expected accepts.\n\t\tassert(pending !== undefined, 0x2f8 /* Unexpected accept op, nothing pending */);\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.runtime.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 * @internal\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 * @internal\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 * @internal\n\t */\n\tprotected initializeLocalCore(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.onDisconnect}\n\t * @internal\n\t */\n\tprotected onDisconnect(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.reSubmitCore}\n\t * @internal\n\t */\n\tprotected reSubmitCore(content: unknown, localOpMetadata: unknown): void {\n\t\tconst pactMapOp = content as IPactMapOperation<T>;\n\t\t// Filter out accept messages - if we're coming back from a disconnect, our acceptance is never required\n\t\t// because we're implicitly removed from the list of expected accepts.\n\t\tif (pactMapOp.type === \"accept\") {\n\t\t\treturn;\n\t\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\tcurrentValue !== undefined &&\n\t\t\t(currentValue.pending !== undefined ||\n\t\t\t\tpactMapOp.refSeq < currentValue.accepted?.sequenceNumber)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Otherwise we can resubmit\n\t\tthis.submitLocalMessage(pactMapOp, localOpMetadata);\n\t}\n\n\t/**\n\t * Process a PactMap operation\n\t *\n\t * @param message - the message to prepare\n\t * @param local - whether the message was sent by the local client\n\t * @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.\n\t * For messages from a remote client, this will be undefined.\n\t * @internal\n\t */\n\tprotected processCore(\n\t\tmessage: ISequencedDocumentMessage,\n\t\tlocal: boolean,\n\t\tlocalOpMetadata: unknown,\n\t): void {\n\t\tif (message.type === MessageType.Operation) {\n\t\t\tconst op = message.contents as IPactMapOperation<T>;\n\n\t\t\tswitch (op.type) {\n\t\t\t\tcase \"set\": {\n\t\t\t\t\tthis.incomingOp.emit(\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\tmessage.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\tmessage.clientId,\n\t\t\t\t\t\tmessage.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\tpublic applyStashedOp(): void {\n\t\tthrow new Error(\"not implemented\");\n\t}\n}\n"]}
@@ -2,8 +2,8 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { IChannelAttributes, IFluidDataStoreRuntime, IChannelServices, IChannelFactory } from "@fluidframework/datastore-definitions";
6
- import { IPactMap } from "./interfaces";
5
+ import { type IChannelAttributes, type IFluidDataStoreRuntime, type IChannelServices, type IChannelFactory } from "@fluidframework/datastore-definitions";
6
+ import { type IPactMap } from "./interfaces";
7
7
  /**
8
8
  * The factory that produces the PactMap
9
9
  */
@@ -1 +1 @@
1
- {"version":3,"file":"pactMapFactory.d.ts","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,kBAAkB,EAClB,sBAAsB,EACtB,gBAAgB,EAChB,eAAe,EACf,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAGxC;;GAEG;AACH,qBAAa,cAAe,YAAW,eAAe;IACrD,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"}
1
+ {"version":3,"file":"pactMapFactory.d.ts","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C;;GAEG;AACH,qBAAa,cAAe,YAAW,eAAe;IACrD,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"}
@@ -1 +1 @@
1
- {"version":3,"file":"pactMapFactory.js","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAQH,uCAAoC;AAEpC,qDAA8C;AAE9C;;GAEG;AACH,MAAa,cAAc;IAS1B,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,iBAAO,CAAC,EAAE,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QACrD,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,iBAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3D,OAAO,CAAC,eAAe,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC;IAChB,CAAC;;AAnCF,wCAoCC;AAnCuB,mBAAI,GAAG,4CAA4C,CAAC;AAEpD,yBAAU,GAAuB;IACvD,IAAI,EAAE,cAAc,CAAC,IAAI;IACzB,qBAAqB,EAAE,KAAK;IAC5B,cAAc,EAAE,2BAAU;CAC1B,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tIChannelAttributes,\n\tIFluidDataStoreRuntime,\n\tIChannelServices,\n\tIChannelFactory,\n} from \"@fluidframework/datastore-definitions\";\nimport { PactMap } from \"./pactMap\";\nimport { IPactMap } from \"./interfaces\";\nimport { pkgVersion } from \"./packageVersion\";\n\n/**\n * The factory that produces the PactMap\n */\nexport class PactMapFactory implements IChannelFactory {\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 PactMap(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 PactMap(id, document, this.attributes);\n\t\tpactMap.initializeLocal();\n\t\treturn pactMap;\n\t}\n}\n"]}
1
+ {"version":3,"file":"pactMapFactory.js","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAQH,uCAAoC;AAEpC,qDAA8C;AAE9C;;GAEG;AACH,MAAa,cAAc;IAS1B,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,iBAAO,CAAC,EAAE,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QACrD,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,iBAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3D,OAAO,CAAC,eAAe,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC;IAChB,CAAC;;AAnCF,wCAoCC;AAnCuB,mBAAI,GAAG,4CAA4C,CAAC;AAEpD,yBAAU,GAAuB;IACvD,IAAI,EAAE,cAAc,CAAC,IAAI;IACzB,qBAAqB,EAAE,KAAK;IAC5B,cAAc,EAAE,2BAAU;CAC1B,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\ttype IChannelAttributes,\n\ttype IFluidDataStoreRuntime,\n\ttype IChannelServices,\n\ttype IChannelFactory,\n} from \"@fluidframework/datastore-definitions\";\nimport { PactMap } from \"./pactMap\";\nimport { type IPactMap } from \"./interfaces\";\nimport { pkgVersion } from \"./packageVersion\";\n\n/**\n * The factory that produces the PactMap\n */\nexport class PactMapFactory implements IChannelFactory {\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 PactMap(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 PactMap(id, document, this.attributes);\n\t\tpactMap.initializeLocal();\n\t\treturn pactMap;\n\t}\n}\n"]}
package/lib/index.d.ts CHANGED
@@ -2,6 +2,6 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- export { IPactMap, IPactMapEvents, IAcceptedPact } from "./interfaces";
5
+ export type { IPactMap, IPactMapEvents, IAcceptedPact } from "./interfaces";
6
6
  export { PactMap } from "./pactMap";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC"}
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { IPactMap, IPactMapEvents, IAcceptedPact } from \"./interfaces\";\nexport { PactMap } from \"./pactMap\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport type { IPactMap, IPactMapEvents, IAcceptedPact } from \"./interfaces\";\nexport { PactMap } from \"./pactMap\";\n"]}
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { ISharedObject, ISharedObjectEvents } from "@fluidframework/shared-object-base";
5
+ import { type ISharedObject, type ISharedObjectEvents } from "@fluidframework/shared-object-base";
6
6
  /**
7
7
  * IPactMapEvents are the events fired by an IPactMap.
8
8
  */
@@ -1 +1 @@
1
- {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAExF;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,mBAAmB;IAC1D;;OAEG;IACH,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,OAAE;CACjE;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC/B;;OAEG;IACH,KAAK,EAAE,CAAC,GAAG,SAAS,CAAC;IAErB;;;;OAIG;IACH,sBAAsB,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,aAAa,CAAC,cAAc,CAAC;IAC3E;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;IAEhC;;;OAGG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAE1D;;;;OAIG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAEhC;;;OAGG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;IAEvC;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;IAE7C;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B"}
1
+ {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAElG;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,mBAAmB;IAC1D;;OAEG;IACH,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,OAAE;CACjE;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC/B;;OAEG;IACH,KAAK,EAAE,CAAC,GAAG,SAAS,CAAC;IAErB;;;;OAIG;IACH,sBAAsB,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,aAAa,CAAC,cAAc,CAAC;IAC3E;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;IAEhC;;;OAGG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAE1D;;;;OAIG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAEhC;;;OAGG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;IAEvC;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;IAE7C;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B"}
@@ -1 +1 @@
1
- {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ISharedObject, ISharedObjectEvents } from \"@fluidframework/shared-object-base\";\n\n/**\n * IPactMapEvents are the events fired by an IPactMap.\n */\nexport interface IPactMapEvents extends ISharedObjectEvents {\n\t/**\n\t * Notifies when a new value goes pending or has been accepted.\n\t */\n\t(event: \"pending\" | \"accepted\", listener: (key: string) => void);\n}\n\n/**\n * Details of the accepted pact.\n */\nexport interface IAcceptedPact<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.\n\t *\n\t * For values set in detached state, it will be 0.\n\t */\n\tacceptedSequenceNumber: number;\n}\n\n/**\n * An IPactMap is a key-value storage, in which setting a value is done via a proposal system. All collaborators\n * who were connected at the time of the proposal must accept the change before it is considered accepted (or, if\n * those clients disconnect they are considered to have implicitly accepted). As a result, the value goes through\n * two phases:\n * 1. \"pending\" state where the proposal has been sequenced, but there are still outstanding acceptances\n * 2. \"accepted\" state where all clients who were connected at the time the proposal was made have either accepted\n * or disconnected.\n */\nexport interface IPactMap<T = unknown> extends ISharedObject<IPactMapEvents> {\n\t/**\n\t * Gets the accepted value for the given key.\n\t * @param key - The key to retrieve from\n\t */\n\tget(key: string): T | undefined;\n\n\t/**\n\t * Gets the accepted value and details for the given key.\n\t * @param key - The key to retrieve from\n\t */\n\tgetWithDetails(key: string): IAcceptedPact<T> | undefined;\n\n\t/**\n\t * Returns whether there is a pending value for the given key. Can be used to distinguish a pending delete vs.\n\t * nothing pending when getPending would just return undefined.\n\t * @param key - The key to check\n\t */\n\tisPending(key: string): boolean;\n\n\t/**\n\t * Gets the pending value for the given key.\n\t * @param key - The key to retrieve from\n\t */\n\tgetPending(key: string): T | undefined;\n\n\t/**\n\t * Sets the value for the given key. After setting the value, it will be in \"pending\" state until all connected\n\t * clients have approved the change. The accepted value remains unchanged until that time.\n\t * @param key - The key to set\n\t * @param value - The value to store\n\t */\n\tset(key: string, value: T | undefined): void;\n\n\t/**\n\t * Deletes the key/value pair at the given key. After issuing the delete, the delete is in \"pending\" state until\n\t * all connected clients have approved the delete. The accepted value remains unchanged until that time.\n\t * @param key - the key to delete\n\t */\n\tdelete(key: string): void;\n}\n"]}
1
+ {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { type ISharedObject, type ISharedObjectEvents } from \"@fluidframework/shared-object-base\";\n\n/**\n * IPactMapEvents are the events fired by an IPactMap.\n */\nexport interface IPactMapEvents extends ISharedObjectEvents {\n\t/**\n\t * Notifies when a new value goes pending or has been accepted.\n\t */\n\t(event: \"pending\" | \"accepted\", listener: (key: string) => void);\n}\n\n/**\n * Details of the accepted pact.\n */\nexport interface IAcceptedPact<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.\n\t *\n\t * For values set in detached state, it will be 0.\n\t */\n\tacceptedSequenceNumber: number;\n}\n\n/**\n * An IPactMap is a key-value storage, in which setting a value is done via a proposal system. All collaborators\n * who were connected at the time of the proposal must accept the change before it is considered accepted (or, if\n * those clients disconnect they are considered to have implicitly accepted). As a result, the value goes through\n * two phases:\n * 1. \"pending\" state where the proposal has been sequenced, but there are still outstanding acceptances\n * 2. \"accepted\" state where all clients who were connected at the time the proposal was made have either accepted\n * or disconnected.\n */\nexport interface IPactMap<T = unknown> extends ISharedObject<IPactMapEvents> {\n\t/**\n\t * Gets the accepted value for the given key.\n\t * @param key - The key to retrieve from\n\t */\n\tget(key: string): T | undefined;\n\n\t/**\n\t * Gets the accepted value and details for the given key.\n\t * @param key - The key to retrieve from\n\t */\n\tgetWithDetails(key: string): IAcceptedPact<T> | undefined;\n\n\t/**\n\t * Returns whether there is a pending value for the given key. Can be used to distinguish a pending delete vs.\n\t * nothing pending when getPending would just return undefined.\n\t * @param key - The key to check\n\t */\n\tisPending(key: string): boolean;\n\n\t/**\n\t * Gets the pending value for the given key.\n\t * @param key - The key to retrieve from\n\t */\n\tgetPending(key: string): T | undefined;\n\n\t/**\n\t * Sets the value for the given key. After setting the value, it will be in \"pending\" state until all connected\n\t * clients have approved the change. The accepted value remains unchanged until that time.\n\t * @param key - The key to set\n\t * @param value - The value to store\n\t */\n\tset(key: string, value: T | undefined): void;\n\n\t/**\n\t * Deletes the key/value pair at the given key. After issuing the delete, the delete is in \"pending\" state until\n\t * all connected clients have approved the delete. The accepted value remains unchanged until that time.\n\t * @param key - the key to delete\n\t */\n\tdelete(key: string): void;\n}\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 = "2.0.0-internal.6.3.2";
8
+ export declare const pkgVersion = "2.0.0-internal.6.4.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 = "2.0.0-internal.6.3.2";
8
+ export const pkgVersion = "2.0.0-internal.6.4.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,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluid-experimental/pact-map\";\nexport const pkgVersion = \"2.0.0-internal.6.3.2\";\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,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluid-experimental/pact-map\";\nexport const pkgVersion = \"2.0.0-internal.6.4.0\";\n"]}
package/lib/pactMap.d.ts CHANGED
@@ -2,11 +2,11 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
6
- import { IChannelAttributes, IFluidDataStoreRuntime, IChannelStorageService, IChannelFactory } from "@fluidframework/datastore-definitions";
7
- import { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
8
- import { IFluidSerializer, SharedObject } from "@fluidframework/shared-object-base";
9
- import { IAcceptedPact, IPactMap, IPactMapEvents } from "./interfaces";
5
+ import { type ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
6
+ import { type IChannelAttributes, type IFluidDataStoreRuntime, type IChannelStorageService, type IChannelFactory } from "@fluidframework/datastore-definitions";
7
+ import { type ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
8
+ import { type IFluidSerializer, SharedObject } from "@fluidframework/shared-object-base";
9
+ import { type IAcceptedPact, type IPactMap, type IPactMapEvents } from "./interfaces";
10
10
  /**
11
11
  * The PactMap distributed data structure provides key/value storage with a cautious conflict resolution strategy.
12
12
  * This strategy optimizes for all clients being aware of the change prior to considering the value as accepted.
@@ -1 +1 @@
1
- {"version":3,"file":"pactMap.d.ts","sourceRoot":"","sources":["../src/pactMap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EAAE,yBAAyB,EAAe,MAAM,sCAAsC,CAAC;AAC9F,OAAO,EACN,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,eAAe,EACf,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAE5E,OAAO,EAEN,gBAAgB,EAChB,YAAY,EACZ,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAyEvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,qBAAa,OAAO,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,YAAY,CAAC,cAAc,CAAE,YAAW,QAAQ,CAAC,CAAC,CAAC;IAC5F;;;;;;OAMG;WACW,MAAM,CAAC,OAAO,EAAE,sBAAsB,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;IAI3E;;;;OAIG;WACW,UAAU,IAAI,eAAe;IAI3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAE1D,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,CA0BnC;IAEF,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAsBvC;IAEF;;;;;OAKG;IACH,SAAS,CAAC,aAAa,CAAC,UAAU,EAAE,gBAAgB,GAAG,qBAAqB;IAK5E;;;OAGG;cACa,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxE;;;OAGG;IACH,SAAS,CAAC,mBAAmB,IAAI,IAAI;IAErC;;;OAGG;IACH,SAAS,CAAC,YAAY,IAAI,IAAI;IAE9B;;;OAGG;IACH,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,GAAG,IAAI;IAuBxE;;;;;;;;OAQG;IACH,SAAS,CAAC,WAAW,CACpB,OAAO,EAAE,yBAAyB,EAClC,KAAK,EAAE,OAAO,EACd,eAAe,EAAE,OAAO,GACtB,IAAI;IA8BA,cAAc,IAAI,IAAI;CAG7B"}
1
+ {"version":3,"file":"pactMap.d.ts","sourceRoot":"","sources":["../src/pactMap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,OAAO,EAAE,KAAK,yBAAyB,EAAe,MAAM,sCAAsC,CAAC;AACnG,OAAO,EACN,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,eAAe,EACpB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAEjF,OAAO,EAEN,KAAK,gBAAgB,EACrB,YAAY,EACZ,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAyEtF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,qBAAa,OAAO,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,YAAY,CAAC,cAAc,CAAE,YAAW,QAAQ,CAAC,CAAC,CAAC;IAC5F;;;;;;OAMG;WACW,MAAM,CAAC,OAAO,EAAE,sBAAsB,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;IAI3E;;;;OAIG;WACW,UAAU,IAAI,eAAe;IAI3C,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,CA0BnC;IAEF,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAsBvC;IAEF;;;;;OAKG;IACH,SAAS,CAAC,aAAa,CAAC,UAAU,EAAE,gBAAgB,GAAG,qBAAqB;IAK5E;;;OAGG;cACa,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxE;;;OAGG;IACH,SAAS,CAAC,mBAAmB,IAAI,IAAI;IAErC;;;OAGG;IACH,SAAS,CAAC,YAAY,IAAI,IAAI;IAE9B;;;OAGG;IACH,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,GAAG,IAAI;IAuBxE;;;;;;;;OAQG;IACH,SAAS,CAAC,WAAW,CACpB,OAAO,EAAE,yBAAyB,EAClC,KAAK,EAAE,OAAO,EACd,eAAe,EAAE,OAAO,GACtB,IAAI;IAiCA,cAAc,IAAI,IAAI;CAG7B"}
package/lib/pactMap.js CHANGED
@@ -3,6 +3,8 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  /* eslint-disable unicorn/numeric-separators-style */
6
+ // False positive: this is an import from the `events` package, not from Node.
7
+ // eslint-disable-next-line unicorn/prefer-node-protocol
6
8
  import { EventEmitter } from "events";
7
9
  import { assert } from "@fluidframework/core-utils";
8
10
  import { MessageType } from "@fluidframework/protocol-definitions";
@@ -332,14 +334,17 @@ export class PactMap extends SharedObject {
332
334
  if (message.type === MessageType.Operation) {
333
335
  const op = message.contents;
334
336
  switch (op.type) {
335
- case "set":
337
+ case "set": {
336
338
  this.incomingOp.emit("set", op.key, op.value, op.refSeq, message.sequenceNumber);
337
339
  break;
338
- case "accept":
340
+ }
341
+ case "accept": {
339
342
  this.incomingOp.emit("accept", op.key, message.clientId, message.sequenceNumber);
340
343
  break;
341
- default:
344
+ }
345
+ default: {
342
346
  throw new Error("Unknown operation");
347
+ }
343
348
  }
344
349
  }
345
350
  }
@@ -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\n/* eslint-disable unicorn/numeric-separators-style */\n\nimport { EventEmitter } from \"events\";\n\nimport { assert } from \"@fluidframework/core-utils\";\nimport { ISequencedDocumentMessage, MessageType } from \"@fluidframework/protocol-definitions\";\nimport {\n\tIChannelAttributes,\n\tIFluidDataStoreRuntime,\n\tIChannelStorageService,\n\tIChannelFactory,\n} from \"@fluidframework/datastore-definitions\";\nimport { ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions\";\nimport { readAndParse } from \"@fluidframework/driver-utils\";\nimport {\n\tcreateSingleBlobSummary,\n\tIFluidSerializer,\n\tSharedObject,\n} from \"@fluidframework/shared-object-base\";\nimport { PactMapFactory } from \"./pactMapFactory\";\nimport { IAcceptedPact, IPactMap, IPactMapEvents } from \"./interfaces\";\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 * 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 */\nexport class PactMap<T = unknown> extends SharedObject<IPactMapEvents> implements IPactMap<T> {\n\t/**\n\t * Create a new PactMap\n\t *\n\t * @param runtime - data store runtime the new PactMap belongs to\n\t * @param id - optional name of the PactMap\n\t * @returns newly created PactMap (but not attached yet)\n\t */\n\tpublic static create(runtime: IFluidDataStoreRuntime, id?: string): PactMap {\n\t\treturn runtime.createChannel(id, PactMapFactory.Type) as PactMap;\n\t}\n\n\t/**\n\t * Get a factory for PactMap to register with the data store.\n\t *\n\t * @returns a factory that creates and loads PactMaps\n\t */\n\tpublic static getFactory(): IChannelFactory {\n\t\treturn new PactMapFactory();\n\t}\n\n\tprivate readonly values: Map<string, Pact<T>> = new Map();\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.runtime.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\t// We don't resubmit accepts on reconnect so this should only run for expected accepts.\n\t\tassert(pending !== undefined, 0x2f8 /* Unexpected accept op, nothing pending */);\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.runtime.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 * @internal\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 * @internal\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 * @internal\n\t */\n\tprotected initializeLocalCore(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.onDisconnect}\n\t * @internal\n\t */\n\tprotected onDisconnect(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.reSubmitCore}\n\t * @internal\n\t */\n\tprotected reSubmitCore(content: unknown, localOpMetadata: unknown): void {\n\t\tconst pactMapOp = content as IPactMapOperation<T>;\n\t\t// Filter out accept messages - if we're coming back from a disconnect, our acceptance is never required\n\t\t// because we're implicitly removed from the list of expected accepts.\n\t\tif (pactMapOp.type === \"accept\") {\n\t\t\treturn;\n\t\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\tcurrentValue !== undefined &&\n\t\t\t(currentValue.pending !== undefined ||\n\t\t\t\tpactMapOp.refSeq < currentValue.accepted?.sequenceNumber)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Otherwise we can resubmit\n\t\tthis.submitLocalMessage(pactMapOp, localOpMetadata);\n\t}\n\n\t/**\n\t * Process a PactMap operation\n\t *\n\t * @param message - the message to prepare\n\t * @param local - whether the message was sent by the local client\n\t * @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.\n\t * For messages from a remote client, this will be undefined.\n\t * @internal\n\t */\n\tprotected processCore(\n\t\tmessage: ISequencedDocumentMessage,\n\t\tlocal: boolean,\n\t\tlocalOpMetadata: unknown,\n\t): void {\n\t\tif (message.type === MessageType.Operation) {\n\t\t\tconst op = message.contents as IPactMapOperation<T>;\n\n\t\t\tswitch (op.type) {\n\t\t\t\tcase \"set\":\n\t\t\t\t\tthis.incomingOp.emit(\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\tmessage.sequenceNumber,\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\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\tmessage.clientId,\n\t\t\t\t\t\tmessage.sequenceNumber,\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(\"Unknown operation\");\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic 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\n/* eslint-disable unicorn/numeric-separators-style */\n\n// False positive: this is an import from the `events` package, not from Node.\n// eslint-disable-next-line unicorn/prefer-node-protocol\nimport { EventEmitter } from \"events\";\n\nimport { assert } from \"@fluidframework/core-utils\";\nimport { type ISequencedDocumentMessage, MessageType } from \"@fluidframework/protocol-definitions\";\nimport {\n\ttype IChannelAttributes,\n\ttype IFluidDataStoreRuntime,\n\ttype IChannelStorageService,\n\ttype IChannelFactory,\n} from \"@fluidframework/datastore-definitions\";\nimport { type ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions\";\nimport { readAndParse } from \"@fluidframework/driver-utils\";\nimport {\n\tcreateSingleBlobSummary,\n\ttype IFluidSerializer,\n\tSharedObject,\n} from \"@fluidframework/shared-object-base\";\nimport { PactMapFactory } from \"./pactMapFactory\";\nimport { type IAcceptedPact, type IPactMap, type IPactMapEvents } from \"./interfaces\";\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 * 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 */\nexport class PactMap<T = unknown> extends SharedObject<IPactMapEvents> implements IPactMap<T> {\n\t/**\n\t * Create a new PactMap\n\t *\n\t * @param runtime - data store runtime the new PactMap belongs to\n\t * @param id - optional name of the PactMap\n\t * @returns newly created PactMap (but not attached yet)\n\t */\n\tpublic static create(runtime: IFluidDataStoreRuntime, id?: string): PactMap {\n\t\treturn runtime.createChannel(id, PactMapFactory.Type) as PactMap;\n\t}\n\n\t/**\n\t * Get a factory for PactMap to register with the data store.\n\t *\n\t * @returns a factory that creates and loads PactMaps\n\t */\n\tpublic static getFactory(): IChannelFactory {\n\t\treturn new PactMapFactory();\n\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.runtime.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\t// We don't resubmit accepts on reconnect so this should only run for expected accepts.\n\t\tassert(pending !== undefined, 0x2f8 /* Unexpected accept op, nothing pending */);\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.runtime.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 * @internal\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 * @internal\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 * @internal\n\t */\n\tprotected initializeLocalCore(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.onDisconnect}\n\t * @internal\n\t */\n\tprotected onDisconnect(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.reSubmitCore}\n\t * @internal\n\t */\n\tprotected reSubmitCore(content: unknown, localOpMetadata: unknown): void {\n\t\tconst pactMapOp = content as IPactMapOperation<T>;\n\t\t// Filter out accept messages - if we're coming back from a disconnect, our acceptance is never required\n\t\t// because we're implicitly removed from the list of expected accepts.\n\t\tif (pactMapOp.type === \"accept\") {\n\t\t\treturn;\n\t\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\tcurrentValue !== undefined &&\n\t\t\t(currentValue.pending !== undefined ||\n\t\t\t\tpactMapOp.refSeq < currentValue.accepted?.sequenceNumber)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Otherwise we can resubmit\n\t\tthis.submitLocalMessage(pactMapOp, localOpMetadata);\n\t}\n\n\t/**\n\t * Process a PactMap operation\n\t *\n\t * @param message - the message to prepare\n\t * @param local - whether the message was sent by the local client\n\t * @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.\n\t * For messages from a remote client, this will be undefined.\n\t * @internal\n\t */\n\tprotected processCore(\n\t\tmessage: ISequencedDocumentMessage,\n\t\tlocal: boolean,\n\t\tlocalOpMetadata: unknown,\n\t): void {\n\t\tif (message.type === MessageType.Operation) {\n\t\t\tconst op = message.contents as IPactMapOperation<T>;\n\n\t\t\tswitch (op.type) {\n\t\t\t\tcase \"set\": {\n\t\t\t\t\tthis.incomingOp.emit(\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\tmessage.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\tmessage.clientId,\n\t\t\t\t\t\tmessage.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\tpublic applyStashedOp(): void {\n\t\tthrow new Error(\"not implemented\");\n\t}\n}\n"]}
@@ -2,8 +2,8 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { IChannelAttributes, IFluidDataStoreRuntime, IChannelServices, IChannelFactory } from "@fluidframework/datastore-definitions";
6
- import { IPactMap } from "./interfaces";
5
+ import { type IChannelAttributes, type IFluidDataStoreRuntime, type IChannelServices, type IChannelFactory } from "@fluidframework/datastore-definitions";
6
+ import { type IPactMap } from "./interfaces";
7
7
  /**
8
8
  * The factory that produces the PactMap
9
9
  */
@@ -1 +1 @@
1
- {"version":3,"file":"pactMapFactory.d.ts","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,kBAAkB,EAClB,sBAAsB,EACtB,gBAAgB,EAChB,eAAe,EACf,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAGxC;;GAEG;AACH,qBAAa,cAAe,YAAW,eAAe;IACrD,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"}
1
+ {"version":3,"file":"pactMapFactory.d.ts","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C;;GAEG;AACH,qBAAa,cAAe,YAAW,eAAe;IACrD,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"}
@@ -1 +1 @@
1
- {"version":3,"file":"pactMapFactory.js","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;GAEG;AACH,MAAM,OAAO,cAAc;IAS1B,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,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QACrD,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,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3D,OAAO,CAAC,eAAe,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC;IAChB,CAAC;;AAlCsB,mBAAI,GAAG,4CAA4C,CAAC;AAEpD,yBAAU,GAAuB;IACvD,IAAI,EAAE,cAAc,CAAC,IAAI;IACzB,qBAAqB,EAAE,KAAK;IAC5B,cAAc,EAAE,UAAU;CAC1B,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tIChannelAttributes,\n\tIFluidDataStoreRuntime,\n\tIChannelServices,\n\tIChannelFactory,\n} from \"@fluidframework/datastore-definitions\";\nimport { PactMap } from \"./pactMap\";\nimport { IPactMap } from \"./interfaces\";\nimport { pkgVersion } from \"./packageVersion\";\n\n/**\n * The factory that produces the PactMap\n */\nexport class PactMapFactory implements IChannelFactory {\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 PactMap(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 PactMap(id, document, this.attributes);\n\t\tpactMap.initializeLocal();\n\t\treturn pactMap;\n\t}\n}\n"]}
1
+ {"version":3,"file":"pactMapFactory.js","sourceRoot":"","sources":["../src/pactMapFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;GAEG;AACH,MAAM,OAAO,cAAc;IAS1B,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,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QACrD,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,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3D,OAAO,CAAC,eAAe,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC;IAChB,CAAC;;AAlCsB,mBAAI,GAAG,4CAA4C,CAAC;AAEpD,yBAAU,GAAuB;IACvD,IAAI,EAAE,cAAc,CAAC,IAAI;IACzB,qBAAqB,EAAE,KAAK;IAC5B,cAAc,EAAE,UAAU;CAC1B,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\ttype IChannelAttributes,\n\ttype IFluidDataStoreRuntime,\n\ttype IChannelServices,\n\ttype IChannelFactory,\n} from \"@fluidframework/datastore-definitions\";\nimport { PactMap } from \"./pactMap\";\nimport { type IPactMap } from \"./interfaces\";\nimport { pkgVersion } from \"./packageVersion\";\n\n/**\n * The factory that produces the PactMap\n */\nexport class PactMapFactory implements IChannelFactory {\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 PactMap(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 PactMap(id, document, this.attributes);\n\t\tpactMap.initializeLocal();\n\t\treturn pactMap;\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluid-experimental/pact-map",
3
- "version": "2.0.0-internal.6.3.2",
3
+ "version": "2.0.0-internal.6.4.0",
4
4
  "description": "Distributed data structure for key-value pairs using pact consensus",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -35,22 +35,22 @@
35
35
  "temp-directory": "nyc/.nyc_output"
36
36
  },
37
37
  "dependencies": {
38
- "@fluidframework/core-interfaces": ">=2.0.0-internal.6.3.2 <2.0.0-internal.6.4.0",
39
- "@fluidframework/core-utils": ">=2.0.0-internal.6.3.2 <2.0.0-internal.6.4.0",
40
- "@fluidframework/datastore-definitions": ">=2.0.0-internal.6.3.2 <2.0.0-internal.6.4.0",
41
- "@fluidframework/driver-utils": ">=2.0.0-internal.6.3.2 <2.0.0-internal.6.4.0",
38
+ "@fluidframework/core-interfaces": ">=2.0.0-internal.6.4.0 <2.0.0-internal.6.5.0",
39
+ "@fluidframework/core-utils": ">=2.0.0-internal.6.4.0 <2.0.0-internal.6.5.0",
40
+ "@fluidframework/datastore-definitions": ">=2.0.0-internal.6.4.0 <2.0.0-internal.6.5.0",
41
+ "@fluidframework/driver-utils": ">=2.0.0-internal.6.4.0 <2.0.0-internal.6.5.0",
42
42
  "@fluidframework/protocol-definitions": "^1.1.0",
43
- "@fluidframework/runtime-definitions": ">=2.0.0-internal.6.3.2 <2.0.0-internal.6.4.0",
44
- "@fluidframework/shared-object-base": ">=2.0.0-internal.6.3.2 <2.0.0-internal.6.4.0",
43
+ "@fluidframework/runtime-definitions": ">=2.0.0-internal.6.4.0 <2.0.0-internal.6.5.0",
44
+ "@fluidframework/shared-object-base": ">=2.0.0-internal.6.4.0 <2.0.0-internal.6.5.0",
45
45
  "events": "^3.1.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@fluid-internal/test-dds-utils": ">=2.0.0-internal.6.3.2 <2.0.0-internal.6.4.0",
48
+ "@fluid-internal/test-dds-utils": ">=2.0.0-internal.6.4.0 <2.0.0-internal.6.5.0",
49
49
  "@fluidframework/build-common": "^2.0.0",
50
50
  "@fluidframework/build-tools": "^0.22.0",
51
51
  "@fluidframework/eslint-config-fluid": "^2.1.0",
52
- "@fluidframework/mocha-test-setup": ">=2.0.0-internal.6.3.2 <2.0.0-internal.6.4.0",
53
- "@fluidframework/test-runtime-utils": ">=2.0.0-internal.6.3.2 <2.0.0-internal.6.4.0",
52
+ "@fluidframework/mocha-test-setup": ">=2.0.0-internal.6.4.0 <2.0.0-internal.6.5.0",
53
+ "@fluidframework/test-runtime-utils": ">=2.0.0-internal.6.4.0 <2.0.0-internal.6.5.0",
54
54
  "@microsoft/api-extractor": "^7.34.4",
55
55
  "@types/events": "^3.0.0",
56
56
  "@types/mocha": "^9.1.1",
package/src/index.ts CHANGED
@@ -3,5 +3,5 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- export { IPactMap, IPactMapEvents, IAcceptedPact } from "./interfaces";
6
+ export type { IPactMap, IPactMapEvents, IAcceptedPact } from "./interfaces";
7
7
  export { PactMap } from "./pactMap";
package/src/interfaces.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { ISharedObject, ISharedObjectEvents } from "@fluidframework/shared-object-base";
6
+ import { type ISharedObject, type ISharedObjectEvents } from "@fluidframework/shared-object-base";
7
7
 
8
8
  /**
9
9
  * IPactMapEvents are the events fired by an IPactMap.
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluid-experimental/pact-map";
9
- export const pkgVersion = "2.0.0-internal.6.3.2";
9
+ export const pkgVersion = "2.0.0-internal.6.4.0";
package/src/pactMap.ts CHANGED
@@ -5,25 +5,27 @@
5
5
 
6
6
  /* eslint-disable unicorn/numeric-separators-style */
7
7
 
8
+ // False positive: this is an import from the `events` package, not from Node.
9
+ // eslint-disable-next-line unicorn/prefer-node-protocol
8
10
  import { EventEmitter } from "events";
9
11
 
10
12
  import { assert } from "@fluidframework/core-utils";
11
- import { ISequencedDocumentMessage, MessageType } from "@fluidframework/protocol-definitions";
13
+ import { type ISequencedDocumentMessage, MessageType } from "@fluidframework/protocol-definitions";
12
14
  import {
13
- IChannelAttributes,
14
- IFluidDataStoreRuntime,
15
- IChannelStorageService,
16
- IChannelFactory,
15
+ type IChannelAttributes,
16
+ type IFluidDataStoreRuntime,
17
+ type IChannelStorageService,
18
+ type IChannelFactory,
17
19
  } from "@fluidframework/datastore-definitions";
18
- import { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
20
+ import { type ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
19
21
  import { readAndParse } from "@fluidframework/driver-utils";
20
22
  import {
21
23
  createSingleBlobSummary,
22
- IFluidSerializer,
24
+ type IFluidSerializer,
23
25
  SharedObject,
24
26
  } from "@fluidframework/shared-object-base";
25
27
  import { PactMapFactory } from "./pactMapFactory";
26
- import { IAcceptedPact, IPactMap, IPactMapEvents } from "./interfaces";
28
+ import { type IAcceptedPact, type IPactMap, type IPactMapEvents } from "./interfaces";
27
29
 
28
30
  /**
29
31
  * The accepted pact information, if any.
@@ -175,7 +177,7 @@ export class PactMap<T = unknown> extends SharedObject<IPactMapEvents> implement
175
177
  return new PactMapFactory();
176
178
  }
177
179
 
178
- private readonly values: Map<string, Pact<T>> = new Map();
180
+ private readonly values = new Map<string, Pact<T>>();
179
181
 
180
182
  private readonly incomingOp: EventEmitter = new EventEmitter();
181
183
 
@@ -485,7 +487,7 @@ export class PactMap<T = unknown> extends SharedObject<IPactMapEvents> implement
485
487
  const op = message.contents as IPactMapOperation<T>;
486
488
 
487
489
  switch (op.type) {
488
- case "set":
490
+ case "set": {
489
491
  this.incomingOp.emit(
490
492
  "set",
491
493
  op.key,
@@ -494,8 +496,9 @@ export class PactMap<T = unknown> extends SharedObject<IPactMapEvents> implement
494
496
  message.sequenceNumber,
495
497
  );
496
498
  break;
499
+ }
497
500
 
498
- case "accept":
501
+ case "accept": {
499
502
  this.incomingOp.emit(
500
503
  "accept",
501
504
  op.key,
@@ -503,9 +506,11 @@ export class PactMap<T = unknown> extends SharedObject<IPactMapEvents> implement
503
506
  message.sequenceNumber,
504
507
  );
505
508
  break;
509
+ }
506
510
 
507
- default:
511
+ default: {
508
512
  throw new Error("Unknown operation");
513
+ }
509
514
  }
510
515
  }
511
516
  }
@@ -4,13 +4,13 @@
4
4
  */
5
5
 
6
6
  import {
7
- IChannelAttributes,
8
- IFluidDataStoreRuntime,
9
- IChannelServices,
10
- IChannelFactory,
7
+ type IChannelAttributes,
8
+ type IFluidDataStoreRuntime,
9
+ type IChannelServices,
10
+ type IChannelFactory,
11
11
  } from "@fluidframework/datastore-definitions";
12
12
  import { PactMap } from "./pactMap";
13
- import { IPactMap } from "./interfaces";
13
+ import { type IPactMap } from "./interfaces";
14
14
  import { pkgVersion } from "./packageVersion";
15
15
 
16
16
  /**