undici 7.0.0-alpha.7 → 7.0.0-alpha.8

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/lib/util/cache.js CHANGED
@@ -96,36 +96,27 @@ function assertCacheValue (value) {
96
96
  /**
97
97
  * @see https://www.rfc-editor.org/rfc/rfc9111.html#name-cache-control
98
98
  * @see https://www.iana.org/assignments/http-cache-directives/http-cache-directives.xhtml
99
- *
100
- * @typedef {{
101
- * 'max-stale'?: number;
102
- * 'min-fresh'?: number;
103
- * 'max-age'?: number;
104
- * 's-maxage'?: number;
105
- * 'stale-while-revalidate'?: number;
106
- * 'stale-if-error'?: number;
107
- * public?: true;
108
- * private?: true | string[];
109
- * 'no-store'?: true;
110
- * 'no-cache'?: true | string[];
111
- * 'must-revalidate'?: true;
112
- * 'proxy-revalidate'?: true;
113
- * immutable?: true;
114
- * 'no-transform'?: true;
115
- * 'must-understand'?: true;
116
- * 'only-if-cached'?: true;
117
- * }} CacheControlDirectives
118
- *
99
+
119
100
  * @param {string | string[]} header
120
- * @returns {CacheControlDirectives}
101
+ * @returns {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives}
121
102
  */
122
103
  function parseCacheControlHeader (header) {
123
104
  /**
124
- * @type {import('../util/cache.js').CacheControlDirectives}
105
+ * @type {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives}
125
106
  */
126
107
  const output = {}
127
108
 
128
- const directives = Array.isArray(header) ? header : header.split(',')
109
+ let directives
110
+ if (Array.isArray(header)) {
111
+ directives = []
112
+
113
+ for (const directive of header) {
114
+ directives.push(...directive.split(','))
115
+ }
116
+ } else {
117
+ directives = header.split(',')
118
+ }
119
+
129
120
  for (let i = 0; i < directives.length; i++) {
130
121
  const directive = directives[i].toLowerCase()
131
122
  const keyValueDelimiter = directive.indexOf('=')
@@ -133,10 +124,8 @@ function parseCacheControlHeader (header) {
133
124
  let key
134
125
  let value
135
126
  if (keyValueDelimiter !== -1) {
136
- key = directive.substring(0, keyValueDelimiter).trim()
137
- value = directive
138
- .substring(keyValueDelimiter + 1)
139
- .trim()
127
+ key = directive.substring(0, keyValueDelimiter).trimStart()
128
+ value = directive.substring(keyValueDelimiter + 1)
140
129
  } else {
141
130
  key = directive.trim()
142
131
  }
@@ -148,16 +137,28 @@ function parseCacheControlHeader (header) {
148
137
  case 's-maxage':
149
138
  case 'stale-while-revalidate':
150
139
  case 'stale-if-error': {
151
- if (value === undefined) {
140
+ if (value === undefined || value[0] === ' ') {
152
141
  continue
153
142
  }
154
143
 
144
+ if (
145
+ value.length >= 2 &&
146
+ value[0] === '"' &&
147
+ value[value.length - 1] === '"'
148
+ ) {
149
+ value = value.substring(1, value.length - 1)
150
+ }
151
+
155
152
  const parsedValue = parseInt(value, 10)
156
153
  // eslint-disable-next-line no-self-compare
157
154
  if (parsedValue !== parsedValue) {
158
155
  continue
159
156
  }
160
157
 
158
+ if (key === 'max-age' && key in output && output[key] >= parsedValue) {
159
+ continue
160
+ }
161
+
161
162
  output[key] = parsedValue
162
163
 
163
164
  break
@@ -206,11 +207,19 @@ function parseCacheControlHeader (header) {
206
207
  headers[headers.length - 1] = lastHeader
207
208
  }
208
209
 
209
- output[key] = headers
210
+ if (key in output) {
211
+ output[key] = output[key].concat(headers)
212
+ } else {
213
+ output[key] = headers
214
+ }
210
215
  }
211
216
  } else {
212
217
  // Something like `no-cache=some-header`
213
- output[key] = [value]
218
+ if (key in output) {
219
+ output[key] = output[key].concat(value)
220
+ } else {
221
+ output[key] = [value]
222
+ }
214
223
  }
215
224
 
216
225
  break
@@ -248,7 +257,7 @@ function parseCacheControlHeader (header) {
248
257
  * @returns {Record<string, string | string[]>}
249
258
  */
250
259
  function parseVaryHeader (varyHeader, headers) {
251
- if (typeof varyHeader === 'string' && varyHeader === '*') {
260
+ if (typeof varyHeader === 'string' && varyHeader.includes('*')) {
252
261
  return headers
253
262
  }
254
263
 
@@ -262,6 +271,8 @@ function parseVaryHeader (varyHeader, headers) {
262
271
 
263
272
  if (headers[trimmedHeader]) {
264
273
  output[trimmedHeader] = headers[trimmedHeader]
274
+ } else {
275
+ return undefined
265
276
  }
266
277
  }
267
278
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "undici",
3
- "version": "7.0.0-alpha.7",
3
+ "version": "7.0.0-alpha.8",
4
4
  "description": "An HTTP/1.1 client, written from scratch for Node.js",
5
5
  "homepage": "https://undici.nodejs.org",
6
6
  "bugs": {
@@ -73,6 +73,7 @@
73
73
  "test:javascript:without-intl": "npm run test:javascript:no-jest",
74
74
  "test:busboy": "borp -p \"test/busboy/*.js\"",
75
75
  "test:cache": "borp -p \"test/cache/*.js\"",
76
+ "test:sqlite": "NODE_OPTIONS=--experimental-sqlite borp -p \"test/cache-interceptor/*.js\"",
76
77
  "test:cache-interceptor": "borp -p \"test/cache-interceptor/*.js\"",
77
78
  "test:cookies": "borp -p \"test/cookie/*.js\"",
78
79
  "test:eventsource": "npm run build:node && borp --expose-gc -p \"test/eventsource/*.js\"",
@@ -110,7 +111,7 @@
110
111
  "@sinonjs/fake-timers": "^12.0.0",
111
112
  "@types/node": "^18.19.50",
112
113
  "abort-controller": "^3.0.0",
113
- "borp": "^0.18.0",
114
+ "borp": "^0.19.0",
114
115
  "c8": "^10.0.0",
115
116
  "cross-env": "^7.0.3",
116
117
  "dns-packet": "^5.4.0",
@@ -128,7 +129,7 @@
128
129
  "ws": "^8.11.0"
129
130
  },
130
131
  "engines": {
131
- "node": ">=18.17"
132
+ "node": ">=20.18.1"
132
133
  },
133
134
  "tsd": {
134
135
  "directory": "test/types",
@@ -7,6 +7,10 @@ declare namespace CacheHandler {
7
7
 
8
8
  export interface CacheHandlerOptions {
9
9
  store: CacheStore
10
+
11
+ cacheByDefault?: number
12
+
13
+ type?: CacheOptions['type']
10
14
  }
11
15
 
12
16
  export interface CacheOptions {
@@ -20,6 +24,39 @@ declare namespace CacheHandler {
20
24
  * @see https://www.rfc-editor.org/rfc/rfc9110#section-9.2.1
21
25
  */
22
26
  methods?: CacheMethods[]
27
+
28
+ /**
29
+ * RFC9111 allows for caching responses that we aren't explicitly told to
30
+ * cache or to not cache.
31
+ * @see https://www.rfc-editor.org/rfc/rfc9111.html#section-3-5
32
+ * @default undefined
33
+ */
34
+ cacheByDefault?: number
35
+
36
+ /**
37
+ * TODO docs
38
+ * @default 'shared'
39
+ */
40
+ type?: 'shared' | 'private'
41
+ }
42
+
43
+ export interface CacheControlDirectives {
44
+ 'max-stale'?: number;
45
+ 'min-fresh'?: number;
46
+ 'max-age'?: number;
47
+ 's-maxage'?: number;
48
+ 'stale-while-revalidate'?: number;
49
+ 'stale-if-error'?: number;
50
+ public?: true;
51
+ private?: true | string[];
52
+ 'no-store'?: true;
53
+ 'no-cache'?: true | string[];
54
+ 'must-revalidate'?: true;
55
+ 'proxy-revalidate'?: true;
56
+ immutable?: true;
57
+ 'no-transform'?: true;
58
+ 'must-understand'?: true;
59
+ 'only-if-cached'?: true;
23
60
  }
24
61
 
25
62
  export interface CacheKey {
@@ -35,6 +72,7 @@ declare namespace CacheHandler {
35
72
  headers: Record<string, string | string[]>
36
73
  vary?: Record<string, string | string[]>
37
74
  etag?: string
75
+ cacheControlDirectives?: CacheControlDirectives
38
76
  cachedAt: number
39
77
  staleAt: number
40
78
  deleteAt: number
@@ -50,8 +88,10 @@ declare namespace CacheHandler {
50
88
  statusCode: number
51
89
  statusMessage: string
52
90
  headers: Record<string, string | string[]>
91
+ vary?: Record<string, string | string[]>
53
92
  etag?: string
54
93
  body: null | Readable | Iterable<Buffer> | AsyncIterable<Buffer> | Buffer | Iterable<string> | AsyncIterable<string> | string
94
+ cacheControlDirectives: CacheControlDirectives,
55
95
  cachedAt: number
56
96
  staleAt: number
57
97
  deleteAt: number