pnpm 7.9.1 → 7.9.2

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.
Files changed (108) hide show
  1. package/README.md +22 -7
  2. package/bin/pnpm.cjs +3 -0
  3. package/bin/pnpx.cjs +1 -15
  4. package/dist/node_modules/.modules.yaml +3 -3
  5. package/dist/node_modules/.pnpm/lock.yaml +76 -42
  6. package/dist/node_modules/@npmcli/fs/lib/common/owner-sync.js +96 -0
  7. package/dist/node_modules/@npmcli/fs/lib/common/owner.js +8 -4
  8. package/dist/node_modules/@npmcli/fs/lib/copy-file.js +3 -9
  9. package/dist/node_modules/@npmcli/fs/lib/fs.js +9 -3
  10. package/dist/node_modules/@npmcli/fs/lib/index.js +3 -1
  11. package/dist/node_modules/@npmcli/fs/lib/mkdir.js +19 -0
  12. package/dist/node_modules/@npmcli/fs/lib/mkdtemp.js +3 -8
  13. package/dist/node_modules/@npmcli/fs/lib/with-owner-sync.js +21 -0
  14. package/dist/node_modules/@npmcli/fs/lib/with-owner.js +21 -0
  15. package/dist/node_modules/@npmcli/fs/lib/with-temp-dir.js +4 -2
  16. package/dist/node_modules/@npmcli/fs/lib/write-file.js +3 -8
  17. package/dist/node_modules/@npmcli/fs/package.json +21 -9
  18. package/dist/node_modules/@npmcli/move-file/{index.js → lib/index.js} +50 -27
  19. package/dist/node_modules/@npmcli/move-file/package.json +20 -7
  20. package/dist/node_modules/@tootallnate/once/LICENSE +21 -0
  21. package/dist/node_modules/@tootallnate/once/dist/index.js +21 -36
  22. package/dist/node_modules/@tootallnate/once/dist/index.js.map +1 -1
  23. package/dist/node_modules/@tootallnate/once/dist/overloaded-parameters.js +3 -0
  24. package/dist/node_modules/@tootallnate/once/dist/overloaded-parameters.js.map +1 -0
  25. package/dist/node_modules/@tootallnate/once/dist/types.js +3 -0
  26. package/dist/node_modules/@tootallnate/once/dist/types.js.map +1 -0
  27. package/dist/node_modules/@tootallnate/once/package.json +22 -15
  28. package/dist/node_modules/cacache/lib/content/read.js +99 -102
  29. package/dist/node_modules/cacache/lib/content/rm.js +9 -8
  30. package/dist/node_modules/cacache/lib/content/write.js +67 -67
  31. package/dist/node_modules/cacache/lib/entry-index.js +128 -118
  32. package/dist/node_modules/cacache/{get.js → lib/get.js} +88 -100
  33. package/dist/node_modules/cacache/{index.js → lib/index.js} +5 -6
  34. package/dist/node_modules/cacache/lib/memoization.js +10 -11
  35. package/dist/node_modules/cacache/{put.js → lib/put.js} +23 -26
  36. package/dist/node_modules/cacache/{rm.js → lib/rm.js} +3 -3
  37. package/dist/node_modules/cacache/lib/util/fix-owner.js +41 -38
  38. package/dist/node_modules/cacache/lib/util/move-file.js +36 -47
  39. package/dist/node_modules/cacache/lib/util/tmp.js +5 -7
  40. package/dist/node_modules/cacache/lib/verify.js +160 -190
  41. package/dist/node_modules/cacache/node_modules/brace-expansion/.github/FUNDING.yml +2 -0
  42. package/dist/node_modules/cacache/node_modules/brace-expansion/LICENSE +21 -0
  43. package/dist/node_modules/cacache/node_modules/brace-expansion/index.js +203 -0
  44. package/dist/node_modules/cacache/node_modules/brace-expansion/package.json +46 -0
  45. package/dist/node_modules/cacache/node_modules/glob/LICENSE +15 -0
  46. package/dist/node_modules/cacache/node_modules/glob/common.js +240 -0
  47. package/dist/node_modules/cacache/node_modules/glob/glob.js +790 -0
  48. package/dist/node_modules/cacache/node_modules/glob/package.json +55 -0
  49. package/dist/node_modules/cacache/node_modules/glob/sync.js +486 -0
  50. package/dist/node_modules/cacache/node_modules/minimatch/LICENSE +15 -0
  51. package/dist/node_modules/cacache/node_modules/minimatch/lib/path.js +4 -0
  52. package/dist/node_modules/cacache/node_modules/minimatch/minimatch.js +906 -0
  53. package/dist/node_modules/cacache/node_modules/minimatch/package.json +32 -0
  54. package/dist/node_modules/cacache/package.json +34 -30
  55. package/dist/node_modules/http-proxy-agent/dist/agent.js +3 -3
  56. package/dist/node_modules/http-proxy-agent/dist/agent.js.map +1 -1
  57. package/dist/node_modules/http-proxy-agent/package.json +4 -4
  58. package/dist/node_modules/lru-cache/LICENSE +1 -1
  59. package/dist/node_modules/lru-cache/index.js +921 -247
  60. package/dist/node_modules/lru-cache/package.json +49 -9
  61. package/dist/node_modules/make-fetch-happen/LICENSE +1 -1
  62. package/dist/node_modules/make-fetch-happen/lib/agent.js +34 -14
  63. package/dist/node_modules/make-fetch-happen/lib/cache/entry.js +90 -106
  64. package/dist/node_modules/make-fetch-happen/lib/cache/errors.js +1 -0
  65. package/dist/node_modules/make-fetch-happen/lib/cache/index.js +10 -6
  66. package/dist/node_modules/make-fetch-happen/lib/cache/policy.js +21 -21
  67. package/dist/node_modules/make-fetch-happen/lib/dns.js +49 -0
  68. package/dist/node_modules/make-fetch-happen/lib/fetch.js +40 -22
  69. package/dist/node_modules/make-fetch-happen/lib/index.js +4 -3
  70. package/dist/node_modules/make-fetch-happen/lib/options.js +17 -9
  71. package/dist/node_modules/make-fetch-happen/lib/pipeline.js +41 -0
  72. package/dist/node_modules/make-fetch-happen/lib/remote.js +28 -9
  73. package/dist/node_modules/make-fetch-happen/package.json +36 -33
  74. package/dist/node_modules/minipass-fetch/lib/blob.js +4 -4
  75. package/dist/node_modules/minipass-fetch/lib/body.js +63 -49
  76. package/dist/node_modules/minipass-fetch/lib/fetch-error.js +2 -1
  77. package/dist/node_modules/minipass-fetch/lib/headers.js +38 -21
  78. package/dist/node_modules/minipass-fetch/lib/index.js +130 -106
  79. package/dist/node_modules/minipass-fetch/lib/request.js +46 -28
  80. package/dist/node_modules/minipass-fetch/lib/response.js +3 -2
  81. package/dist/node_modules/minipass-fetch/package.json +27 -14
  82. package/dist/node_modules/node-gyp/.github/workflows/release-please.yml +1 -1
  83. package/dist/node_modules/node-gyp/.github/workflows/tests.yml +16 -9
  84. package/dist/node_modules/node-gyp/.github/workflows/visual-studio.yml +16 -8
  85. package/dist/node_modules/node-gyp/lib/build.js +7 -0
  86. package/dist/node_modules/node-gyp/lib/configure.js +26 -1
  87. package/dist/node_modules/node-gyp/lib/create-config-gypi.js +2 -1
  88. package/dist/node_modules/node-gyp/lib/find-visualstudio.js +9 -8
  89. package/dist/node_modules/node-gyp/lib/node-gyp.js +4 -0
  90. package/dist/node_modules/node-gyp/package.json +4 -4
  91. package/dist/node_modules/semver/node_modules/lru-cache/LICENSE +15 -0
  92. package/dist/node_modules/semver/node_modules/lru-cache/index.js +334 -0
  93. package/dist/node_modules/semver/node_modules/lru-cache/package.json +34 -0
  94. package/dist/node_modules/socks-proxy-agent/dist/index.js +3 -3
  95. package/dist/node_modules/socks-proxy-agent/dist/index.js.map +1 -1
  96. package/dist/node_modules/socks-proxy-agent/package.json +2 -2
  97. package/dist/node_modules/ssri/{index.js → lib/index.js} +78 -24
  98. package/dist/node_modules/ssri/package.json +27 -16
  99. package/dist/pnpm.cjs +67042 -65886
  100. package/package.json +6 -6
  101. package/dist/node_modules/@npmcli/fs/lib/common/file-url-to-path/index.js +0 -17
  102. package/dist/node_modules/@npmcli/fs/lib/common/file-url-to-path/polyfill.js +0 -121
  103. package/dist/node_modules/@npmcli/fs/lib/mkdir/index.js +0 -32
  104. package/dist/node_modules/@npmcli/fs/lib/mkdir/polyfill.js +0 -81
  105. package/dist/node_modules/cacache/lib/util/disposer.js +0 -30
  106. package/dist/node_modules/cacache/ls.js +0 -6
  107. package/dist/node_modules/cacache/verify.js +0 -3
  108. package/dist/node_modules/minipass-fetch/index.js +0 -1
@@ -1,34 +1,74 @@
1
1
  {
2
2
  "name": "lru-cache",
3
3
  "description": "A cache object that deletes the least-recently-used items.",
4
- "version": "6.0.0",
4
+ "version": "7.14.0",
5
5
  "author": "Isaac Z. Schlueter <i@izs.me>",
6
6
  "keywords": [
7
7
  "mru",
8
8
  "lru",
9
9
  "cache"
10
10
  ],
11
+ "sideEffects": false,
11
12
  "scripts": {
13
+ "build": "",
14
+ "size": "size-limit",
12
15
  "test": "tap",
13
16
  "snap": "tap",
14
17
  "preversion": "npm test",
15
18
  "postversion": "npm publish",
16
- "prepublishOnly": "git push origin --follow-tags"
19
+ "prepublishOnly": "git push origin --follow-tags",
20
+ "format": "prettier --write ."
17
21
  },
18
22
  "main": "index.js",
19
23
  "repository": "git://github.com/isaacs/node-lru-cache.git",
20
24
  "devDependencies": {
25
+ "@size-limit/preset-small-lib": "^7.0.8",
26
+ "@types/node": "^17.0.31",
27
+ "@types/tap": "^15.0.6",
21
28
  "benchmark": "^2.1.4",
22
- "tap": "^14.10.7"
29
+ "c8": "^7.11.2",
30
+ "clock-mock": "^1.0.6",
31
+ "eslint-config-prettier": "^8.5.0",
32
+ "prettier": "^2.6.2",
33
+ "size-limit": "^7.0.8",
34
+ "tap": "^16.0.1",
35
+ "ts-node": "^10.7.0",
36
+ "tslib": "^2.4.0",
37
+ "typescript": "^4.6.4"
23
38
  },
24
39
  "license": "ISC",
25
- "dependencies": {
26
- "yallist": "^4.0.0"
27
- },
28
40
  "files": [
29
- "index.js"
41
+ "index.js",
42
+ "index.d.ts"
30
43
  ],
31
44
  "engines": {
32
- "node": ">=10"
33
- }
45
+ "node": ">=12"
46
+ },
47
+ "prettier": {
48
+ "semi": false,
49
+ "printWidth": 70,
50
+ "tabWidth": 2,
51
+ "useTabs": false,
52
+ "singleQuote": true,
53
+ "jsxSingleQuote": false,
54
+ "bracketSameLine": true,
55
+ "arrowParens": "avoid",
56
+ "endOfLine": "lf"
57
+ },
58
+ "tap": {
59
+ "nyc-arg": [
60
+ "--include=index.js"
61
+ ],
62
+ "node-arg": [
63
+ "--expose-gc",
64
+ "--require",
65
+ "ts-node/register"
66
+ ],
67
+ "ts": false
68
+ },
69
+ "size-limit": [
70
+ {
71
+ "path": "./index.js"
72
+ }
73
+ ]
34
74
  }
@@ -1,6 +1,6 @@
1
1
  ISC License
2
2
 
3
- Copyright (c) npm, Inc.
3
+ Copyright 2017-2022 (c) npm, Inc.
4
4
 
5
5
  Permission to use, copy, modify, and/or distribute this software for
6
6
  any purpose with or without fee is hereby granted, provided that the
@@ -2,6 +2,7 @@
2
2
  const LRU = require('lru-cache')
3
3
  const url = require('url')
4
4
  const isLambda = require('is-lambda')
5
+ const dns = require('./dns.js')
5
6
 
6
7
  const AGENT_CACHE = new LRU({ max: 50 })
7
8
  const HttpAgent = require('agentkeepalive')
@@ -50,11 +51,13 @@ function getAgent (uri, opts) {
50
51
  : isHttps ? require('https').globalAgent
51
52
  : require('http').globalAgent
52
53
 
53
- if (isLambda && !pxuri)
54
+ if (isLambda && !pxuri) {
54
55
  return lambdaAgent
56
+ }
55
57
 
56
- if (AGENT_CACHE.peek(key))
58
+ if (AGENT_CACHE.peek(key)) {
57
59
  return AGENT_CACHE.get(key)
60
+ }
58
61
 
59
62
  if (pxuri) {
60
63
  const pxopts = isLambda ? {
@@ -74,10 +77,14 @@ function getAgent (uri, opts) {
74
77
  localAddress: opts.localAddress,
75
78
  rejectUnauthorized: opts.rejectUnauthorized,
76
79
  timeout: agentTimeout,
80
+ freeSocketTimeout: 15000,
81
+ lookup: dns.getLookup(opts.dns),
77
82
  }) : new HttpAgent({
78
83
  maxSockets: agentMaxSockets,
79
84
  localAddress: opts.localAddress,
80
85
  timeout: agentTimeout,
86
+ freeSocketTimeout: 15000,
87
+ lookup: dns.getLookup(opts.dns),
81
88
  })
82
89
  AGENT_CACHE.set(key, agent)
83
90
  return agent
@@ -86,16 +93,19 @@ function getAgent (uri, opts) {
86
93
  function checkNoProxy (uri, opts) {
87
94
  const host = new url.URL(uri).hostname.split('.').reverse()
88
95
  let noproxy = (opts.noProxy || getProcessEnv('no_proxy'))
89
- if (typeof noproxy === 'string')
90
- noproxy = noproxy.split(/\s*,\s*/g)
96
+ if (typeof noproxy === 'string') {
97
+ noproxy = noproxy.split(',').map(n => n.trim())
98
+ }
91
99
 
92
100
  return noproxy && noproxy.some(no => {
93
101
  const noParts = no.split('.').filter(x => x).reverse()
94
- if (!noParts.length)
102
+ if (!noParts.length) {
95
103
  return false
104
+ }
96
105
  for (let i = 0; i < noParts.length; i++) {
97
- if (host[i] !== noParts[i])
106
+ if (host[i] !== noParts[i]) {
98
107
  return false
108
+ }
99
109
  }
100
110
  return true
101
111
  })
@@ -104,8 +114,9 @@ function checkNoProxy (uri, opts) {
104
114
  module.exports.getProcessEnv = getProcessEnv
105
115
 
106
116
  function getProcessEnv (env) {
107
- if (!env)
117
+ if (!env) {
108
118
  return
119
+ }
109
120
 
110
121
  let value
111
122
 
@@ -114,8 +125,9 @@ function getProcessEnv (env) {
114
125
  value = process.env[e] ||
115
126
  process.env[e.toUpperCase()] ||
116
127
  process.env[e.toLowerCase()]
117
- if (typeof value !== 'undefined')
128
+ if (typeof value !== 'undefined') {
118
129
  break
130
+ }
119
131
  }
120
132
  }
121
133
 
@@ -141,8 +153,9 @@ function getProxyUri (uri, opts) {
141
153
  protocol === 'http:' &&
142
154
  getProcessEnv(['https_proxy', 'http_proxy', 'proxy'])
143
155
  )
144
- if (!proxy)
156
+ if (!proxy) {
145
157
  return null
158
+ }
146
159
 
147
160
  const parsedProxy = (typeof proxy === 'string') ? new url.URL(proxy) : proxy
148
161
 
@@ -158,9 +171,11 @@ const getPath = u => u.pathname + u.search + u.hash
158
171
 
159
172
  const HttpProxyAgent = require('http-proxy-agent')
160
173
  const HttpsProxyAgent = require('https-proxy-agent')
161
- const SocksProxyAgent = require('socks-proxy-agent')
174
+ const { SocksProxyAgent } = require('socks-proxy-agent')
162
175
  module.exports.getProxy = getProxy
163
176
  function getProxy (proxyUrl, opts, isHttps) {
177
+ // our current proxy agents do not support an overridden dns lookup method, so will not
178
+ // benefit from the dns cache
164
179
  const popts = {
165
180
  host: proxyUrl.hostname,
166
181
  port: proxyUrl.port,
@@ -177,16 +192,21 @@ function getProxy (proxyUrl, opts, isHttps) {
177
192
  }
178
193
 
179
194
  if (proxyUrl.protocol === 'http:' || proxyUrl.protocol === 'https:') {
180
- if (!isHttps)
195
+ if (!isHttps) {
181
196
  return new HttpProxyAgent(popts)
182
- else
197
+ } else {
183
198
  return new HttpsProxyAgent(popts)
184
- } else if (proxyUrl.protocol.startsWith('socks'))
199
+ }
200
+ } else if (proxyUrl.protocol.startsWith('socks')) {
201
+ // socks-proxy-agent uses hostname not host
202
+ popts.hostname = popts.host
203
+ delete popts.host
185
204
  return new SocksProxyAgent(popts)
186
- else {
205
+ } else {
187
206
  throw Object.assign(
188
207
  new Error(`unsupported proxy protocol: '${proxyUrl.protocol}'`),
189
208
  {
209
+ code: 'EUNSUPPORTEDPROXY',
190
210
  url: proxyUrl.href,
191
211
  }
192
212
  )
@@ -1,21 +1,16 @@
1
1
  const { Request, Response } = require('minipass-fetch')
2
2
  const Minipass = require('minipass')
3
- const MinipassCollect = require('minipass-collect')
4
3
  const MinipassFlush = require('minipass-flush')
5
- const MinipassPipeline = require('minipass-pipeline')
6
4
  const cacache = require('cacache')
7
5
  const url = require('url')
8
6
 
7
+ const CachingMinipassPipeline = require('../pipeline.js')
9
8
  const CachePolicy = require('./policy.js')
10
9
  const cacheKey = require('./key.js')
11
10
  const remote = require('../remote.js')
12
11
 
13
12
  const hasOwnProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
14
13
 
15
- // maximum amount of data we will buffer into memory
16
- // if we'll exceed this, we switch to streaming
17
- const MAX_MEM_SIZE = 5 * 1024 * 1024 // 5MB
18
-
19
14
  // allow list for request headers that will be written to the cache index
20
15
  // note: we will also store any request headers
21
16
  // that are named in a response's vary header
@@ -40,6 +35,7 @@ const KEEP_RESPONSE_HEADERS = [
40
35
  'etag',
41
36
  'expires',
42
37
  'last-modified',
38
+ 'link',
43
39
  'location',
44
40
  'pragma',
45
41
  'vary',
@@ -52,23 +48,31 @@ const getMetadata = (request, response, options) => {
52
48
  url: request.url,
53
49
  reqHeaders: {},
54
50
  resHeaders: {},
51
+
52
+ // options on which we must match the request and vary the response
53
+ options: {
54
+ compress: options.compress != null ? options.compress : request.compress,
55
+ },
55
56
  }
56
57
 
57
58
  // only save the status if it's not a 200 or 304
58
- if (response.status !== 200 && response.status !== 304)
59
+ if (response.status !== 200 && response.status !== 304) {
59
60
  metadata.status = response.status
61
+ }
60
62
 
61
63
  for (const name of KEEP_REQUEST_HEADERS) {
62
- if (request.headers.has(name))
64
+ if (request.headers.has(name)) {
63
65
  metadata.reqHeaders[name] = request.headers.get(name)
66
+ }
64
67
  }
65
68
 
66
69
  // if the request's host header differs from the host in the url
67
70
  // we need to keep it, otherwise it's just noise and we ignore it
68
71
  const host = request.headers.get('host')
69
72
  const parsedUrl = new url.URL(request.url)
70
- if (host && parsedUrl.host !== host)
73
+ if (host && parsedUrl.host !== host) {
71
74
  metadata.reqHeaders.host = host
75
+ }
72
76
 
73
77
  // if the response has a vary header, make sure
74
78
  // we store the relevant request headers too
@@ -82,25 +86,17 @@ const getMetadata = (request, response, options) => {
82
86
  // copy any other request headers that will vary the response
83
87
  const varyHeaders = vary.trim().toLowerCase().split(/\s*,\s*/)
84
88
  for (const name of varyHeaders) {
85
- // explicitly ignore accept-encoding here
86
- if (name !== 'accept-encoding' && request.headers.has(name))
89
+ if (request.headers.has(name)) {
87
90
  metadata.reqHeaders[name] = request.headers.get(name)
91
+ }
88
92
  }
89
93
  }
90
94
  }
91
95
 
92
96
  for (const name of KEEP_RESPONSE_HEADERS) {
93
- if (response.headers.has(name))
97
+ if (response.headers.has(name)) {
94
98
  metadata.resHeaders[name] = response.headers.get(name)
95
- }
96
-
97
- // we only store accept-encoding and content-encoding if the user
98
- // has disabled automatic compression and decompression in minipass-fetch
99
- // since if it's enabled (the default) then the content will have
100
- // already been decompressed making the header a lie
101
- if (options.compress === false) {
102
- metadata.reqHeaders['accept-encoding'] = request.headers.get('accept-encoding')
103
- metadata.resHeaders['content-encoding'] = response.headers.get('content-encoding')
99
+ }
104
100
  }
105
101
 
106
102
  return metadata
@@ -121,8 +117,9 @@ class CacheEntry {
121
117
  // entry timestamp to determine staleness because cacache will update it
122
118
  // when it verifies its data
123
119
  this.entry.metadata.time = this.entry.metadata.time || this.entry.time
124
- } else
120
+ } else {
125
121
  this.key = cacheKey(request)
122
+ }
126
123
 
127
124
  this.options = options
128
125
 
@@ -143,9 +140,17 @@ class CacheEntry {
143
140
  return entryA.policy.satisfies(entryB.request)
144
141
  }, {
145
142
  validateEntry: (entry) => {
143
+ // clean out entries with a buggy content-encoding value
144
+ if (entry.metadata &&
145
+ entry.metadata.resHeaders &&
146
+ entry.metadata.resHeaders['content-encoding'] === null) {
147
+ return false
148
+ }
149
+
146
150
  // if an integrity is null, it needs to have a status specified
147
- if (entry.integrity === null)
151
+ if (entry.integrity === null) {
148
152
  return !!(entry.metadata && entry.metadata.status)
153
+ }
149
154
 
150
155
  return true
151
156
  },
@@ -158,8 +163,9 @@ class CacheEntry {
158
163
  // a cache mode of 'reload' means to behave as though we have no cache
159
164
  // on the way to the network. return undefined to allow cacheFetch to
160
165
  // create a brand new request no matter what.
161
- if (options.cache === 'reload')
166
+ if (options.cache === 'reload') {
162
167
  return
168
+ }
163
169
 
164
170
  // find the specific entry that satisfies the request
165
171
  let match
@@ -194,6 +200,7 @@ class CacheEntry {
194
200
  this[_request] = new Request(this.entry.metadata.url, {
195
201
  method: 'GET',
196
202
  headers: this.entry.metadata.reqHeaders,
203
+ ...this.entry.metadata.options,
197
204
  })
198
205
  }
199
206
 
@@ -235,19 +242,22 @@ class CacheEntry {
235
242
  // if we got a status other than 200, 301, or 308,
236
243
  // or the CachePolicy forbid storage, append the
237
244
  // cache status header and return it untouched
238
- if (this.request.method !== 'GET' || ![200, 301, 308].includes(this.response.status) || !this.policy.storable()) {
245
+ if (
246
+ this.request.method !== 'GET' ||
247
+ ![200, 301, 308].includes(this.response.status) ||
248
+ !this.policy.storable()
249
+ ) {
239
250
  this.response.headers.set('x-local-cache-status', 'skip')
240
251
  return this.response
241
252
  }
242
253
 
243
254
  const size = this.response.headers.get('content-length')
244
- const fitsInMemory = !!size && Number(size) < MAX_MEM_SIZE
245
- const shouldBuffer = this.options.memoize !== false && fitsInMemory
246
255
  const cacheOpts = {
247
256
  algorithms: this.options.algorithms,
248
257
  metadata: getMetadata(this.request, this.response, this.options),
249
258
  size,
250
- memoize: fitsInMemory && this.options.memoize,
259
+ integrity: this.options.integrity,
260
+ integrityEmitter: this.response.body.hasIntegrityEmitter && this.response.body,
251
261
  }
252
262
 
253
263
  let body = null
@@ -260,53 +270,35 @@ class CacheEntry {
260
270
  cacheWriteReject = reject
261
271
  })
262
272
 
263
- body = new MinipassPipeline(new MinipassFlush({
273
+ body = new CachingMinipassPipeline({ events: ['integrity', 'size'] }, new MinipassFlush({
264
274
  flush () {
265
275
  return cacheWritePromise
266
276
  },
267
277
  }))
268
-
269
- let abortStream, onResume
270
- if (shouldBuffer) {
271
- // if the result fits in memory, use a collect stream to gather
272
- // the response and write it to cacache while also passing it through
273
- // to the user
274
- onResume = () => {
275
- const collector = new MinipassCollect.PassThrough()
276
- abortStream = collector
277
- collector.on('collect', (data) => {
278
- // TODO if the cache write fails, log a warning but return the response anyway
279
- cacache.put(this.options.cachePath, this.key, data, cacheOpts).then(cacheWriteResolve, cacheWriteReject)
280
- })
281
- body.unshift(collector)
282
- body.unshift(this.response.body)
283
- }
284
- } else {
285
- // if it does not fit in memory, create a tee stream and use
286
- // that to pipe to both the cache and the user simultaneously
287
- onResume = () => {
288
- const tee = new Minipass()
289
- const cacheStream = cacache.put.stream(this.options.cachePath, this.key, cacheOpts)
290
- abortStream = cacheStream
291
- tee.pipe(cacheStream)
292
- // TODO if the cache write fails, log a warning but return the response anyway
293
- cacheStream.promise().then(cacheWriteResolve, cacheWriteReject)
294
- body.unshift(tee)
295
- body.unshift(this.response.body)
296
- }
278
+ // this is always true since if we aren't reusing the one from the remote fetch, we
279
+ // are using the one from cacache
280
+ body.hasIntegrityEmitter = true
281
+
282
+ const onResume = () => {
283
+ const tee = new Minipass()
284
+ const cacheStream = cacache.put.stream(this.options.cachePath, this.key, cacheOpts)
285
+ // re-emit the integrity and size events on our new response body so they can be reused
286
+ cacheStream.on('integrity', i => body.emit('integrity', i))
287
+ cacheStream.on('size', s => body.emit('size', s))
288
+ // stick a flag on here so downstream users will know if they can expect integrity events
289
+ tee.pipe(cacheStream)
290
+ // TODO if the cache write fails, log a warning but return the response anyway
291
+ // eslint-disable-next-line promise/catch-or-return
292
+ cacheStream.promise().then(cacheWriteResolve, cacheWriteReject)
293
+ body.unshift(tee)
294
+ body.unshift(this.response.body)
297
295
  }
298
296
 
299
297
  body.once('resume', onResume)
300
298
  body.once('end', () => body.removeListener('resume', onResume))
301
- this.response.body.on('error', (err) => {
302
- // the abortStream will either be a MinipassCollect if we buffer
303
- // or a cacache write stream, either way be sure to listen for
304
- // errors from the actual response and avoid writing data that we
305
- // know to be invalid to the cache
306
- abortStream.destroy(err)
307
- })
308
- } else
299
+ } else {
309
300
  await cacache.index.insert(this.options.cachePath, this.key, null, cacheOpts)
301
+ }
310
302
 
311
303
  // note: we do not set the x-local-cache-hash header because we do not know
312
304
  // the hash value until after the write to the cache completes, which doesn't
@@ -314,7 +306,7 @@ class CacheEntry {
314
306
  // the header anyway
315
307
  this.response.headers.set('x-local-cache', encodeURIComponent(this.options.cachePath))
316
308
  this.response.headers.set('x-local-cache-key', encodeURIComponent(this.key))
317
- this.response.headers.set('x-local-cache-mode', shouldBuffer ? 'buffer' : 'stream')
309
+ this.response.headers.set('x-local-cache-mode', 'stream')
318
310
  this.response.headers.set('x-local-cache-status', status)
319
311
  this.response.headers.set('x-local-cache-time', new Date().toISOString())
320
312
  const newResponse = new Response(body, {
@@ -329,9 +321,6 @@ class CacheEntry {
329
321
  // use the cached data to create a response and return it
330
322
  async respond (method, options, status) {
331
323
  let response
332
- const size = Number(this.response.headers.get('content-length'))
333
- const fitsInMemory = !!size && size < MAX_MEM_SIZE
334
- const shouldBuffer = this.options.memoize !== false && fitsInMemory
335
324
  if (method === 'HEAD' || [301, 308].includes(this.response.status)) {
336
325
  // if the request is a HEAD, or the response is a redirect,
337
326
  // then the metadata in the entry already includes everything
@@ -341,54 +330,44 @@ class CacheEntry {
341
330
  // we're responding with a full cached response, so create a body
342
331
  // that reads from cacache and attach it to a new Response
343
332
  const body = new Minipass()
344
- const removeOnResume = () => body.removeListener('resume', onResume)
345
- let onResume
346
- if (shouldBuffer) {
347
- onResume = async () => {
348
- removeOnResume()
349
- try {
350
- const content = await cacache.get.byDigest(this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize })
351
- body.end(content)
352
- } catch (err) {
353
- if (err.code === 'EINTEGRITY')
354
- await cacache.rm.content(this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize })
355
- if (err.code === 'ENOENT' || err.code === 'EINTEGRITY')
356
- await CacheEntry.invalidate(this.request, this.options)
357
- body.emit('error', err)
333
+ const headers = { ...this.policy.responseHeaders() }
334
+ const onResume = () => {
335
+ const cacheStream = cacache.get.stream.byDigest(
336
+ this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize }
337
+ )
338
+ cacheStream.on('error', async (err) => {
339
+ cacheStream.pause()
340
+ if (err.code === 'EINTEGRITY') {
341
+ await cacache.rm.content(
342
+ this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize }
343
+ )
358
344
  }
359
- }
360
- } else {
361
- onResume = () => {
362
- const cacheStream = cacache.get.stream.byDigest(this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize })
363
- cacheStream.on('error', async (err) => {
364
- cacheStream.pause()
365
- if (err.code === 'EINTEGRITY')
366
- await cacache.rm.content(this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize })
367
- if (err.code === 'ENOENT' || err.code === 'EINTEGRITY')
368
- await CacheEntry.invalidate(this.request, this.options)
369
- body.emit('error', err)
370
- cacheStream.resume()
371
- })
372
- cacheStream.pipe(body)
373
- }
345
+ if (err.code === 'ENOENT' || err.code === 'EINTEGRITY') {
346
+ await CacheEntry.invalidate(this.request, this.options)
347
+ }
348
+ body.emit('error', err)
349
+ cacheStream.resume()
350
+ })
351
+ // emit the integrity and size events based on our metadata so we're consistent
352
+ body.emit('integrity', this.entry.integrity)
353
+ body.emit('size', Number(headers['content-length']))
354
+ cacheStream.pipe(body)
374
355
  }
375
356
 
376
357
  body.once('resume', onResume)
377
- body.once('end', removeOnResume)
358
+ body.once('end', () => body.removeListener('resume', onResume))
378
359
  response = new Response(body, {
379
360
  url: this.entry.metadata.url,
380
361
  counter: options.counter,
381
362
  status: 200,
382
- headers: {
383
- ...this.policy.responseHeaders(),
384
- },
363
+ headers,
385
364
  })
386
365
  }
387
366
 
388
367
  response.headers.set('x-local-cache', encodeURIComponent(this.options.cachePath))
389
368
  response.headers.set('x-local-cache-hash', encodeURIComponent(this.entry.integrity))
390
369
  response.headers.set('x-local-cache-key', encodeURIComponent(this.key))
391
- response.headers.set('x-local-cache-mode', shouldBuffer ? 'buffer' : 'stream')
370
+ response.headers.set('x-local-cache-mode', 'stream')
392
371
  response.headers.set('x-local-cache-status', status)
393
372
  response.headers.set('x-local-cache-time', new Date(this.entry.metadata.time).toUTCString())
394
373
  return response
@@ -415,8 +394,9 @@ class CacheEntry {
415
394
  // if the network fetch fails, return the stale
416
395
  // cached response unless it has a cache-control
417
396
  // of 'must-revalidate'
418
- if (!this.policy.mustRevalidate)
397
+ if (!this.policy.mustRevalidate) {
419
398
  return this.respond(request.method, options, 'stale')
399
+ }
420
400
 
421
401
  throw err
422
402
  }
@@ -429,8 +409,12 @@ class CacheEntry {
429
409
  // in the old cache entry to the new one, if the new metadata does not already
430
410
  // include that header
431
411
  for (const name of KEEP_RESPONSE_HEADERS) {
432
- if (!hasOwnProperty(metadata.resHeaders, name) && hasOwnProperty(this.entry.metadata.resHeaders, name))
412
+ if (
413
+ !hasOwnProperty(metadata.resHeaders, name) &&
414
+ hasOwnProperty(this.entry.metadata.resHeaders, name)
415
+ ) {
433
416
  metadata.resHeaders[name] = this.entry.metadata.resHeaders[name]
417
+ }
434
418
  }
435
419
 
436
420
  try {
@@ -1,5 +1,6 @@
1
1
  class NotCachedError extends Error {
2
2
  constructor (url) {
3
+ /* eslint-disable-next-line max-len */
3
4
  super(`request to ${url} failed: cache mode is 'only-if-cached' but no cached response is available.`)
4
5
  this.code = 'ENOTCACHED'
5
6
  }
@@ -8,19 +8,21 @@ const cacheFetch = async (request, options) => {
8
8
  const entry = await CacheEntry.find(request, options)
9
9
  if (!entry) {
10
10
  // no cached result, if the cache mode is 'only-if-cached' that's a failure
11
- if (options.cache === 'only-if-cached')
11
+ if (options.cache === 'only-if-cached') {
12
12
  throw new NotCachedError(request.url)
13
+ }
13
14
 
14
15
  // otherwise, we make a request, store it and return it
15
16
  const response = await remote(request, options)
16
- const entry = new CacheEntry({ request, response, options })
17
- return entry.store('miss')
17
+ const newEntry = new CacheEntry({ request, response, options })
18
+ return newEntry.store('miss')
18
19
  }
19
20
 
20
21
  // we have a cached response that satisfies this request, however if the cache
21
22
  // mode is 'no-cache' then we send the revalidation request no matter what
22
- if (options.cache === 'no-cache')
23
+ if (options.cache === 'no-cache') {
23
24
  return entry.revalidate(request, options)
25
+ }
24
26
 
25
27
  // if the cached entry is not stale, or if the cache mode is 'force-cache' or
26
28
  // 'only-if-cached' we can respond with the cached entry. set the status
@@ -28,16 +30,18 @@ const cacheFetch = async (request, options) => {
28
30
  const _needsRevalidation = entry.policy.needsRevalidation(request)
29
31
  if (options.cache === 'force-cache' ||
30
32
  options.cache === 'only-if-cached' ||
31
- !_needsRevalidation)
33
+ !_needsRevalidation) {
32
34
  return entry.respond(request.method, options, _needsRevalidation ? 'stale' : 'hit')
35
+ }
33
36
 
34
37
  // if we got here, the cache entry is stale so revalidate it
35
38
  return entry.revalidate(request, options)
36
39
  }
37
40
 
38
41
  cacheFetch.invalidate = async (request, options) => {
39
- if (!options.cachePath)
42
+ if (!options.cachePath) {
40
43
  return
44
+ }
41
45
 
42
46
  return CacheEntry.invalidate(request, options)
43
47
  }