@agoric/store 0.9.3-dev-57802f9.0 → 0.9.3-other-dev-1f26562.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +690 -0
- package/package.json +12 -15
- package/src/index.js +1 -1
- package/src/legacy/legacyMap.js +18 -20
- package/src/legacy/legacyWeakMap.js +2 -2
- package/src/stores/scalarMapStore.js +11 -11
- package/src/stores/scalarSetStore.js +6 -6
- package/src/stores/scalarWeakMapStore.js +13 -17
- package/src/stores/scalarWeakSetStore.js +8 -12
- package/src/stores/store-utils.js +30 -29
- package/src/types.js +191 -90
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/store",
|
|
3
|
-
"version": "0.9.3-dev-
|
|
3
|
+
"version": "0.9.3-other-dev-1f26562.0+1f26562",
|
|
4
4
|
"description": "Wrapper for JavaScript map",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"test:xs": "exit 0",
|
|
14
14
|
"lint-fix": "yarn lint:eslint --fix",
|
|
15
15
|
"lint": "run-s --continue-on-error lint:*",
|
|
16
|
-
"lint:types": "tsc",
|
|
16
|
+
"lint:types": "tsc -p jsconfig.json",
|
|
17
17
|
"lint:eslint": "eslint ."
|
|
18
18
|
},
|
|
19
19
|
"repository": {
|
|
@@ -30,17 +30,17 @@
|
|
|
30
30
|
},
|
|
31
31
|
"homepage": "https://github.com/Agoric/agoric-sdk#readme",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@agoric/assert": "0.6.1-dev-
|
|
34
|
-
"@endo/exo": "
|
|
35
|
-
"@endo/marshal": "
|
|
36
|
-
"@endo/pass-style": "
|
|
37
|
-
"@endo/patterns": "
|
|
33
|
+
"@agoric/assert": "0.6.1-other-dev-1f26562.0+1f26562",
|
|
34
|
+
"@endo/exo": "0.2.2",
|
|
35
|
+
"@endo/marshal": "0.8.5",
|
|
36
|
+
"@endo/pass-style": "0.1.3",
|
|
37
|
+
"@endo/patterns": "0.2.2"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@agoric/
|
|
41
|
-
"@
|
|
42
|
-
"@endo/ses-ava": "
|
|
43
|
-
"ava": "^5.
|
|
40
|
+
"@agoric/swingset-vat": "0.32.3-other-dev-1f26562.0+1f26562",
|
|
41
|
+
"@agoric/time": "0.3.3-other-dev-1f26562.0+1f26562",
|
|
42
|
+
"@endo/ses-ava": "0.2.40",
|
|
43
|
+
"ava": "^5.2.0"
|
|
44
44
|
},
|
|
45
45
|
"files": [
|
|
46
46
|
"src/",
|
|
@@ -54,10 +54,7 @@
|
|
|
54
54
|
"files": [
|
|
55
55
|
"test/**/test-*.js"
|
|
56
56
|
],
|
|
57
|
-
"require": [
|
|
58
|
-
"@endo/init/debug.js"
|
|
59
|
-
],
|
|
60
57
|
"timeout": "2m"
|
|
61
58
|
},
|
|
62
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "1f265627270d514ab48943f86c668eb58a280552"
|
|
63
60
|
}
|
package/src/index.js
CHANGED
|
@@ -56,7 +56,7 @@ export { makeScalarSetStore } from './stores/scalarSetStore.js';
|
|
|
56
56
|
export { makeScalarWeakMapStore } from './stores/scalarWeakMapStore.js';
|
|
57
57
|
export { makeScalarMapStore } from './stores/scalarMapStore.js';
|
|
58
58
|
|
|
59
|
-
export { provideLazy
|
|
59
|
+
export { provideLazy } from './stores/store-utils.js';
|
|
60
60
|
|
|
61
61
|
// /////////////////////// Deprecated Legacy ///////////////////////////////////
|
|
62
62
|
|
package/src/legacy/legacyMap.js
CHANGED
|
@@ -3,37 +3,35 @@ import { q, Fail } from '@agoric/assert';
|
|
|
3
3
|
import '../types.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* This module and its fraternal sibling legacyWeakMap exist only to
|
|
7
|
-
* transition to the modern `store` system, are deprecated,
|
|
8
|
-
* disappear. They are needed for now to support
|
|
9
|
-
*
|
|
10
|
-
* new
|
|
11
|
-
*
|
|
6
|
+
* This module and its fraternal sibling legacyWeakMap exist only to
|
|
7
|
+
* ease a transition to the modern `store` system, are deprecated,
|
|
8
|
+
* and will eventually disappear. They are needed for now to support
|
|
9
|
+
* some of the uses of the old behavior that are not compatible with
|
|
10
|
+
* the new. The constraint imposed by the new is that only passables can
|
|
11
|
+
* be used as values, and only keys (roughly, structures, aka comparables)
|
|
12
|
+
* can be used as values.
|
|
12
13
|
*
|
|
13
14
|
* See https://github.com/Agoric/agoric-sdk/pull/3567
|
|
14
|
-
*
|
|
15
15
|
* TODO Once that PR is merged, link to the documents rather than the PRs.
|
|
16
16
|
*
|
|
17
17
|
* Each of these non-conforming uses should be marked with a
|
|
18
|
-
*
|
|
19
18
|
* ```js
|
|
20
19
|
* // Legacy because...
|
|
21
20
|
* ```
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* mutation. Using a far object wrapping an array would likely work fine.
|
|
21
|
+
* comment explaining the problem inhibiting conversion to the new
|
|
22
|
+
* system. Some of these problems as of this writing:
|
|
23
|
+
* * A promiseKit used as a value, even though a promiseKit is not
|
|
24
|
+
* a passable. Solutions are to make it a passable, or to convert
|
|
25
|
+
* the container back to a conventional JavaScript Map.
|
|
26
|
+
* * A mutable array used as a value, that is subsequently mutated.
|
|
27
|
+
* Freezing the array wouldn't work of course because it would break
|
|
28
|
+
* the subsequent mutation. Using a far object wrapping an array would
|
|
29
|
+
* likely work fine.
|
|
32
30
|
*
|
|
33
31
|
* @deprecated switch to ScalarMap if possible, Map otherwise
|
|
34
32
|
* @template K,V
|
|
35
|
-
* @param {string} [tag] - tag for debugging
|
|
36
|
-
* @returns {LegacyMap<K,
|
|
33
|
+
* @param {string} [tag='key'] - tag for debugging
|
|
34
|
+
* @returns {LegacyMap<K,V>}
|
|
37
35
|
*/
|
|
38
36
|
export const makeLegacyMap = (tag = 'key') => {
|
|
39
37
|
const m = new Map();
|
|
@@ -6,8 +6,8 @@ import '../types.js';
|
|
|
6
6
|
*
|
|
7
7
|
* @deprecated switch to ScalarWeakMap if possible, WeakMap otherwise
|
|
8
8
|
* @template K,V
|
|
9
|
-
* @param {string} [tag] - tag for debugging
|
|
10
|
-
* @returns {LegacyWeakMap<K,
|
|
9
|
+
* @param {string} [tag='key'] - tag for debugging
|
|
10
|
+
* @returns {LegacyWeakMap<K,V>}
|
|
11
11
|
*/
|
|
12
12
|
export const makeLegacyWeakMap = (tag = 'key') => {
|
|
13
13
|
/** @type {WeakMap<K & object, V>} */
|
|
@@ -20,12 +20,12 @@ const { quote: q } = assert;
|
|
|
20
20
|
/**
|
|
21
21
|
* @template {Key} K
|
|
22
22
|
* @template {Passable} V
|
|
23
|
-
* @param {Map<K,
|
|
23
|
+
* @param {Map<K,V>} jsmap
|
|
24
24
|
* @param {(k: K, v: V) => void} assertKVOkToAdd
|
|
25
25
|
* @param {(k: K, v: V) => void} assertKVOkToSet
|
|
26
|
-
* @param {(k: K) => void} [assertKeyOkToDelete]
|
|
26
|
+
* @param {((k: K) => void)} [assertKeyOkToDelete]
|
|
27
27
|
* @param {string} [tag]
|
|
28
|
-
* @returns {MapStore<K,
|
|
28
|
+
* @returns {MapStore<K,V>}
|
|
29
29
|
*/
|
|
30
30
|
export const makeMapStoreMethods = (
|
|
31
31
|
jsmap,
|
|
@@ -77,7 +77,7 @@ export const makeMapStoreMethods = (
|
|
|
77
77
|
/**
|
|
78
78
|
* @param {Pattern} [keyPatt]
|
|
79
79
|
* @param {Pattern} [valuePatt]
|
|
80
|
-
* @returns {Iterable<[K,
|
|
80
|
+
* @returns {Iterable<[K,V]>}
|
|
81
81
|
*/
|
|
82
82
|
const entries = (keyPatt = undefined, valuePatt = undefined) =>
|
|
83
83
|
mapIterable(keys(keyPatt, valuePatt), k => [
|
|
@@ -117,21 +117,21 @@ export const makeMapStoreMethods = (
|
|
|
117
117
|
};
|
|
118
118
|
|
|
119
119
|
/**
|
|
120
|
-
* Distinguishes between adding a new key (init) and updating or
|
|
121
|
-
* key (get, set, delete).
|
|
120
|
+
* Distinguishes between adding a new key (init) and updating or
|
|
121
|
+
* referencing a key (get, set, delete).
|
|
122
122
|
*
|
|
123
|
-
* `init` is only allowed if the key does not already exist. `Get`,
|
|
124
|
-
* `delete` are only allowed if the key does already exist.
|
|
123
|
+
* `init` is only allowed if the key does not already exist. `Get`,
|
|
124
|
+
* `set` and `delete` are only allowed if the key does already exist.
|
|
125
125
|
*
|
|
126
|
-
* This is a
|
|
126
|
+
* This is a *scalar* map in that the keys can only be atomic values, primitives
|
|
127
127
|
* or remotables. Other storeMaps will accept, for example, copyArrays and
|
|
128
128
|
* copyRecords, as keys and look them up based on equality of their contents.
|
|
129
129
|
*
|
|
130
130
|
* @template {Key} K
|
|
131
131
|
* @template {Passable} V
|
|
132
|
-
* @param {string} [tag] - the column name for the key
|
|
132
|
+
* @param {string} [tag='key'] - the column name for the key
|
|
133
133
|
* @param {StoreOptions} [options]
|
|
134
|
-
* @returns {MapStore<K,
|
|
134
|
+
* @returns {MapStore<K,V>}
|
|
135
135
|
*/
|
|
136
136
|
export const makeScalarMapStore = (
|
|
137
137
|
tag = 'key',
|
|
@@ -74,18 +74,18 @@ export const makeSetStoreMethods = (
|
|
|
74
74
|
};
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
|
-
* Distinguishes between adding a new key (init) and updating or
|
|
78
|
-
* key (get, set, delete).
|
|
77
|
+
* Distinguishes between adding a new key (init) and updating or
|
|
78
|
+
* referencing a key (get, set, delete).
|
|
79
79
|
*
|
|
80
|
-
* `init` is only allowed if the key does not already exist. `Get`,
|
|
81
|
-
* `delete` are only allowed if the key does already exist.
|
|
80
|
+
* `init` is only allowed if the key does not already exist. `Get`,
|
|
81
|
+
* `set` and `delete` are only allowed if the key does already exist.
|
|
82
82
|
*
|
|
83
|
-
* This is a
|
|
83
|
+
* This is a *scalar* set in that the keys can only be atomic values, primitives
|
|
84
84
|
* or remotables. Other storeSets will accept, for example, copyArrays and
|
|
85
85
|
* copyRecords, as keys and look them up based on equality of their contents.
|
|
86
86
|
*
|
|
87
87
|
* @template K
|
|
88
|
-
* @param {string} [tag] - tag for debugging
|
|
88
|
+
* @param {string} [tag='key'] - tag for debugging
|
|
89
89
|
* @param {StoreOptions} [options]
|
|
90
90
|
* @returns {SetStore<K>}
|
|
91
91
|
*/
|
|
@@ -11,7 +11,7 @@ const { quote: q, Fail } = assert;
|
|
|
11
11
|
* @param {(k: K, v: V) => void} assertKVOkToSet
|
|
12
12
|
* @param {(k: K) => void} [assertKeyOkToDelete]
|
|
13
13
|
* @param {string} [keyName]
|
|
14
|
-
* @returns {WeakMapStore<K,
|
|
14
|
+
* @returns {WeakMapStore<K,V>}
|
|
15
15
|
*/
|
|
16
16
|
export const makeWeakMapStoreMethods = (
|
|
17
17
|
jsmap,
|
|
@@ -58,12 +58,8 @@ export const makeWeakMapStoreMethods = (
|
|
|
58
58
|
},
|
|
59
59
|
|
|
60
60
|
addAll: entries => {
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
entries = getCopyMapEntries(entries);
|
|
64
|
-
} else {
|
|
65
|
-
Fail`provided data source is not iterable: ${entries}`;
|
|
66
|
-
}
|
|
61
|
+
if (isCopyMap(entries)) {
|
|
62
|
+
entries = getCopyMapEntries(entries);
|
|
67
63
|
}
|
|
68
64
|
for (const [key, value] of /** @type {Iterable<[K, V]>} */ (entries)) {
|
|
69
65
|
// Don't assert that the key either does or does not exist.
|
|
@@ -75,22 +71,22 @@ export const makeWeakMapStoreMethods = (
|
|
|
75
71
|
};
|
|
76
72
|
|
|
77
73
|
/**
|
|
78
|
-
* This is a
|
|
79
|
-
* primitives or remotables.
|
|
80
|
-
*
|
|
81
|
-
* their contents.
|
|
74
|
+
* This is a *scalar* mapStore in that the keys can only be atomic values:
|
|
75
|
+
* primitives or remotables.
|
|
76
|
+
* Other mapStores will accept, for example, copyArrays and
|
|
77
|
+
* copyRecords as keys and look them up based on equality of their contents.
|
|
82
78
|
*
|
|
83
79
|
* TODO For now, this scalarWeakMap accepts only remotables, reflecting the
|
|
84
|
-
* constraints of the underlying JavaScript WeakMap it uses internally. But
|
|
85
|
-
* should accept the primitives as well, storing them in a separate internal
|
|
80
|
+
* constraints of the underlying JavaScript WeakMap it uses internally. But
|
|
81
|
+
* it should accept the primitives as well, storing them in a separate internal
|
|
86
82
|
* map. What makes it "weak" is that it provides no API for enumerating what's
|
|
87
|
-
* there. Though note that this would only enables collection of the
|
|
88
|
-
* since the other primitives may always reappear.
|
|
83
|
+
* there. Though note that this would only enables collection of the
|
|
84
|
+
* remotables, since the other primitives may always reappear.
|
|
89
85
|
*
|
|
90
86
|
* @template K,V
|
|
91
|
-
* @param {string} [tag] - tag for debugging
|
|
87
|
+
* @param {string} [tag='key'] - tag for debugging
|
|
92
88
|
* @param {StoreOptions} [options]
|
|
93
|
-
* @returns {WeakMapStore<K,
|
|
89
|
+
* @returns {WeakMapStore<K,V>}
|
|
94
90
|
*/
|
|
95
91
|
export const makeScalarWeakMapStore = (
|
|
96
92
|
tag = 'key',
|
|
@@ -42,12 +42,8 @@ export const makeWeakSetStoreMethods = (
|
|
|
42
42
|
},
|
|
43
43
|
|
|
44
44
|
addAll: keys => {
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
keys = getCopySetKeys(keys);
|
|
48
|
-
} else {
|
|
49
|
-
Fail`provided data source is not iterable: ${keys}`;
|
|
50
|
-
}
|
|
45
|
+
if (isCopySet(keys)) {
|
|
46
|
+
keys = getCopySetKeys(keys);
|
|
51
47
|
}
|
|
52
48
|
for (const key of /** @type {Iterable<K>} */ (keys)) {
|
|
53
49
|
assertKeyOkToAdd(key);
|
|
@@ -58,19 +54,19 @@ export const makeWeakSetStoreMethods = (
|
|
|
58
54
|
};
|
|
59
55
|
|
|
60
56
|
/**
|
|
61
|
-
* This is a
|
|
57
|
+
* This is a *scalar* set in that the keys can only be atomic values, primitives
|
|
62
58
|
* or remotables. Other storeSets will accept, for example, copyArrays and
|
|
63
59
|
* copyRecords, as keys and look them up based on equality of their contents.
|
|
64
60
|
*
|
|
65
61
|
* TODO For now, this scalarWeakSet accepts only remotables, reflecting the
|
|
66
|
-
* constraints of the underlying JavaScript WeakSet it uses internally. But
|
|
67
|
-
* should accept the primitives as well, storing them in a separate internal
|
|
62
|
+
* constraints of the underlying JavaScript WeakSet it uses internally. But
|
|
63
|
+
* it should accept the primitives as well, storing them in a separate internal
|
|
68
64
|
* set. What makes it "weak" is that it provides no API for enumerating what's
|
|
69
|
-
* there. Though note that this would only enables collection of the
|
|
70
|
-
* since the other primitives may always appear.
|
|
65
|
+
* there. Though note that this would only enables collection of the
|
|
66
|
+
* remotables, since the other primitives may always appear.
|
|
71
67
|
*
|
|
72
68
|
* @template K
|
|
73
|
-
* @param {string} [tag] - tag for debugging
|
|
69
|
+
* @param {string} [tag='key'] - tag for debugging
|
|
74
70
|
* @param {StoreOptions} [options]
|
|
75
71
|
* @returns {WeakSetStore<K>}
|
|
76
72
|
*/
|
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
import { Far } from '@endo/marshal';
|
|
2
2
|
import { M, matches } from '@endo/patterns';
|
|
3
3
|
|
|
4
|
-
/** @typedef {import('@endo/marshal').RankCompare} RankCompare */
|
|
5
|
-
|
|
6
4
|
const { Fail, quote: q } = assert;
|
|
7
5
|
|
|
8
|
-
// TODO: Undate `@endo/patterns` to export the original, and delete the
|
|
9
|
-
// reimplementation here.
|
|
10
6
|
/**
|
|
11
|
-
* Should behave identically to the one in `@endo/patterns`, but
|
|
12
|
-
* for now because `@endo/patterns` forgot to export this one.
|
|
13
|
-
* simple enough that I prefer a reimplementation to a deep import.
|
|
7
|
+
* Should behave identically to the one in `@endo/patterns`, but
|
|
8
|
+
* reimplemented for now because `@endo/patterns` forgot to export this one.
|
|
9
|
+
* This one is simple enough that I prefer a reimplementation to a deep import.
|
|
10
|
+
* TODO: Undate `@endo/patterns` to export the original, and delete the
|
|
11
|
+
* reimplementation here.
|
|
14
12
|
*
|
|
15
13
|
* @param {Passable} s
|
|
16
14
|
* @returns {s is CopySet}
|
|
17
15
|
*/
|
|
18
16
|
export const isCopySet = s => matches(s, M.set());
|
|
19
17
|
|
|
20
|
-
// TODO: Undate `@endo/patterns` to export the original, and delete the
|
|
21
|
-
// reimplementation here.
|
|
22
18
|
/**
|
|
23
|
-
* Should behave identically to the one in `@endo/patterns`, but
|
|
24
|
-
* for now because `@endo/patterns` forgot to export this one.
|
|
25
|
-
* simple enough that I prefer a reimplementation to a deep import.
|
|
19
|
+
* Should behave identically to the one in `@endo/patterns`, but
|
|
20
|
+
* reimplemented for now because `@endo/patterns` forgot to export this one.
|
|
21
|
+
* This one is simple enough that I prefer a reimplementation to a deep import.
|
|
22
|
+
* TODO: Undate `@endo/patterns` to export the original, and delete the
|
|
23
|
+
* reimplementation here.
|
|
26
24
|
*
|
|
27
25
|
* @param {Passable} m
|
|
28
26
|
* @returns {m is CopyMap}
|
|
@@ -45,7 +43,7 @@ export const isCopyMap = m => matches(m, M.map());
|
|
|
45
43
|
* @param {(k: K, v?: V) => void} assertOkToAdd
|
|
46
44
|
* @param {(k: K) => void} [assertOkToDelete]
|
|
47
45
|
* @param {string} [keyName]
|
|
48
|
-
* @returns {CurrentKeysKit<K,
|
|
46
|
+
* @returns {CurrentKeysKit<K,V>}
|
|
49
47
|
*/
|
|
50
48
|
export const makeCurrentKeysKit = (
|
|
51
49
|
getRawKeys,
|
|
@@ -109,12 +107,13 @@ export const makeCurrentKeysKit = (
|
|
|
109
107
|
harden(makeCurrentKeysKit);
|
|
110
108
|
|
|
111
109
|
/**
|
|
112
|
-
* Call `provideLazy` to get or make the value associated with the key.
|
|
113
|
-
* already is one, return that. Otherwise,
|
|
114
|
-
*
|
|
110
|
+
* Call `provideLazy` to get or make the value associated with the key.
|
|
111
|
+
* If there already is one, return that. Otherwise,
|
|
112
|
+
* call `makeValue(key)`, remember it as the value for
|
|
113
|
+
* that key, and return it.
|
|
115
114
|
*
|
|
116
115
|
* @template K,V
|
|
117
|
-
* @param {WeakMapStore<K,
|
|
116
|
+
* @param {WeakMapStore<K,V>} mapStore
|
|
118
117
|
* @param {K} key
|
|
119
118
|
* @param {(key: K) => V} makeValue
|
|
120
119
|
* @returns {V}
|
|
@@ -128,11 +127,12 @@ export const provideLazy = (mapStore, key, makeValue) => {
|
|
|
128
127
|
harden(provideLazy);
|
|
129
128
|
|
|
130
129
|
/**
|
|
131
|
-
* Helper for use cases in which the maker function is async.
|
|
132
|
-
* provideLazy calls with the same key, one may be making when the
|
|
133
|
-
* starts and it would make again.
|
|
134
|
-
*
|
|
135
|
-
*
|
|
130
|
+
* Helper for use cases in which the maker function is async.
|
|
131
|
+
* For two provideLazy calls with the same key, one may be making when the
|
|
132
|
+
* other call starts and it would make again.
|
|
133
|
+
* (Then there'd be a collision when the second tries to store
|
|
134
|
+
* the key.) This prevents that race condition by immediately storing a Promise
|
|
135
|
+
* for the maker in an ephemeral store.
|
|
136
136
|
*
|
|
137
137
|
* When the `store` argument is durable storage, note that it's possible for
|
|
138
138
|
* termination to happen after the make completes and before it reaches durable
|
|
@@ -147,16 +147,17 @@ export const makeAtomicProvider = store => {
|
|
|
147
147
|
const pending = new Map();
|
|
148
148
|
|
|
149
149
|
/**
|
|
150
|
-
* Call `provideAsync` to get or make the value associated with the key,
|
|
151
|
-
* the maker is asynchronous.
|
|
152
|
-
*
|
|
153
|
-
* it
|
|
150
|
+
* Call `provideAsync` to get or make the value associated with the key,
|
|
151
|
+
* when the maker is asynchronous.
|
|
152
|
+
* If there already is one, return that. Otherwise,
|
|
153
|
+
* call `makeValue(key)`, remember it as the value for
|
|
154
|
+
* that key, and return it.
|
|
154
155
|
*
|
|
155
156
|
* @param {K} key
|
|
156
|
-
* @param {(key: K) => Promise<V>} makeValue make the value for the store
|
|
157
|
-
*
|
|
157
|
+
* @param {(key: K) => Promise<V>} makeValue make the value for the store
|
|
158
|
+
* if it hasn't been made yet or the last make failed
|
|
158
159
|
* @param {(key: K, value: V) => Promise<void>} [finishValue] runs exactly
|
|
159
|
-
*
|
|
160
|
+
* once after a new value is added to the store
|
|
160
161
|
* @returns {Promise<V>}
|
|
161
162
|
*/
|
|
162
163
|
const provideAsync = (key, makeValue, finishValue) => {
|