@fluid-experimental/pact-map 2.0.0-dev.7.3.0.210328 → 2.0.0-dev.7.3.0.212138
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/api-extractor.json +4 -1
- package/dist/{index.js → index.cjs} +2 -2
- package/dist/index.cjs.map +1 -0
- package/dist/{interfaces.js → interfaces.cjs} +1 -1
- package/dist/interfaces.cjs.map +1 -0
- package/dist/{packageVersion.js → packageVersion.cjs} +2 -2
- package/dist/packageVersion.cjs.map +1 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/pact-map-alpha.d.ts +218 -0
- package/dist/pact-map-beta.d.ts +218 -0
- package/dist/pact-map-public.d.ts +218 -0
- package/dist/pact-map-untrimmed.d.ts +249 -0
- package/dist/{pactMap.js → pactMap.cjs} +2 -2
- package/dist/pactMap.cjs.map +1 -0
- package/dist/{pactMapFactory.js → pactMapFactory.cjs} +3 -3
- package/dist/pactMapFactory.cjs.map +1 -0
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/{index.js → index.mjs} +2 -2
- package/lib/index.mjs.map +1 -0
- package/lib/{interfaces.js → interfaces.mjs} +1 -1
- package/{dist/interfaces.js.map → lib/interfaces.mjs.map} +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/{packageVersion.js → packageVersion.mjs} +2 -2
- package/lib/packageVersion.mjs.map +1 -0
- package/lib/pact-map-alpha.d.ts +218 -0
- package/lib/pact-map-beta.d.ts +218 -0
- package/lib/pact-map-public.d.ts +218 -0
- package/lib/pact-map-untrimmed.d.ts +249 -0
- package/lib/{pactMap.js → pactMap.mjs} +2 -5
- package/lib/pactMap.mjs.map +1 -0
- package/lib/{pactMapFactory.js → pactMapFactory.mjs} +3 -3
- package/lib/pactMapFactory.mjs.map +1 -0
- package/package.json +48 -19
- package/src/packageVersion.ts +1 -1
- package/tsc-multi.test.json +4 -0
- package/dist/index.js.map +0 -1
- package/dist/packageVersion.js.map +0 -1
- package/dist/pactMap.js.map +0 -1
- package/dist/pactMapFactory.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/interfaces.js.map +0 -1
- package/lib/packageVersion.js.map +0 -1
- package/lib/pactMap.js.map +0 -1
- package/lib/pactMapFactory.js.map +0 -1
- package/tsconfig.esnext.json +0 -6
package/CHANGELOG.md
CHANGED
package/api-extractor.json
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
|
3
|
-
"extends": "@fluidframework/build-common/api-extractor-base.json"
|
|
3
|
+
"extends": "@fluidframework/build-common/api-extractor-base.json",
|
|
4
|
+
"dtsRollup": {
|
|
5
|
+
"enabled": true
|
|
6
|
+
}
|
|
4
7
|
}
|
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.PactMap = void 0;
|
|
8
|
-
var pactMap_1 = require("./pactMap");
|
|
8
|
+
var pactMap_1 = require("./pactMap.cjs");
|
|
9
9
|
Object.defineProperty(exports, "PactMap", { enumerable: true, get: function () { return pactMap_1.PactMap; } });
|
|
10
|
-
//# sourceMappingURL=index.
|
|
10
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,yCAAoC;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"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.cjs","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 * Events emitted by {@link IPactMap}.\n *\n * @public\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 *\n * @public\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 *\n * @public\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"]}
|
|
@@ -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-dev.7.3.0.
|
|
12
|
-
//# sourceMappingURL=packageVersion.
|
|
11
|
+
exports.pkgVersion = "2.0.0-dev.7.3.0.212138";
|
|
12
|
+
//# sourceMappingURL=packageVersion.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"packageVersion.cjs","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,8BAA8B,CAAC;AACzC,QAAA,UAAU,GAAG,wBAAwB,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-dev.7.3.0.212138\";\n"]}
|
package/dist/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluid-experimental/pact-map";
|
|
8
|
-
export declare const pkgVersion = "2.0.0-dev.7.3.0.
|
|
8
|
+
export declare const pkgVersion = "2.0.0-dev.7.3.0.212138";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { IChannelAttributes } from '@fluidframework/datastore-definitions';
|
|
2
|
+
import { IChannelFactory } from '@fluidframework/datastore-definitions';
|
|
3
|
+
import { IChannelStorageService } from '@fluidframework/datastore-definitions';
|
|
4
|
+
import { IFluidDataStoreRuntime } from '@fluidframework/datastore-definitions';
|
|
5
|
+
import { IFluidSerializer } from '@fluidframework/shared-object-base';
|
|
6
|
+
import { ISequencedDocumentMessage } from '@fluidframework/protocol-definitions';
|
|
7
|
+
import { ISharedObject } from '@fluidframework/shared-object-base';
|
|
8
|
+
import { ISharedObjectEvents } from '@fluidframework/shared-object-base';
|
|
9
|
+
import { ISummaryTreeWithStats } from '@fluidframework/runtime-definitions';
|
|
10
|
+
import { SharedObject } from '@fluidframework/shared-object-base';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Details of the accepted pact.
|
|
14
|
+
*
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export declare interface IAcceptedPact<T> {
|
|
18
|
+
/**
|
|
19
|
+
* The accepted value of the given type or undefined (typically in case of delete).
|
|
20
|
+
*/
|
|
21
|
+
value: T | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* The sequence number when the value was accepted.
|
|
24
|
+
*
|
|
25
|
+
* For values set in detached state, it will be 0.
|
|
26
|
+
*/
|
|
27
|
+
acceptedSequenceNumber: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* An IPactMap is a key-value storage, in which setting a value is done via a proposal system. All collaborators
|
|
32
|
+
* who were connected at the time of the proposal must accept the change before it is considered accepted (or, if
|
|
33
|
+
* those clients disconnect they are considered to have implicitly accepted). As a result, the value goes through
|
|
34
|
+
* two phases:
|
|
35
|
+
* 1. "pending" state where the proposal has been sequenced, but there are still outstanding acceptances
|
|
36
|
+
* 2. "accepted" state where all clients who were connected at the time the proposal was made have either accepted
|
|
37
|
+
* or disconnected.
|
|
38
|
+
*
|
|
39
|
+
* @public
|
|
40
|
+
*/
|
|
41
|
+
export declare interface IPactMap<T = unknown> extends ISharedObject<IPactMapEvents> {
|
|
42
|
+
/**
|
|
43
|
+
* Gets the accepted value for the given key.
|
|
44
|
+
* @param key - The key to retrieve from
|
|
45
|
+
*/
|
|
46
|
+
get(key: string): T | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Gets the accepted value and details for the given key.
|
|
49
|
+
* @param key - The key to retrieve from
|
|
50
|
+
*/
|
|
51
|
+
getWithDetails(key: string): IAcceptedPact<T> | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Returns whether there is a pending value for the given key. Can be used to distinguish a pending delete vs.
|
|
54
|
+
* nothing pending when getPending would just return undefined.
|
|
55
|
+
* @param key - The key to check
|
|
56
|
+
*/
|
|
57
|
+
isPending(key: string): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Gets the pending value for the given key.
|
|
60
|
+
* @param key - The key to retrieve from
|
|
61
|
+
*/
|
|
62
|
+
getPending(key: string): T | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Sets the value for the given key. After setting the value, it will be in "pending" state until all connected
|
|
65
|
+
* clients have approved the change. The accepted value remains unchanged until that time.
|
|
66
|
+
* @param key - The key to set
|
|
67
|
+
* @param value - The value to store
|
|
68
|
+
*/
|
|
69
|
+
set(key: string, value: T | undefined): void;
|
|
70
|
+
/**
|
|
71
|
+
* Deletes the key/value pair at the given key. After issuing the delete, the delete is in "pending" state until
|
|
72
|
+
* all connected clients have approved the delete. The accepted value remains unchanged until that time.
|
|
73
|
+
* @param key - the key to delete
|
|
74
|
+
*/
|
|
75
|
+
delete(key: string): void;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Events emitted by {@link IPactMap}.
|
|
80
|
+
*
|
|
81
|
+
* @public
|
|
82
|
+
*/
|
|
83
|
+
export declare interface IPactMapEvents extends ISharedObjectEvents {
|
|
84
|
+
/**
|
|
85
|
+
* Notifies when a new value goes pending or has been accepted.
|
|
86
|
+
*/
|
|
87
|
+
(event: "pending" | "accepted", listener: (key: string) => void): any;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The PactMap distributed data structure provides key/value storage with a cautious conflict resolution strategy.
|
|
92
|
+
* This strategy optimizes for all clients being aware of the change prior to considering the value as accepted.
|
|
93
|
+
*
|
|
94
|
+
* It is still experimental and under development. Please do try it out, but expect breaking changes in the future.
|
|
95
|
+
*
|
|
96
|
+
* @remarks
|
|
97
|
+
* ### Creation
|
|
98
|
+
*
|
|
99
|
+
* To create a `PactMap`, call the static create method:
|
|
100
|
+
*
|
|
101
|
+
* ```typescript
|
|
102
|
+
* const pactMap = PactMap.create(this.runtime, id);
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* ### Usage
|
|
106
|
+
*
|
|
107
|
+
* Setting and reading values is somewhat similar to a `SharedMap`. However, because the acceptance strategy
|
|
108
|
+
* cannot be resolved until other clients have witnessed the set, the new value will only be reflected in the data
|
|
109
|
+
* after the consensus is reached.
|
|
110
|
+
*
|
|
111
|
+
* ```typescript
|
|
112
|
+
* pactMap.on("pending", (key: string) => {
|
|
113
|
+
* console.log(pactMap.getPending(key));
|
|
114
|
+
* });
|
|
115
|
+
* pactMap.on("accepted", (key: string) => {
|
|
116
|
+
* console.log(pactMap.get(key));
|
|
117
|
+
* });
|
|
118
|
+
* pactMap.set("myKey", "myValue");
|
|
119
|
+
*
|
|
120
|
+
* // Reading from the pact map prior to the async operation's completion will still return the old value.
|
|
121
|
+
* console.log(pactMap.get("myKey"));
|
|
122
|
+
* ```
|
|
123
|
+
*
|
|
124
|
+
* The acceptance process has two stages. When an op indicating a client's attempt to set a value is sequenced,
|
|
125
|
+
* we first verify that it was set with knowledge of the most recently accepted value (consensus-like FWW). If it
|
|
126
|
+
* meets this bar, then the value is "pending". During this time, clients may observe the pending value and act
|
|
127
|
+
* upon it, but should be aware that not all other clients may have witnessed the value yet. Once all clients
|
|
128
|
+
* that were connected at the time of the value being set have explicitly acknowledged the new value, the value
|
|
129
|
+
* becomes "accepted". Once the value is accepted, it once again becomes possible to set the value, again with
|
|
130
|
+
* consensus-like FWW resolution.
|
|
131
|
+
*
|
|
132
|
+
* Since all connected clients must explicitly accept the new value, it is important that all connected clients
|
|
133
|
+
* have the PactMap loaded, including e.g. the summarizing client. Otherwise, those clients who have not loaded
|
|
134
|
+
* the PactMap will not be responding to proposals and delay their acceptance (until they disconnect, which implicitly
|
|
135
|
+
* removes them from consideration). The easiest way to ensure all clients load the PactMap is to instantiate it
|
|
136
|
+
* as part of instantiating the IRuntime for the container (containerHasInitialized if using Aqueduct).
|
|
137
|
+
*
|
|
138
|
+
* ### Eventing
|
|
139
|
+
*
|
|
140
|
+
* `PactMap` is an `EventEmitter`, and will emit events when a new value is accepted for a key.
|
|
141
|
+
*
|
|
142
|
+
* ```typescript
|
|
143
|
+
* pactMap.on("accept", (key: string) => {
|
|
144
|
+
* console.log(`New value was accepted for key: ${ key }, value: ${ pactMap.get(key) }`);
|
|
145
|
+
* });
|
|
146
|
+
* ```
|
|
147
|
+
*
|
|
148
|
+
* @public
|
|
149
|
+
*/
|
|
150
|
+
export declare class PactMap<T = unknown> extends SharedObject<IPactMapEvents> implements IPactMap<T> {
|
|
151
|
+
/**
|
|
152
|
+
* Create a new PactMap
|
|
153
|
+
*
|
|
154
|
+
* @param runtime - data store runtime the new PactMap belongs to
|
|
155
|
+
* @param id - optional name of the PactMap
|
|
156
|
+
* @returns newly created PactMap (but not attached yet)
|
|
157
|
+
*/
|
|
158
|
+
static create(runtime: IFluidDataStoreRuntime, id?: string): PactMap;
|
|
159
|
+
/**
|
|
160
|
+
* Get a factory for PactMap to register with the data store.
|
|
161
|
+
*
|
|
162
|
+
* @returns a factory that creates and loads PactMaps
|
|
163
|
+
*/
|
|
164
|
+
static getFactory(): IChannelFactory;
|
|
165
|
+
private readonly values;
|
|
166
|
+
private readonly incomingOp;
|
|
167
|
+
/**
|
|
168
|
+
* Constructs a new PactMap. If the object is non-local an id and service interfaces will
|
|
169
|
+
* be provided
|
|
170
|
+
*
|
|
171
|
+
* @param runtime - data store runtime the PactMap belongs to
|
|
172
|
+
* @param id - optional name of the PactMap
|
|
173
|
+
*/
|
|
174
|
+
constructor(id: string, runtime: IFluidDataStoreRuntime, attributes: IChannelAttributes);
|
|
175
|
+
/**
|
|
176
|
+
* {@inheritDoc IPactMap.get}
|
|
177
|
+
*/
|
|
178
|
+
get(key: string): T | undefined;
|
|
179
|
+
/**
|
|
180
|
+
* {@inheritDoc IPactMap.getWithDetails}
|
|
181
|
+
*/
|
|
182
|
+
getWithDetails(key: string): IAcceptedPact<T> | undefined;
|
|
183
|
+
/**
|
|
184
|
+
* {@inheritDoc IPactMap.isPending}
|
|
185
|
+
*/
|
|
186
|
+
isPending(key: string): boolean;
|
|
187
|
+
/**
|
|
188
|
+
* {@inheritDoc IPactMap.getPending}
|
|
189
|
+
*/
|
|
190
|
+
getPending(key: string): T | undefined;
|
|
191
|
+
/**
|
|
192
|
+
* {@inheritDoc IPactMap.set}
|
|
193
|
+
*/
|
|
194
|
+
set(key: string, value: T | undefined): void;
|
|
195
|
+
/**
|
|
196
|
+
* {@inheritDoc IPactMap.delete}
|
|
197
|
+
*/
|
|
198
|
+
delete(key: string): void;
|
|
199
|
+
/**
|
|
200
|
+
* Get a point-in-time list of clients who must sign off on values coming in for them to move from "pending" to
|
|
201
|
+
* "accepted" state. This list is finalized for a value at the moment it goes pending (i.e. if more clients
|
|
202
|
+
* join later, they are not added to the list of signoffs).
|
|
203
|
+
* @returns The list of clientIds for clients who must sign off to accept the incoming pending value
|
|
204
|
+
*/
|
|
205
|
+
private getSignoffClients;
|
|
206
|
+
private readonly handleIncomingSet;
|
|
207
|
+
private readonly handleIncomingAccept;
|
|
208
|
+
private readonly handleQuorumRemoveMember;
|
|
209
|
+
/* Excluded from this release type: summarizeCore */
|
|
210
|
+
/* Excluded from this release type: loadCore */
|
|
211
|
+
/* Excluded from this release type: initializeLocalCore */
|
|
212
|
+
/* Excluded from this release type: onDisconnect */
|
|
213
|
+
/* Excluded from this release type: reSubmitCore */
|
|
214
|
+
/* Excluded from this release type: processCore */
|
|
215
|
+
applyStashedOp(): void;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export { }
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { IChannelAttributes } from '@fluidframework/datastore-definitions';
|
|
2
|
+
import { IChannelFactory } from '@fluidframework/datastore-definitions';
|
|
3
|
+
import { IChannelStorageService } from '@fluidframework/datastore-definitions';
|
|
4
|
+
import { IFluidDataStoreRuntime } from '@fluidframework/datastore-definitions';
|
|
5
|
+
import { IFluidSerializer } from '@fluidframework/shared-object-base';
|
|
6
|
+
import { ISequencedDocumentMessage } from '@fluidframework/protocol-definitions';
|
|
7
|
+
import { ISharedObject } from '@fluidframework/shared-object-base';
|
|
8
|
+
import { ISharedObjectEvents } from '@fluidframework/shared-object-base';
|
|
9
|
+
import { ISummaryTreeWithStats } from '@fluidframework/runtime-definitions';
|
|
10
|
+
import { SharedObject } from '@fluidframework/shared-object-base';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Details of the accepted pact.
|
|
14
|
+
*
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export declare interface IAcceptedPact<T> {
|
|
18
|
+
/**
|
|
19
|
+
* The accepted value of the given type or undefined (typically in case of delete).
|
|
20
|
+
*/
|
|
21
|
+
value: T | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* The sequence number when the value was accepted.
|
|
24
|
+
*
|
|
25
|
+
* For values set in detached state, it will be 0.
|
|
26
|
+
*/
|
|
27
|
+
acceptedSequenceNumber: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* An IPactMap is a key-value storage, in which setting a value is done via a proposal system. All collaborators
|
|
32
|
+
* who were connected at the time of the proposal must accept the change before it is considered accepted (or, if
|
|
33
|
+
* those clients disconnect they are considered to have implicitly accepted). As a result, the value goes through
|
|
34
|
+
* two phases:
|
|
35
|
+
* 1. "pending" state where the proposal has been sequenced, but there are still outstanding acceptances
|
|
36
|
+
* 2. "accepted" state where all clients who were connected at the time the proposal was made have either accepted
|
|
37
|
+
* or disconnected.
|
|
38
|
+
*
|
|
39
|
+
* @public
|
|
40
|
+
*/
|
|
41
|
+
export declare interface IPactMap<T = unknown> extends ISharedObject<IPactMapEvents> {
|
|
42
|
+
/**
|
|
43
|
+
* Gets the accepted value for the given key.
|
|
44
|
+
* @param key - The key to retrieve from
|
|
45
|
+
*/
|
|
46
|
+
get(key: string): T | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Gets the accepted value and details for the given key.
|
|
49
|
+
* @param key - The key to retrieve from
|
|
50
|
+
*/
|
|
51
|
+
getWithDetails(key: string): IAcceptedPact<T> | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Returns whether there is a pending value for the given key. Can be used to distinguish a pending delete vs.
|
|
54
|
+
* nothing pending when getPending would just return undefined.
|
|
55
|
+
* @param key - The key to check
|
|
56
|
+
*/
|
|
57
|
+
isPending(key: string): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Gets the pending value for the given key.
|
|
60
|
+
* @param key - The key to retrieve from
|
|
61
|
+
*/
|
|
62
|
+
getPending(key: string): T | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Sets the value for the given key. After setting the value, it will be in "pending" state until all connected
|
|
65
|
+
* clients have approved the change. The accepted value remains unchanged until that time.
|
|
66
|
+
* @param key - The key to set
|
|
67
|
+
* @param value - The value to store
|
|
68
|
+
*/
|
|
69
|
+
set(key: string, value: T | undefined): void;
|
|
70
|
+
/**
|
|
71
|
+
* Deletes the key/value pair at the given key. After issuing the delete, the delete is in "pending" state until
|
|
72
|
+
* all connected clients have approved the delete. The accepted value remains unchanged until that time.
|
|
73
|
+
* @param key - the key to delete
|
|
74
|
+
*/
|
|
75
|
+
delete(key: string): void;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Events emitted by {@link IPactMap}.
|
|
80
|
+
*
|
|
81
|
+
* @public
|
|
82
|
+
*/
|
|
83
|
+
export declare interface IPactMapEvents extends ISharedObjectEvents {
|
|
84
|
+
/**
|
|
85
|
+
* Notifies when a new value goes pending or has been accepted.
|
|
86
|
+
*/
|
|
87
|
+
(event: "pending" | "accepted", listener: (key: string) => void): any;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The PactMap distributed data structure provides key/value storage with a cautious conflict resolution strategy.
|
|
92
|
+
* This strategy optimizes for all clients being aware of the change prior to considering the value as accepted.
|
|
93
|
+
*
|
|
94
|
+
* It is still experimental and under development. Please do try it out, but expect breaking changes in the future.
|
|
95
|
+
*
|
|
96
|
+
* @remarks
|
|
97
|
+
* ### Creation
|
|
98
|
+
*
|
|
99
|
+
* To create a `PactMap`, call the static create method:
|
|
100
|
+
*
|
|
101
|
+
* ```typescript
|
|
102
|
+
* const pactMap = PactMap.create(this.runtime, id);
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* ### Usage
|
|
106
|
+
*
|
|
107
|
+
* Setting and reading values is somewhat similar to a `SharedMap`. However, because the acceptance strategy
|
|
108
|
+
* cannot be resolved until other clients have witnessed the set, the new value will only be reflected in the data
|
|
109
|
+
* after the consensus is reached.
|
|
110
|
+
*
|
|
111
|
+
* ```typescript
|
|
112
|
+
* pactMap.on("pending", (key: string) => {
|
|
113
|
+
* console.log(pactMap.getPending(key));
|
|
114
|
+
* });
|
|
115
|
+
* pactMap.on("accepted", (key: string) => {
|
|
116
|
+
* console.log(pactMap.get(key));
|
|
117
|
+
* });
|
|
118
|
+
* pactMap.set("myKey", "myValue");
|
|
119
|
+
*
|
|
120
|
+
* // Reading from the pact map prior to the async operation's completion will still return the old value.
|
|
121
|
+
* console.log(pactMap.get("myKey"));
|
|
122
|
+
* ```
|
|
123
|
+
*
|
|
124
|
+
* The acceptance process has two stages. When an op indicating a client's attempt to set a value is sequenced,
|
|
125
|
+
* we first verify that it was set with knowledge of the most recently accepted value (consensus-like FWW). If it
|
|
126
|
+
* meets this bar, then the value is "pending". During this time, clients may observe the pending value and act
|
|
127
|
+
* upon it, but should be aware that not all other clients may have witnessed the value yet. Once all clients
|
|
128
|
+
* that were connected at the time of the value being set have explicitly acknowledged the new value, the value
|
|
129
|
+
* becomes "accepted". Once the value is accepted, it once again becomes possible to set the value, again with
|
|
130
|
+
* consensus-like FWW resolution.
|
|
131
|
+
*
|
|
132
|
+
* Since all connected clients must explicitly accept the new value, it is important that all connected clients
|
|
133
|
+
* have the PactMap loaded, including e.g. the summarizing client. Otherwise, those clients who have not loaded
|
|
134
|
+
* the PactMap will not be responding to proposals and delay their acceptance (until they disconnect, which implicitly
|
|
135
|
+
* removes them from consideration). The easiest way to ensure all clients load the PactMap is to instantiate it
|
|
136
|
+
* as part of instantiating the IRuntime for the container (containerHasInitialized if using Aqueduct).
|
|
137
|
+
*
|
|
138
|
+
* ### Eventing
|
|
139
|
+
*
|
|
140
|
+
* `PactMap` is an `EventEmitter`, and will emit events when a new value is accepted for a key.
|
|
141
|
+
*
|
|
142
|
+
* ```typescript
|
|
143
|
+
* pactMap.on("accept", (key: string) => {
|
|
144
|
+
* console.log(`New value was accepted for key: ${ key }, value: ${ pactMap.get(key) }`);
|
|
145
|
+
* });
|
|
146
|
+
* ```
|
|
147
|
+
*
|
|
148
|
+
* @public
|
|
149
|
+
*/
|
|
150
|
+
export declare class PactMap<T = unknown> extends SharedObject<IPactMapEvents> implements IPactMap<T> {
|
|
151
|
+
/**
|
|
152
|
+
* Create a new PactMap
|
|
153
|
+
*
|
|
154
|
+
* @param runtime - data store runtime the new PactMap belongs to
|
|
155
|
+
* @param id - optional name of the PactMap
|
|
156
|
+
* @returns newly created PactMap (but not attached yet)
|
|
157
|
+
*/
|
|
158
|
+
static create(runtime: IFluidDataStoreRuntime, id?: string): PactMap;
|
|
159
|
+
/**
|
|
160
|
+
* Get a factory for PactMap to register with the data store.
|
|
161
|
+
*
|
|
162
|
+
* @returns a factory that creates and loads PactMaps
|
|
163
|
+
*/
|
|
164
|
+
static getFactory(): IChannelFactory;
|
|
165
|
+
private readonly values;
|
|
166
|
+
private readonly incomingOp;
|
|
167
|
+
/**
|
|
168
|
+
* Constructs a new PactMap. If the object is non-local an id and service interfaces will
|
|
169
|
+
* be provided
|
|
170
|
+
*
|
|
171
|
+
* @param runtime - data store runtime the PactMap belongs to
|
|
172
|
+
* @param id - optional name of the PactMap
|
|
173
|
+
*/
|
|
174
|
+
constructor(id: string, runtime: IFluidDataStoreRuntime, attributes: IChannelAttributes);
|
|
175
|
+
/**
|
|
176
|
+
* {@inheritDoc IPactMap.get}
|
|
177
|
+
*/
|
|
178
|
+
get(key: string): T | undefined;
|
|
179
|
+
/**
|
|
180
|
+
* {@inheritDoc IPactMap.getWithDetails}
|
|
181
|
+
*/
|
|
182
|
+
getWithDetails(key: string): IAcceptedPact<T> | undefined;
|
|
183
|
+
/**
|
|
184
|
+
* {@inheritDoc IPactMap.isPending}
|
|
185
|
+
*/
|
|
186
|
+
isPending(key: string): boolean;
|
|
187
|
+
/**
|
|
188
|
+
* {@inheritDoc IPactMap.getPending}
|
|
189
|
+
*/
|
|
190
|
+
getPending(key: string): T | undefined;
|
|
191
|
+
/**
|
|
192
|
+
* {@inheritDoc IPactMap.set}
|
|
193
|
+
*/
|
|
194
|
+
set(key: string, value: T | undefined): void;
|
|
195
|
+
/**
|
|
196
|
+
* {@inheritDoc IPactMap.delete}
|
|
197
|
+
*/
|
|
198
|
+
delete(key: string): void;
|
|
199
|
+
/**
|
|
200
|
+
* Get a point-in-time list of clients who must sign off on values coming in for them to move from "pending" to
|
|
201
|
+
* "accepted" state. This list is finalized for a value at the moment it goes pending (i.e. if more clients
|
|
202
|
+
* join later, they are not added to the list of signoffs).
|
|
203
|
+
* @returns The list of clientIds for clients who must sign off to accept the incoming pending value
|
|
204
|
+
*/
|
|
205
|
+
private getSignoffClients;
|
|
206
|
+
private readonly handleIncomingSet;
|
|
207
|
+
private readonly handleIncomingAccept;
|
|
208
|
+
private readonly handleQuorumRemoveMember;
|
|
209
|
+
/* Excluded from this release type: summarizeCore */
|
|
210
|
+
/* Excluded from this release type: loadCore */
|
|
211
|
+
/* Excluded from this release type: initializeLocalCore */
|
|
212
|
+
/* Excluded from this release type: onDisconnect */
|
|
213
|
+
/* Excluded from this release type: reSubmitCore */
|
|
214
|
+
/* Excluded from this release type: processCore */
|
|
215
|
+
applyStashedOp(): void;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export { }
|