mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-19 19:55:51 +00:00
Fix generateXAddress() and generateXAddress() with no entropy (#1211)
Fix #1209 Calling: Uint8Array.from(undefined) Throws: TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator)) at Function.from (<anonymous>) * generateSeed: Pass only entropy and algorithm * Update typescript and ripple-keypairs * Improve unit tests * Rename [Original Address] to [Classic Address] in test output
This commit is contained in:
@@ -29,7 +29,7 @@
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"ripple-address-codec": "^4.0.0",
|
||||
"ripple-binary-codec": "^0.2.5",
|
||||
"ripple-keypairs": "^1.0.0-beta.6",
|
||||
"ripple-keypairs": "^1.0.0",
|
||||
"ripple-lib-transactionparser": "0.8.2",
|
||||
"ws": "^7.2.0"
|
||||
},
|
||||
@@ -49,7 +49,7 @@
|
||||
"nyc": "^15.0.0",
|
||||
"prettier": "^1.19.1",
|
||||
"ts-node": "^8.4.1",
|
||||
"typescript": "^3.6.4",
|
||||
"typescript": "^3.7.5",
|
||||
"webpack": "^4.41.2",
|
||||
"webpack-bundle-analyzer": "^3.6.0",
|
||||
"webpack-cli": "^3.3.9"
|
||||
|
||||
@@ -28,10 +28,13 @@ export interface GenerateAddressOptions {
|
||||
function generateAddressAPI(options: GenerateAddressOptions): GeneratedAddress {
|
||||
validate.generateAddress({options})
|
||||
try {
|
||||
const secret = keypairs.generateSeed({
|
||||
entropy: Uint8Array.from(options.entropy),
|
||||
const generateSeedOptions: { entropy?: Uint8Array; algorithm?: "ecdsa-secp256k1" | "ed25519"; } = {
|
||||
algorithm: options.algorithm
|
||||
})
|
||||
}
|
||||
if (options.entropy) {
|
||||
generateSeedOptions.entropy = Uint8Array.from(options.entropy)
|
||||
}
|
||||
const secret = keypairs.generateSeed(generateSeedOptions)
|
||||
const keypair = keypairs.deriveKeypair(secret)
|
||||
const classicAddress = keypairs.deriveAddress(keypair.publicKey)
|
||||
const returnValue: any = {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import assert from 'assert-diff'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {TestSuite} from '../../utils'
|
||||
import { GenerateAddressOptions } from '../../../src/offline/generate-address'
|
||||
const {generateAddress: RESPONSE_FIXTURES} = responses
|
||||
|
||||
/**
|
||||
@@ -9,22 +10,192 @@ const {generateAddress: RESPONSE_FIXTURES} = responses
|
||||
* - Check out "test/api/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'generateAddress': async (api, address) => {
|
||||
function random(): number[] {
|
||||
'generateAddress': async (api) => {
|
||||
// GIVEN entropy of all zeros
|
||||
function random() {
|
||||
return new Array(16).fill(0)
|
||||
}
|
||||
|
||||
assert.deepEqual(
|
||||
// WHEN generating an address
|
||||
api.generateAddress({entropy: random()}),
|
||||
|
||||
// THEN we get the expected return value
|
||||
RESPONSE_FIXTURES
|
||||
)
|
||||
},
|
||||
|
||||
'generateAddress invalid': async (api, address) => {
|
||||
'generateAddress invalid entropy': async (api) => {
|
||||
assert.throws(() => {
|
||||
// GIVEN entropy of 1 byte
|
||||
function random() {
|
||||
return new Array(1).fill(0)
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
api.generateAddress({entropy: random()})
|
||||
|
||||
// THEN an UnexpectedError is thrown
|
||||
// because 16 bytes of entropy are required
|
||||
}, api.errors.UnexpectedError)
|
||||
},
|
||||
|
||||
'generateAddress with no options object': async (api) => {
|
||||
// GIVEN no options
|
||||
|
||||
// WHEN generating an address
|
||||
const account = api.generateAddress()
|
||||
|
||||
// THEN we get an object with an address starting with 'r' and a secret starting with 's'
|
||||
assert(account.address.startsWith('r'), 'Address must start with `r`')
|
||||
assert(account.secret.startsWith('s'), 'Secret must start with `s`')
|
||||
},
|
||||
|
||||
'generateAddress with empty options object': async (api) => {
|
||||
// GIVEN an empty options object
|
||||
const options = {}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = api.generateAddress(options)
|
||||
|
||||
// THEN we get an object with an address starting with 'r' and a secret starting with 's'
|
||||
assert(account.address.startsWith('r'), 'Address must start with `r`')
|
||||
assert(account.secret.startsWith('s'), 'Secret must start with `s`')
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ecdsa-secp256k1`': async (api) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1'
|
||||
const options: GenerateAddressOptions = {algorithm: 'ecdsa-secp256k1'}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = api.generateAddress(options)
|
||||
|
||||
// THEN we get an object with an address starting with 'r' and a secret starting with 's' (not 'sEd')
|
||||
assert(account.address.startsWith('r'), 'Address must start with `r`')
|
||||
assert.deepEqual(account.secret.slice(0, 1), 's', `Secret ${account.secret} must start with 's'`)
|
||||
assert.notStrictEqual(account.secret.slice(0, 3), 'sEd', `secp256k1 secret ${account.secret} must not start with 'sEd'`)
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ed25519`': async (api) => {
|
||||
// GIVEN we want to use 'ed25519'
|
||||
const options: GenerateAddressOptions = {algorithm: 'ed25519'}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = api.generateAddress(options)
|
||||
|
||||
// THEN we get an object with an address starting with 'r' and a secret starting with 'sEd'
|
||||
assert(account.address.startsWith('r'), 'Address must start with `r`')
|
||||
assert.deepEqual(account.secret.slice(0, 3), 'sEd', `Ed25519 secret ${account.secret} must start with 'sEd'`)
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ecdsa-secp256k1` and given entropy': async (api) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1' with entropy of zero
|
||||
const options: GenerateAddressOptions = {algorithm: 'ecdsa-secp256k1', entropy: new Array(16).fill(0)}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = api.generateAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, responses.generateAddress)
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ed25519` and given entropy': async (api) => {
|
||||
// GIVEN we want to use 'ed25519' with entropy of zero
|
||||
const options: GenerateAddressOptions = {algorithm: 'ed25519', entropy: new Array(16).fill(0)}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = api.generateAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, {
|
||||
|
||||
// generateAddress return value always includes xAddress to encourage X-address adoption
|
||||
xAddress: 'X7xq1YJ4xmLSGGLhuakFQB9CebWYthQkgsvFC4LGFH871HB',
|
||||
|
||||
classicAddress: "r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7",
|
||||
address: "r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7",
|
||||
secret: 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE'
|
||||
})
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ecdsa-secp256k1` and given entropy; include classic address': async (api) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1' with entropy of zero
|
||||
const options: GenerateAddressOptions = {algorithm: 'ecdsa-secp256k1', entropy: new Array(16).fill(0), includeClassicAddress: true}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = api.generateAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, responses.generateAddress)
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ed25519` and given entropy; include classic address': async (api) => {
|
||||
// GIVEN we want to use 'ed25519' with entropy of zero
|
||||
const options: GenerateAddressOptions = {algorithm: 'ed25519', entropy: new Array(16).fill(0), includeClassicAddress: true}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = api.generateAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, {
|
||||
|
||||
// generateAddress return value always includes xAddress to encourage X-address adoption
|
||||
xAddress: 'X7xq1YJ4xmLSGGLhuakFQB9CebWYthQkgsvFC4LGFH871HB',
|
||||
|
||||
secret: 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE',
|
||||
classicAddress: "r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7",
|
||||
address: "r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7"
|
||||
})
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ecdsa-secp256k1` and given entropy; include classic address; for test network use': async (api) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1' with entropy of zero
|
||||
const options: GenerateAddressOptions = {algorithm: 'ecdsa-secp256k1', entropy: new Array(16).fill(0), includeClassicAddress: true, test: true}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = api.generateAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
const response = Object.assign({}, responses.generateAddress, {
|
||||
|
||||
// generateAddress return value always includes xAddress to encourage X-address adoption
|
||||
xAddress: 'TVG3TcCD58BD6MZqsNuTihdrhZwR8SzvYS8U87zvHsAcNw4'
|
||||
|
||||
})
|
||||
assert.deepEqual(account, response)
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ed25519` and given entropy; include classic address; for test network use': async (api) => {
|
||||
// GIVEN we want to use 'ed25519' with entropy of zero
|
||||
const options: GenerateAddressOptions = {algorithm: 'ed25519', entropy: new Array(16).fill(0), includeClassicAddress: true, test: true}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = api.generateAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, {
|
||||
|
||||
// generateAddress return value always includes xAddress to encourage X-address adoption
|
||||
xAddress: 'T7t4HeTMF5tT68agwuVbJwu23ssMPeh8dDtGysZoQiij1oo',
|
||||
|
||||
secret: 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE',
|
||||
classicAddress: "r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7",
|
||||
address: "r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7"
|
||||
})
|
||||
},
|
||||
|
||||
'generateAddress for test network use': async (api) => {
|
||||
// GIVEN we want an address for test network use
|
||||
const options: GenerateAddressOptions = {test: true}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = api.generateAddress(options)
|
||||
|
||||
// THEN we get an object with xAddress starting with 'T' and a secret starting with 's'
|
||||
|
||||
// generateAddress return value always includes xAddress to encourage X-address adoption
|
||||
assert.deepEqual(account.xAddress.slice(0, 1), 'T', 'Test addresses start with T')
|
||||
|
||||
assert.deepEqual(account.secret.slice(0, 1), 's', `Secret ${account.secret} must start with 's'`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import assert from 'assert-diff'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {TestSuite} from '../../utils'
|
||||
import { GenerateAddressOptions } from '../../../src/offline/generate-address'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
@@ -8,22 +9,175 @@ import {TestSuite} from '../../utils'
|
||||
* - Check out "test/api/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'generateXAddress': async (api, address) => {
|
||||
'generateXAddress': async (api) => {
|
||||
// GIVEN entropy of all zeros
|
||||
function random() {
|
||||
return new Array(16).fill(0)
|
||||
}
|
||||
|
||||
assert.deepEqual(
|
||||
// WHEN generating an X-address
|
||||
api.generateXAddress({entropy: random()}),
|
||||
|
||||
// THEN we get the expected return value
|
||||
responses.generateXAddress
|
||||
)
|
||||
},
|
||||
|
||||
'generateXAddress invalid': async (api, address) => {
|
||||
'generateXAddress invalid entropy': async (api) => {
|
||||
assert.throws(() => {
|
||||
// GIVEN entropy of 1 byte
|
||||
function random() {
|
||||
return new Array(1).fill(0)
|
||||
}
|
||||
|
||||
// WHEN generating an X-address
|
||||
api.generateXAddress({entropy: random()})
|
||||
|
||||
// THEN an UnexpectedError is thrown
|
||||
// because 16 bytes of entropy are required
|
||||
}, api.errors.UnexpectedError)
|
||||
},
|
||||
|
||||
'generateXAddress with no options object': async (api) => {
|
||||
// GIVEN no options
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = api.generateXAddress()
|
||||
|
||||
// THEN we get an object with an xAddress starting with 'X' and a secret starting with 's'
|
||||
assert(account.xAddress.startsWith('X'), 'By default X-addresses start with X')
|
||||
assert(account.secret.startsWith('s'), 'Secrets start with s')
|
||||
},
|
||||
|
||||
'generateXAddress with empty options object': async (api) => {
|
||||
// GIVEN an empty options object
|
||||
const options = {}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = api.generateXAddress(options)
|
||||
|
||||
// THEN we get an object with an xAddress starting with 'X' and a secret starting with 's'
|
||||
assert(account.xAddress.startsWith('X'), 'By default X-addresses start with X')
|
||||
assert(account.secret.startsWith('s'), 'Secrets start with s')
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ecdsa-secp256k1`': async (api) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1'
|
||||
const options: GenerateAddressOptions = {algorithm: 'ecdsa-secp256k1'}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = api.generateXAddress(options)
|
||||
|
||||
// THEN we get an object with an xAddress starting with 'X' and a secret starting with 's'
|
||||
assert(account.xAddress.startsWith('X'), 'By default X-addresses start with X')
|
||||
assert.deepEqual(account.secret.slice(0, 1), 's', `Secret ${account.secret} must start with 's'`)
|
||||
assert.notStrictEqual(account.secret.slice(0, 3), 'sEd', `secp256k1 secret ${account.secret} must not start with 'sEd'`)
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ed25519`': async (api) => {
|
||||
// GIVEN we want to use 'ed25519'
|
||||
const options: GenerateAddressOptions = {algorithm: 'ed25519'}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = api.generateXAddress(options)
|
||||
|
||||
// THEN we get an object with an xAddress starting with 'X' and a secret starting with 'sEd'
|
||||
assert(account.xAddress.startsWith('X'), 'By default X-addresses start with X')
|
||||
assert.deepEqual(account.secret.slice(0, 3), 'sEd', `Ed25519 secret ${account.secret} must start with 'sEd'`)
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ecdsa-secp256k1` and given entropy': async (api) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1' with entropy of zero
|
||||
const options: GenerateAddressOptions = {algorithm: 'ecdsa-secp256k1', entropy: new Array(16).fill(0)}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = api.generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, responses.generateXAddress)
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ed25519` and given entropy': async (api) => {
|
||||
// GIVEN we want to use 'ed25519' with entropy of zero
|
||||
const options: GenerateAddressOptions = {algorithm: 'ed25519', entropy: new Array(16).fill(0)}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = api.generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, {
|
||||
xAddress: 'X7xq1YJ4xmLSGGLhuakFQB9CebWYthQkgsvFC4LGFH871HB',
|
||||
secret: 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE'
|
||||
})
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ecdsa-secp256k1` and given entropy; include classic address': async (api) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1' with entropy of zero
|
||||
const options: GenerateAddressOptions = {algorithm: 'ecdsa-secp256k1', entropy: new Array(16).fill(0), includeClassicAddress: true}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = api.generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, responses.generateAddress)
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ed25519` and given entropy; include classic address': async (api) => {
|
||||
// GIVEN we want to use 'ed25519' with entropy of zero
|
||||
const options: GenerateAddressOptions = {algorithm: 'ed25519', entropy: new Array(16).fill(0), includeClassicAddress: true}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = api.generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, {
|
||||
xAddress: 'X7xq1YJ4xmLSGGLhuakFQB9CebWYthQkgsvFC4LGFH871HB',
|
||||
secret: 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE',
|
||||
classicAddress: "r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7",
|
||||
address: "r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7"
|
||||
})
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ecdsa-secp256k1` and given entropy; include classic address; for test network use': async (api) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1' with entropy of zero
|
||||
const options: GenerateAddressOptions = {algorithm: 'ecdsa-secp256k1', entropy: new Array(16).fill(0), includeClassicAddress: true, test: true}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = api.generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
const response = Object.assign({}, responses.generateAddress, {
|
||||
xAddress: 'TVG3TcCD58BD6MZqsNuTihdrhZwR8SzvYS8U87zvHsAcNw4'
|
||||
})
|
||||
assert.deepEqual(account, response)
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ed25519` and given entropy; include classic address; for test network use': async (api) => {
|
||||
// GIVEN we want to use 'ed25519' with entropy of zero
|
||||
const options: GenerateAddressOptions = {algorithm: 'ed25519', entropy: new Array(16).fill(0), includeClassicAddress: true, test: true}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = api.generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, {
|
||||
xAddress: 'T7t4HeTMF5tT68agwuVbJwu23ssMPeh8dDtGysZoQiij1oo',
|
||||
secret: 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE',
|
||||
classicAddress: "r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7",
|
||||
address: "r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7"
|
||||
})
|
||||
},
|
||||
|
||||
'generateXAddress for test network use': async (api) => {
|
||||
// GIVEN we want an X-address for test network use
|
||||
const options: GenerateAddressOptions = {test: true}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = api.generateXAddress(options)
|
||||
|
||||
// THEN we get an object with xAddress starting with 'T' and a secret starting with 's'
|
||||
assert.deepEqual(account.xAddress.slice(0, 1), 'T', 'Test X-addresses start with T')
|
||||
assert.deepEqual(account.secret.slice(0, 1), 's', `Secret ${account.secret} must start with 's'`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,21 +32,33 @@ describe('RippleAPI [Test Runner]', function() {
|
||||
// Run all the tests:
|
||||
for (const {name: methodName, tests, config} of allTestSuites) {
|
||||
describe(`api.${methodName}`, () => {
|
||||
// Run each test with the original-style address.
|
||||
describe(`[Original Address]`, () => {
|
||||
for (const [testName, fn] of tests) {
|
||||
// Run each test that does not use an address.
|
||||
for (const [testName, fn] of tests) {
|
||||
if (fn.length === 1) {
|
||||
it(testName, function() {
|
||||
return fn(this.api, addresses.ACCOUNT)
|
||||
})
|
||||
}
|
||||
}
|
||||
// Run each test with a classic address.
|
||||
describe(`[Classic Address]`, () => {
|
||||
for (const [testName, fn] of tests) {
|
||||
if (fn.length === 2) {
|
||||
it(testName, function() {
|
||||
return fn(this.api, addresses.ACCOUNT)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
// Run each test with the newer, x-address style.
|
||||
// Run each test with an X-address.
|
||||
if (!config.skipXAddress) {
|
||||
describe(`[X-address]`, () => {
|
||||
for (const [testName, fn] of tests) {
|
||||
it(testName, function() {
|
||||
return fn(this.api, addresses.ACCOUNT_X)
|
||||
})
|
||||
if (fn.length === 2) {
|
||||
it(testName, function() {
|
||||
return fn(this.api, addresses.ACCOUNT_X)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4121,7 +4121,7 @@ ripple-binary-codec@^0.2.5:
|
||||
lodash "^4.17.15"
|
||||
ripple-address-codec "^4.0.0"
|
||||
|
||||
ripple-keypairs@^1.0.0-beta.6:
|
||||
ripple-keypairs@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ripple-keypairs/-/ripple-keypairs-1.0.0.tgz#8f1c604f89daeac5e61b7eebbbca2da99da2bacf"
|
||||
integrity sha512-MQ3d6fU3D+Cqu5ma4dfkfa+KakN2sKpVVVN0FeJyAYPVIGXu8Rcvd1g028TdwYAZcSYk0tGn5UhHxd0gUG3T8g==
|
||||
@@ -4801,7 +4801,7 @@ typedarray@^0.0.6:
|
||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||
|
||||
typescript@^3.6.4:
|
||||
typescript@^3.7.5:
|
||||
version "3.7.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
|
||||
integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==
|
||||
|
||||
Reference in New Issue
Block a user