diff --git a/package.json b/package.json index 018429d..3e2acd3 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "@rauschma/stringio": "^1.4.0", "axios": "^0.19.0", "lodash": "4.17.15", - "pact-lang-api": "https://github.com/kadena-io/pact-lang-api.git#c63892c", + "pact-lang-api": "https://github.com/kadena-io/pact-lang-api.git#0ecc7f9", "tmp": "0.1.0" }, "devDependencies": { diff --git a/src/pactApi.ts b/src/pactApi.ts index b9b2680..8451b86 100644 --- a/src/pactApi.ts +++ b/src/pactApi.ts @@ -17,13 +17,16 @@ export interface ISendOptions { keyPair: IKeyPair } +// The request format expected by the /local endpoint. +export interface ILocalRequest { + hash: string + sigs: {}[] + cmd: string +} + // The request format expected by the /send endpoint. export interface ISendRequest { - cmds: { - hash: string - sigs: {}[] - cmd: string - }[] + cmds: ILocalRequest[] } // The response format returned by the /send endpoint. @@ -53,11 +56,15 @@ export interface IListenResult { } // Example meta object. Currently we just send this with every transaction. -const META = { - chainId: '16', - gasPrice: 1, - gasLimit: 100000, - sender: 'someSender', +function meta() { + return { + sender: 'someSender', + chainId: '16', + gasPrice: 1, + gasLimit: 100000, + creationTime: Date.now() / 1000, + ttl: 6000, // 10 minutes + } } function generateNonce(): string { @@ -126,7 +133,7 @@ export default class PactApi { nonce, code, data, - META, + meta(), ) } @@ -139,6 +146,10 @@ export default class PactApi { return this._post('/send', sendRequest) } + async local(sendRequest: ILocalRequest): Promise { + return this._post('/local', sendRequest) + } + async listen(listenRequest: IListenRequest): Promise { return this._post('/listen', listenRequest) } @@ -158,4 +169,36 @@ export default class PactApi { } return result.data! } + + /** + * Local eval for read-only operations. + */ + async evalLocal(options: ISendOptions): Promise<{}> { + const nonce = options.nonce || generateNonce() + const code: string = (options.codeFile ? await loadFile(options.codeFile) : options.code) || '' + const data: {} = (options.dataFile ? JSON.parse(await loadFile(options.dataFile)) : options.data) || {} + const keyPair = { + publicKey: options.keyPair.publicKey.toString('hex'), + secretKey: options.keyPair.privateKey.toString('hex'), + } + if (!keyPair.publicKey) { + throw new Error('Public key is empty.') + } else if (!keyPair.secretKey) { + throw new Error('Private key is empty.') + } + const localRequest = pact.simple.exec.createLocalCommand( + keyPair, + nonce, + code, + data, + meta(), + ) + const { result } = await this.local(localRequest) + if (result.status === 'failure') { + throw new Error(`Pact eval failed with error: ${result.error!.message} - ${result.error!.info}`) + } else if (result.status !== 'success') { + throw new Error(`Pact eval failed with unknown status: '${result.status}'`) + } + return result.data! + } } diff --git a/src/scripts/pactRepl.ts b/src/scripts/pactRepl.ts index 3a3e1bb..79ce49a 100644 --- a/src/scripts/pactRepl.ts +++ b/src/scripts/pactRepl.ts @@ -8,6 +8,8 @@ import PactApi from '../pactApi' import * as pactUtils from '../pactUtils' import * as config from './config' +const LOCAL_MODE = '--local' in process.argv + async function prompt(message: string): Promise { const reader = readline.createInterface({ input: process.stdin, @@ -23,11 +25,12 @@ async function prompt(message: string): Promise { async function main(): Promise { const pactApi = new PactApi(config.getUrl()) + const evalFn = (LOCAL_MODE ? pactApi.eval : pactApi.evalLocal).bind(pactApi) const adminKeyPair = config.getAdminKeyPair() while (true) { const line = await prompt('> ') - await pactApi.eval({ + await evalFn({ code: line, keyPair: adminKeyPair, data: pactUtils.keysetData(adminKeyPair.publicKey, 'my-keyset'), diff --git a/src/scripts/runFile.ts b/src/scripts/runFile.ts index ab4583c..ee3ab6b 100644 --- a/src/scripts/runFile.ts +++ b/src/scripts/runFile.ts @@ -9,10 +9,12 @@ import PactApi from '../pactApi' import * as config from './config' +const LOCAL_MODE = '--local' in process.argv + const args = process.argv.slice(2); -if (args.length !== 1) { - console.error('Usage: node runFile.js my-pact-script.pact') +if (args.length < 1 || args.length > 2) { + console.error('Usage: node runFile.js my-pact-script.pact [--local]') process.exit(1) } @@ -20,7 +22,8 @@ const [codeFile] = args const adminKeyPair = config.getAdminKeyPair() const pactApi = new PactApi(config.getUrl()) -pactApi.eval({ +const evalFn = (LOCAL_MODE ? pactApi.eval : pactApi.evalLocal).bind(pactApi) +evalFn({ codeFile, keyPair: adminKeyPair, }).then(console.log).catch(console.error) diff --git a/src/typings.d.ts b/src/typings.d.ts index 1fd2d23..bd98318 100644 --- a/src/typings.d.ts +++ b/src/typings.d.ts @@ -4,12 +4,14 @@ declare module 'pact-lang-api' { secretKey: string, } + interface LocalRequest { + hash: string + sigs: {}[] + cmd: string + } + interface SendRequest { - cmds: { - hash: string - sigs: {}[] - cmd: string - }[] + cmds: LocalRequest[] } var crypto: { @@ -19,6 +21,7 @@ declare module 'pact-lang-api' { var simple: { exec: { createCommand: (keyPair: KeyPair, nonce: string, code: string, data: {}, meta: {}) => SendRequest + createLocalCommand: (keyPair: KeyPair, nonce: string, code: string, data: {}, meta: {}) => LocalRequest createListenRequest: (sendRequest: SendRequest) => { requestKey: string } } } diff --git a/yarn.lock b/yarn.lock index 0efcc58..5e9f49a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -122,6 +122,13 @@ blakejs@^1.0.1: resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.0.tgz#69df92ef953aa88ca51a32df6ab1c54a155fc7a5" integrity sha1-ad+S75U6qIylGjLfarHFShVfx6U= +blue-tape@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/blue-tape/-/blue-tape-1.0.0.tgz#7581d04c07395c95c426b2ed6d1edb454a76b92b" + integrity sha1-dYHQTAc5XJXEJrLtbR7bRUp2uSs= + dependencies: + tape ">=2.0.0 <5.0.0" + bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" @@ -420,7 +427,19 @@ debug@=3.1.0: dependencies: ms "2.0.0" -defined@^1.0.0: +deep-equal@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +defined@^1.0.0, defined@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= @@ -486,6 +505,31 @@ elliptic@^6.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.0" +es-abstract@^1.5.0: + version "1.16.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.0.tgz#d3a26dc9c3283ac9750dca569586e976d9dcc06d" + integrity sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg== + dependencies: + es-to-primitive "^1.2.0" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.0" + is-callable "^1.1.4" + is-regex "^1.0.4" + object-inspect "^1.6.0" + object-keys "^1.1.1" + string.prototype.trimleft "^2.1.0" + string.prototype.trimright "^2.1.0" + +es-to-primitive@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" + integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + events@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/events/-/events-2.1.0.tgz#2a9a1e18e6106e0e812aa9ebd4a819b3c29c0ba5" @@ -506,12 +550,19 @@ follow-redirects@1.5.10: dependencies: debug "=3.1.0" +for-each@~0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -function-bind@^1.1.1: +function-bind@^1.0.2, function-bind@^1.1.1, function-bind@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== @@ -533,7 +584,24 @@ glob@^7.1.0, glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -has@^1.0.0: +glob@~7.1.4: + version "7.1.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.5.tgz#6714c69bee20f3c3e64c4dd905553e532b40cdc0" + integrity sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= + +has@^1.0.0, has@^1.0.1, has@^1.0.3, has@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== @@ -598,6 +666,11 @@ inherits@2.0.1: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= +inherits@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + inline-source-map@~0.6.0: version "0.6.2" resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5" @@ -631,6 +704,30 @@ is-buffer@^2.0.2: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw== +is-callable@^1.1.3, is-callable@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= + dependencies: + has "^1.0.1" + +is-symbol@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" + integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== + dependencies: + has-symbols "^1.0.0" + isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -710,7 +807,7 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@^1.1.0, minimist@^1.1.1: +minimist@^1.1.0, minimist@^1.1.1, minimist@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= @@ -748,11 +845,26 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= +node-fetch@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" + integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== + object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= +object-inspect@^1.6.0, object-inspect@~1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" + integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== + +object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -765,13 +877,16 @@ os-browserify@~0.3.0: resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= -"pact-lang-api@https://github.com/kadena-io/pact-lang-api.git#c63892c": - version "3.0.0" - resolved "https://github.com/kadena-io/pact-lang-api.git#c63892c40a19ce732cf823c17eebf5d1b2f643ba" +"pact-lang-api@https://github.com/kadena-io/pact-lang-api.git#0ecc7f9": + version "3.2.0" + resolved "https://github.com/kadena-io/pact-lang-api.git#0ecc7f9131d2bbb9488c76996f70c306cb1a1c67" dependencies: base64-url "^2.2.1" blakejs "^1.0.1" + blue-tape "^1.0.0" browserify "^16.2.3" + node-fetch "^2.6.0" + tape "^4.11.0" tweetnacl "^0.14.5" pako@~1.0.5: @@ -911,13 +1026,20 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.1.4, resolve@^1.4.0: +resolve@^1.1.4, resolve@^1.4.0, resolve@~1.11.1: version "1.11.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== dependencies: path-parse "^1.0.6" +resumer@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" + integrity sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k= + dependencies: + through "~2.3.4" + rimraf@^2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" @@ -1009,6 +1131,31 @@ stream-splicer@^2.0.0: inherits "^2.0.1" readable-stream "^2.0.2" +string.prototype.trim@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea" + integrity sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo= + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.0" + function-bind "^1.0.2" + +string.prototype.trimleft@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" + integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + +string.prototype.trimright@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" + integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + string_decoder@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" @@ -1037,6 +1184,25 @@ syntax-error@^1.1.1: dependencies: acorn-node "^1.2.0" +"tape@>=2.0.0 <5.0.0", tape@^4.11.0: + version "4.11.0" + resolved "https://registry.yarnpkg.com/tape/-/tape-4.11.0.tgz#63d41accd95e45a23a874473051c57fdbc58edc1" + integrity sha512-yixvDMX7q7JIs/omJSzSZrqulOV51EC9dK8dM0TzImTIkHWfe2/kFyL5v+d9C+SrCMaICk59ujsqFAVidDqDaA== + dependencies: + deep-equal "~1.0.1" + defined "~1.0.0" + for-each "~0.3.3" + function-bind "~1.1.1" + glob "~7.1.4" + has "~1.0.3" + inherits "~2.0.4" + minimist "~1.2.0" + object-inspect "~1.6.0" + resolve "~1.11.1" + resumer "~0.0.0" + string.prototype.trim "~1.1.2" + through "~2.3.8" + through2@^2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" @@ -1045,7 +1211,7 @@ through2@^2.0.0: readable-stream "~2.3.6" xtend "~4.0.1" -"through@>=2.2.7 <3": +"through@>=2.2.7 <3", through@~2.3.4, through@~2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=