@@ -40,6 +40,7 @@ const _istream = Symbol('_istream')
4040const _assertType = Symbol ( '_assertType' )
4141const _tarballFromCache = Symbol ( '_tarballFromCache' )
4242const _tarballFromResolved = Symbol . for ( 'pacote.Fetcher._tarballFromResolved' )
43+ const _cacheFetches = Symbol . for ( 'pacote.Fetcher._cacheFetches' )
4344
4445class FetcherBase {
4546 constructor ( spec , opts ) {
@@ -166,8 +167,8 @@ class FetcherBase {
166167 }
167168
168169 // private, should be overridden.
169- // Note that they should *not* calculate or check integrity, but *just*
170- // return the raw tarball data stream.
170+ // Note that they should *not* calculate or check integrity or cache,
171+ // but *just* return the raw tarball data stream.
171172 [ _tarballFromResolved ] ( ) {
172173 throw this . notImplementedError
173174 }
@@ -194,6 +195,10 @@ class FetcherBase {
194195 return cacache . get . stream . byDigest ( this . cache , this . integrity , this . opts )
195196 }
196197
198+ get [ _cacheFetches ] ( ) {
199+ return true
200+ }
201+
197202 [ _istream ] ( stream ) {
198203 // everyone will need one of these, either for verifying or calculating
199204 // We always set it, because we have might only have a weak legacy hex
@@ -203,7 +208,27 @@ class FetcherBase {
203208 // gets to the point of re-setting the integrity.
204209 const istream = ssri . integrityStream ( this . opts )
205210 istream . on ( 'integrity' , i => this . integrity = i )
206- return stream . on ( 'error' , er => istream . emit ( 'error' , er ) ) . pipe ( istream )
211+ // we have to return a stream that gets ALL the data, and proxies errors,
212+ // but then pipe from the original tarball stream into the cache as well.
213+ // To do this without losing any data, and since the cacache put stream
214+ // is not a passthrough, we have to pipe from the original stream into
215+ // the cache AFTER we pipe into the istream.
216+ // If the cacache put stream was a passthrough, we could just return
217+ // a single pipeline with all three, but that would make cacache put
218+ // streams less useful, because they'd have to be read from to work.
219+ stream . on ( 'error' , er => istream . emit ( 'error' , er ) )
220+ stream . pipe ( istream )
221+ if ( this . opts . cache && this [ _cacheFetches ] ) {
222+ const cstream = cacache . put . stream (
223+ this . opts . cache ,
224+ `pacote:tarball:${ this . from } ` ,
225+ this . opts
226+ )
227+ // best-effort. cache write errors should not crash the fetch.
228+ cstream . on ( 'error' , ( er ) => { } )
229+ stream . pipe ( cstream )
230+ }
231+ return istream
207232 }
208233
209234 pickIntegrityAlgorithm ( ) {
@@ -232,7 +257,9 @@ class FetcherBase {
232257 // An ENOENT trying to read a tgz file, for example, is Right Out.
233258 isRetriableError ( er ) {
234259 // TODO: check error class, once those are rolled out to our deps
235- return this . isDataCorruptionError ( er ) || er . code === 'ENOENT'
260+ return this . isDataCorruptionError ( er ) ||
261+ er . code === 'ENOENT' ||
262+ er . code === 'EISDIR'
236263 }
237264
238265 // Mostly internal, but has some uses
0 commit comments