@agoric/wallet-backend 0.13.5 → 0.13.6-dev-d32a66a.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/bundles/bundle-wallet-js-meta.json +582 -0
- package/bundles/bundle-wallet.js +1 -1
- package/deploy.js +2 -2
- package/jsconfig.json +1 -15
- package/package.json +22 -22
- package/scripts/build-bundles.js +1 -1
- package/src/findOrMakeInvitation.js +10 -13
- package/src/internal-types.js +6 -4
- package/src/issuerTable.js +5 -5
- package/src/lib-dehydrate.js +24 -31
- package/src/lib-wallet.js +85 -210
- package/src/types.js +2 -2
- package/src/wallet.js +4 -8
- package/test/test-getPursesNotifier.js +15 -16
- package/test/test-lib-dehydrate.js +10 -10
- package/test/test-lib-wallet.js +38 -247
- package/test/test-middleware.js +7 -15
- package/bundles/bundle-wallet-meta.js +0 -490
- package/src/marshal-contexts.js +0 -387
- package/test/attestationExample.js +0 -65
- package/test/test-wallet-marshal.js +0 -184
package/deploy.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// FIXME: This is just hacked together for the legacy wallet.
|
|
4
4
|
|
|
5
5
|
import { E } from '@endo/eventual-send';
|
|
6
|
-
import {
|
|
6
|
+
import { Fail } from '@agoric/assert';
|
|
7
7
|
import path from 'path';
|
|
8
8
|
|
|
9
9
|
const filename = new URL(import.meta.url).pathname;
|
|
@@ -63,7 +63,7 @@ export default async function deployWallet(
|
|
|
63
63
|
issuers.map(async ([issuerPetname, issuer]) => {
|
|
64
64
|
const brand = await E(issuer).getBrand();
|
|
65
65
|
const brandMatches = E(brand).isMyIssuer(issuer);
|
|
66
|
-
|
|
66
|
+
brandMatches || Fail`issuer was using a brand which was not its own`;
|
|
67
67
|
brandToIssuer.set(brand, { issuerPetname, issuer });
|
|
68
68
|
}),
|
|
69
69
|
]);
|
package/jsconfig.json
CHANGED
|
@@ -1,20 +1,6 @@
|
|
|
1
1
|
// This file can contain .js-specific Typescript compiler config.
|
|
2
2
|
{
|
|
3
|
-
"
|
|
4
|
-
"target": "esnext",
|
|
5
|
-
"module": "esnext",
|
|
6
|
-
|
|
7
|
-
"noEmit": true,
|
|
8
|
-
/*
|
|
9
|
-
// The following flags are for creating .d.ts files:
|
|
10
|
-
"noEmit": false,
|
|
11
|
-
"declaration": true,
|
|
12
|
-
"emitDeclarationOnly": true,
|
|
13
|
-
*/
|
|
14
|
-
"downlevelIteration": true,
|
|
15
|
-
"strictNullChecks": true,
|
|
16
|
-
"moduleResolution": "node",
|
|
17
|
-
},
|
|
3
|
+
"extends": "../../../tsconfig.json",
|
|
18
4
|
"include": [
|
|
19
5
|
"*.js",
|
|
20
6
|
"scripts/**/*.js",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/wallet-backend",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.6-dev-d32a66a.0+d32a66a",
|
|
4
4
|
"description": "Wallet backend",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -10,31 +10,31 @@
|
|
|
10
10
|
"test:xs": "exit 0",
|
|
11
11
|
"lint": "run-s --continue-on-error lint:*",
|
|
12
12
|
"lint-fix": "yarn lint:eslint --fix",
|
|
13
|
-
"lint:types": "tsc
|
|
13
|
+
"lint:types": "tsc -p jsconfig.json",
|
|
14
14
|
"lint:eslint": "eslint ."
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@agoric/
|
|
18
|
-
"@
|
|
19
|
-
"@endo/
|
|
20
|
-
"
|
|
21
|
-
"ava": "^4.3.1"
|
|
17
|
+
"@agoric/vats": "0.13.3-dev-d32a66a.0+d32a66a",
|
|
18
|
+
"@endo/bundle-source": "^2.5.1",
|
|
19
|
+
"@endo/init": "^0.5.56",
|
|
20
|
+
"ava": "^5.2.0"
|
|
22
21
|
},
|
|
23
22
|
"dependencies": {
|
|
24
|
-
"@agoric/assert": "
|
|
25
|
-
"@agoric/cache": "
|
|
26
|
-
"@agoric/ertp": "
|
|
27
|
-
"@agoric/
|
|
28
|
-
"@agoric/
|
|
29
|
-
"@agoric/
|
|
30
|
-
"@agoric/
|
|
31
|
-
"@agoric/
|
|
32
|
-
"@agoric/vat-data": "
|
|
33
|
-
"@agoric/zoe": "
|
|
34
|
-
"@endo/eventual-send": "^0.
|
|
35
|
-
"@endo/marshal": "^0.
|
|
36
|
-
"@endo/
|
|
37
|
-
"
|
|
23
|
+
"@agoric/assert": "0.5.2-dev-d32a66a.0+d32a66a",
|
|
24
|
+
"@agoric/cache": "0.2.5-dev-d32a66a.0+d32a66a",
|
|
25
|
+
"@agoric/ertp": "0.15.6-dev-d32a66a.0+d32a66a",
|
|
26
|
+
"@agoric/internal": "0.2.2-dev-d32a66a.0+d32a66a",
|
|
27
|
+
"@agoric/notifier": "0.5.2-dev-d32a66a.0+d32a66a",
|
|
28
|
+
"@agoric/smart-wallet": "0.4.5-dev-d32a66a.0+d32a66a",
|
|
29
|
+
"@agoric/store": "0.8.6-dev-d32a66a.0+d32a66a",
|
|
30
|
+
"@agoric/time": "0.2.2-dev-d32a66a.0+d32a66a",
|
|
31
|
+
"@agoric/vat-data": "0.4.6-dev-d32a66a.0+d32a66a",
|
|
32
|
+
"@agoric/zoe": "0.25.6-dev-d32a66a.0+d32a66a",
|
|
33
|
+
"@endo/eventual-send": "^0.17.2",
|
|
34
|
+
"@endo/marshal": "^0.8.5",
|
|
35
|
+
"@endo/nat": "^4.1.27",
|
|
36
|
+
"@endo/promise-kit": "^0.2.56",
|
|
37
|
+
"import-meta-resolve": "^2.2.1"
|
|
38
38
|
},
|
|
39
39
|
"keywords": [],
|
|
40
40
|
"repository": {
|
|
@@ -57,5 +57,5 @@
|
|
|
57
57
|
"publishConfig": {
|
|
58
58
|
"access": "public"
|
|
59
59
|
},
|
|
60
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "d32a66afa6bc92169b51ad73adf2432f4e2ef848"
|
|
61
61
|
}
|
package/scripts/build-bundles.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
2
|
import '@endo/init';
|
|
3
|
-
import { createBundles } from '@agoric/
|
|
3
|
+
import { createBundles } from '@agoric/internal/src/node/createBundles.js';
|
|
4
4
|
import url from 'url';
|
|
5
5
|
|
|
6
6
|
const dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assert,
|
|
1
|
+
import { assert, Fail, q } from '@agoric/assert';
|
|
2
2
|
import { E } from '@endo/eventual-send';
|
|
3
3
|
import { passStyleOf } from '@endo/marshal';
|
|
4
4
|
import { AmountMath } from '@agoric/ertp';
|
|
@@ -8,20 +8,18 @@ export const makeId = (dappOrigin, rawId) => `${dappOrigin}#${rawId}`;
|
|
|
8
8
|
const assertFirstCapASCII = str => {
|
|
9
9
|
assert.typeof(str, 'string');
|
|
10
10
|
const firstCapASCII = /^[A-Z][a-zA-Z0-9_$]*$/;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
X`The string ${q(
|
|
11
|
+
firstCapASCII.test(str) ||
|
|
12
|
+
Fail`The string ${q(
|
|
14
13
|
str,
|
|
15
|
-
)} must be an ascii identifier starting with upper case
|
|
16
|
-
);
|
|
14
|
+
)} must be an ascii identifier starting with upper case.`;
|
|
17
15
|
(str !== 'NaN' && str !== 'Infinity') ||
|
|
18
|
-
|
|
16
|
+
Fail`keyword ${q(str)} must not be a number's name`;
|
|
19
17
|
};
|
|
20
18
|
|
|
21
19
|
/**
|
|
22
20
|
* @param {Amount<'set'>} invitationPurseBalance
|
|
23
21
|
* @param {object} query
|
|
24
|
-
* @param {Board} query.board
|
|
22
|
+
* @param {import('@agoric/vats').Board} query.board
|
|
25
23
|
* @param {string} query.boardId
|
|
26
24
|
* @returns {Promise<Array>}
|
|
27
25
|
* @deprecated
|
|
@@ -31,8 +29,7 @@ const findByBoardId = async (invitationPurseBalance, { board, boardId }) => {
|
|
|
31
29
|
const invitationHandle = await E(board).getValue(boardId);
|
|
32
30
|
const match = element => element.handle === invitationHandle;
|
|
33
31
|
const matchingValue = invitationPurseBalance.value.find(match);
|
|
34
|
-
matchingValue ||
|
|
35
|
-
assert.fail(X`Cannot find invitation corresponding to ${q(boardId)}`);
|
|
32
|
+
matchingValue || Fail`Cannot find invitation corresponding to ${q(boardId)}`;
|
|
36
33
|
|
|
37
34
|
return harden([matchingValue]);
|
|
38
35
|
};
|
|
@@ -53,7 +50,7 @@ const findByKeyValuePairs = async (invitationPurseBalance, kvs) => {
|
|
|
53
50
|
);
|
|
54
51
|
|
|
55
52
|
const matchingValue = invitationPurseBalance.value.find(matches);
|
|
56
|
-
|
|
53
|
+
matchingValue || Fail`Cannot find invitation corresponding to ${q(kvs)}`;
|
|
57
54
|
return harden([matchingValue]);
|
|
58
55
|
};
|
|
59
56
|
|
|
@@ -94,7 +91,7 @@ const makeContinuingInvitation = async (
|
|
|
94
91
|
/**
|
|
95
92
|
* @param {InvitationMaker} invitationMaker
|
|
96
93
|
* @param {string} instanceHandleBoardId
|
|
97
|
-
* @param {Board} board
|
|
94
|
+
* @param {import('@agoric/vats').Board} board
|
|
98
95
|
* @param {ZoeService} zoe
|
|
99
96
|
* @returns {Promise<Invitation>}
|
|
100
97
|
*/
|
|
@@ -169,5 +166,5 @@ export const findOrMakeInvitation = async (
|
|
|
169
166
|
);
|
|
170
167
|
}
|
|
171
168
|
|
|
172
|
-
|
|
169
|
+
throw Fail`no invitation was found or made for this offer ${offer.id}`;
|
|
173
170
|
};
|
package/src/internal-types.js
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* @property {PurseActions} actions
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
/** @typedef {import('@agoric/deploy-script-support/src/externalTypes').Petname} Petname */
|
|
11
|
+
|
|
10
12
|
/**
|
|
11
13
|
* @typedef {PursesJSONState & PursesAddedState} PursesFullState
|
|
12
14
|
*/
|
|
@@ -27,12 +29,12 @@
|
|
|
27
29
|
|
|
28
30
|
/**
|
|
29
31
|
* @typedef {object} Contact
|
|
30
|
-
* @property {string
|
|
32
|
+
* @property {string} [depositBoardId]
|
|
31
33
|
*/
|
|
32
34
|
|
|
33
35
|
/**
|
|
34
36
|
* @typedef {object} DappRecord
|
|
35
|
-
* @property {Promise<void
|
|
37
|
+
* @property {Promise<void>} [approvalP]
|
|
36
38
|
* @property {Petname} suggestedPetname
|
|
37
39
|
* @property {Petname} petname
|
|
38
40
|
* @property {boolean} enable
|
|
@@ -54,11 +56,11 @@
|
|
|
54
56
|
* @property {(petname: Petname) => string} implode
|
|
55
57
|
* @property {(str: string) => Petname} explode
|
|
56
58
|
* @property {LegacyWeakMap<T, Petname>} valToPetname
|
|
57
|
-
* @property {
|
|
59
|
+
* @property {WeakMapStore<T, string[][]>} valToPaths
|
|
58
60
|
* TODO What about when useLegacyMap is true because contact have
|
|
59
61
|
* identity? `T` would be `Contact`. Shouldn't `valToPaths` be
|
|
60
62
|
* a `LegacyWeakMap`?
|
|
61
|
-
* @property {
|
|
63
|
+
* @property {MapStore<Petname, T>} petnameToVal
|
|
62
64
|
* @property {(petname: Petname, val: T) => void} addPetname
|
|
63
65
|
* @property {(path: string[], val: T) => void} addPath
|
|
64
66
|
* @property {(petname: Petname, val: T) => void} renamePetname
|
package/src/issuerTable.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { assert } from '@agoric/assert';
|
|
4
4
|
import { E } from '@endo/eventual-send';
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { makeScalarWeakMapStore } from '@agoric/store';
|
|
7
7
|
|
|
8
8
|
import '../exported.js';
|
|
9
9
|
import './internal-types.js';
|
|
@@ -21,10 +21,10 @@ import './internal-types.js';
|
|
|
21
21
|
* remote calls to get the brand and AmountMath and save them.
|
|
22
22
|
*/
|
|
23
23
|
const makeIssuerTable = () => {
|
|
24
|
-
/** @type {
|
|
25
|
-
const brandToIssuerRecord =
|
|
26
|
-
/** @type {
|
|
27
|
-
const issuerToIssuerRecord =
|
|
24
|
+
/** @type {WeakMapStore<Brand,IssuerRecord>} */
|
|
25
|
+
const brandToIssuerRecord = makeScalarWeakMapStore('brand');
|
|
26
|
+
/** @type {WeakMapStore<Issuer,IssuerRecord>} */
|
|
27
|
+
const issuerToIssuerRecord = makeScalarWeakMapStore('issuer');
|
|
28
28
|
|
|
29
29
|
/** @type {IssuerTable} */
|
|
30
30
|
const issuerTable = {
|
package/src/lib-dehydrate.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
import { makeMarshal, mapIterable } from '@endo/marshal';
|
|
4
|
-
import { makeLegacyMap,
|
|
5
|
-
import { assert,
|
|
4
|
+
import { makeLegacyMap, makeScalarMapStore } from '@agoric/store';
|
|
5
|
+
import { assert, Fail, q } from '@agoric/assert';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @typedef {string[]} Path
|
|
@@ -14,7 +14,7 @@ export const isPath = x => {
|
|
|
14
14
|
if (!Array.isArray(x)) {
|
|
15
15
|
return false;
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
x.length > 0 || Fail`Path ${q(x)} must not be empty`;
|
|
18
18
|
for (const name of x) {
|
|
19
19
|
if (typeof name !== 'string') {
|
|
20
20
|
return false;
|
|
@@ -40,8 +40,8 @@ export const makeDehydrator = (initialUnnamedCount = 0) => {
|
|
|
40
40
|
// Paths are kept across all kinds.
|
|
41
41
|
// TODO What about when useLegacyMap is true because contact have
|
|
42
42
|
// identity?
|
|
43
|
-
/** @type {
|
|
44
|
-
const valToPaths =
|
|
43
|
+
/** @type {MapStore<any, Path[]>} */
|
|
44
|
+
const valToPaths = makeScalarMapStore('value');
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
47
|
* @param {string} data
|
|
@@ -49,9 +49,7 @@ export const makeDehydrator = (initialUnnamedCount = 0) => {
|
|
|
49
49
|
*/
|
|
50
50
|
const explode = data => {
|
|
51
51
|
data.startsWith(IMPLODE_PREFIX) ||
|
|
52
|
-
|
|
53
|
-
X`exploded string ${data} must start with ${q(IMPLODE_PREFIX)}`,
|
|
54
|
-
);
|
|
52
|
+
Fail`exploded string ${data} must start with ${q(IMPLODE_PREFIX)}`;
|
|
55
53
|
const strongname = JSON.parse(data.slice(IMPLODE_PREFIX.length));
|
|
56
54
|
if (!isPath(strongname)) {
|
|
57
55
|
return strongname;
|
|
@@ -79,7 +77,7 @@ export const makeDehydrator = (initialUnnamedCount = 0) => {
|
|
|
79
77
|
const { petnameToVal: petnameToRoot } = edgeMapping;
|
|
80
78
|
if (!petnameToRoot.has(path[0])) {
|
|
81
79
|
// Avoid asserting, which fills up the logs.
|
|
82
|
-
|
|
80
|
+
Fail`Edgename for ${q(path[0])} petname not found`;
|
|
83
81
|
}
|
|
84
82
|
const root = petnameToRoot.get(path[0]);
|
|
85
83
|
path[0] = root;
|
|
@@ -90,12 +88,12 @@ export const makeDehydrator = (initialUnnamedCount = 0) => {
|
|
|
90
88
|
/**
|
|
91
89
|
* @template T
|
|
92
90
|
* @param {string} kind
|
|
93
|
-
* @param {{useLegacyMap?: boolean}
|
|
91
|
+
* @param {{ useLegacyMap?: boolean }} [legacyOptions]
|
|
94
92
|
* @returns {Mapping<T>}
|
|
95
93
|
*/
|
|
96
94
|
const makeMapping = (kind, { useLegacyMap = false } = {}) => {
|
|
97
|
-
|
|
98
|
-
const makeMap = useLegacyMap ? makeLegacyMap :
|
|
95
|
+
typeof kind === 'string' || `kind ${kind} must be a string`;
|
|
96
|
+
const makeMap = useLegacyMap ? makeLegacyMap : makeScalarMapStore;
|
|
99
97
|
// These are actually either a LegacyMap or a MapStore depending on
|
|
100
98
|
// useLegacyMap. Fortunately, the LegacyMap type is approximately the
|
|
101
99
|
// intersection of these, so we can just use it.
|
|
@@ -123,9 +121,9 @@ export const makeDehydrator = (initialUnnamedCount = 0) => {
|
|
|
123
121
|
return mapIterable(rawValToPetname.values(), val => explode(val));
|
|
124
122
|
},
|
|
125
123
|
};
|
|
126
|
-
/** @type {
|
|
127
|
-
const rawPetnameToVal =
|
|
128
|
-
/** @type {
|
|
124
|
+
/** @type {MapStore<string, T>} */
|
|
125
|
+
const rawPetnameToVal = makeScalarMapStore('petname');
|
|
126
|
+
/** @type {MapStore<Path | string, T>} */
|
|
129
127
|
const petnameToVal = {
|
|
130
128
|
...rawPetnameToVal,
|
|
131
129
|
init(key, val) {
|
|
@@ -164,7 +162,7 @@ export const makeDehydrator = (initialUnnamedCount = 0) => {
|
|
|
164
162
|
* @param {any} val
|
|
165
163
|
*/
|
|
166
164
|
const addPath = (path, val) => {
|
|
167
|
-
|
|
165
|
+
isPath(path) || Fail`path ${q(path)} must be an array of strings`;
|
|
168
166
|
|
|
169
167
|
if (
|
|
170
168
|
!valToPetname.has(val) &&
|
|
@@ -206,9 +204,8 @@ export const makeDehydrator = (initialUnnamedCount = 0) => {
|
|
|
206
204
|
if (petnameToVal.has(petname) && petnameToVal.get(petname) === val) {
|
|
207
205
|
return;
|
|
208
206
|
}
|
|
209
|
-
!petnameToVal.has(petname) ||
|
|
210
|
-
|
|
211
|
-
assert(!valToPetname.has(val), X`val ${val} already has a petname`);
|
|
207
|
+
!petnameToVal.has(petname) || Fail`petname ${petname} is already in use`;
|
|
208
|
+
!valToPetname.has(val) || Fail`val ${val} already has a petname`;
|
|
212
209
|
petnameToVal.init(petname, val);
|
|
213
210
|
valToPetname.init(val, petname);
|
|
214
211
|
|
|
@@ -219,11 +216,8 @@ export const makeDehydrator = (initialUnnamedCount = 0) => {
|
|
|
219
216
|
|
|
220
217
|
const renamePetname = (petname, val) => {
|
|
221
218
|
valToPetname.has(val) ||
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
);
|
|
225
|
-
!petnameToVal.has(petname) ||
|
|
226
|
-
assert.fail(X`petname ${petname} is already in use`);
|
|
219
|
+
Fail`val ${val} has not been previously named, would you like to add it instead?`;
|
|
220
|
+
!petnameToVal.has(petname) || Fail`petname ${petname} is already in use`;
|
|
227
221
|
// Delete the old mappings.
|
|
228
222
|
const oldPetname = valToPetname.get(val);
|
|
229
223
|
petnameToVal.delete(oldPetname);
|
|
@@ -266,12 +260,10 @@ export const makeDehydrator = (initialUnnamedCount = 0) => {
|
|
|
266
260
|
};
|
|
267
261
|
|
|
268
262
|
const deletePetname = petname => {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
X`petname ${q(
|
|
263
|
+
petnameToVal.has(petname) ||
|
|
264
|
+
Fail`petname ${q(
|
|
272
265
|
petname,
|
|
273
|
-
)} has not been previously named, would you like to add it instead
|
|
274
|
-
);
|
|
266
|
+
)} has not been previously named, would you like to add it instead?`;
|
|
275
267
|
|
|
276
268
|
// Delete the mappings.
|
|
277
269
|
const val = petnameToVal.get(petname);
|
|
@@ -341,7 +333,7 @@ export const makeDehydrator = (initialUnnamedCount = 0) => {
|
|
|
341
333
|
return petnameToVal.get(petname);
|
|
342
334
|
};
|
|
343
335
|
|
|
344
|
-
const {
|
|
336
|
+
const { toCapData: dehydrate, fromCapData: hydrate } = makeMarshal(
|
|
345
337
|
convertValToName,
|
|
346
338
|
convertNameToVal,
|
|
347
339
|
{
|
|
@@ -349,6 +341,7 @@ export const makeDehydrator = (initialUnnamedCount = 0) => {
|
|
|
349
341
|
// TODO Temporary hack.
|
|
350
342
|
// See https://github.com/Agoric/agoric-sdk/issues/2780
|
|
351
343
|
errorIdNum: 30000,
|
|
344
|
+
serializeBodyFormat: 'smallcaps',
|
|
352
345
|
},
|
|
353
346
|
);
|
|
354
347
|
return harden({
|
|
@@ -358,7 +351,7 @@ export const makeDehydrator = (initialUnnamedCount = 0) => {
|
|
|
358
351
|
/**
|
|
359
352
|
* @template T
|
|
360
353
|
* @param {string} kind
|
|
361
|
-
* @param {{useLegacyMap?: boolean}
|
|
354
|
+
* @param {{ useLegacyMap?: boolean }} [legacyOptions]
|
|
362
355
|
* @returns {Mapping<T>}
|
|
363
356
|
*/
|
|
364
357
|
makeMapping: (kind, legacyOptions = undefined) => {
|