@cacheable/net 1.0.1 → 2.0.0

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/dist/index.js CHANGED
@@ -3,58 +3,672 @@ import { Cacheable } from "cacheable";
3
3
  import { Hookified } from "hookified";
4
4
 
5
5
  // src/fetch.ts
6
+ import CachePolicy from "http-cache-semantics";
6
7
  import {
7
8
  fetch as undiciFetch
8
9
  } from "undici";
9
10
  async function fetch(url, options) {
10
- if (!options.cache) {
11
- throw new Error("Fetch options must include a cache instance or options.");
12
- }
13
11
  const fetchOptions = {
14
12
  ...options,
15
13
  cache: "no-cache"
16
14
  };
17
- return options.cache.getOrSet(url, async () => {
18
- const response = await undiciFetch(url, fetchOptions);
19
- if (!response.ok) {
20
- throw new Error(`Fetch failed with status ${response.status}`);
15
+ if (!options.cache) {
16
+ const response2 = await undiciFetch(url, fetchOptions);
17
+ if (!response2.ok) {
18
+ throw new Error(`Fetch failed with status ${response2.status}`);
21
19
  }
22
- return response;
20
+ return response2;
21
+ }
22
+ if (options.method === "POST" || options.method === "PATCH" || options.method === "DELETE" || options.method === "HEAD") {
23
+ const response2 = await undiciFetch(url, fetchOptions);
24
+ if (!response2.ok) {
25
+ throw new Error(`Fetch failed with status ${response2.status}`);
26
+ }
27
+ return response2;
28
+ }
29
+ const httpCachePolicy = options.httpCachePolicy !== false;
30
+ const method = options.method || "GET";
31
+ const cacheKey = `${method}:${url}`;
32
+ if (!httpCachePolicy) {
33
+ const cachedData = await options.cache.getOrSet(cacheKey, async () => {
34
+ const response2 = await undiciFetch(url, fetchOptions);
35
+ if (!response2.ok) {
36
+ throw new Error(`Fetch failed with status ${response2.status}`);
37
+ }
38
+ const body2 = await response2.text();
39
+ return {
40
+ body: body2,
41
+ status: response2.status,
42
+ statusText: response2.statusText,
43
+ headers: Object.fromEntries(response2.headers.entries())
44
+ };
45
+ });
46
+ if (!cachedData) {
47
+ throw new Error("Failed to get or set cache data");
48
+ }
49
+ return new Response(cachedData.body, {
50
+ status: cachedData.status,
51
+ statusText: cachedData.statusText,
52
+ headers: cachedData.headers
53
+ });
54
+ }
55
+ const policyKey = `${cacheKey}:policy`;
56
+ const [cachedResponse, cachedPolicyData] = await Promise.all([
57
+ options.cache.get(cacheKey),
58
+ options.cache.get(policyKey)
59
+ ]);
60
+ let policy;
61
+ let cachedBody;
62
+ let cachedStatus;
63
+ let cachedStatusText;
64
+ let cachedHeaders;
65
+ if (cachedPolicyData && cachedResponse) {
66
+ policy = CachePolicy.fromObject(
67
+ cachedPolicyData
68
+ );
69
+ cachedBody = cachedResponse.body;
70
+ cachedStatus = cachedResponse.status;
71
+ cachedStatusText = cachedResponse.statusText;
72
+ cachedHeaders = cachedResponse.headers;
73
+ }
74
+ const requestHeaders = fetchOptions.headers || {};
75
+ const request = {
76
+ url,
77
+ method,
78
+ headers: requestHeaders
79
+ };
80
+ if (policy?.satisfiesWithoutRevalidation(request)) {
81
+ const headers = policy.responseHeaders();
82
+ return new Response(cachedBody, {
83
+ status: cachedStatus,
84
+ statusText: cachedStatusText,
85
+ headers
86
+ });
87
+ }
88
+ let revalidationHeaders = {};
89
+ if (policy?.revalidationHeaders(request)) {
90
+ revalidationHeaders = policy.revalidationHeaders(request);
91
+ }
92
+ const response = await undiciFetch(url, {
93
+ ...fetchOptions,
94
+ headers: {
95
+ ...fetchOptions.headers,
96
+ ...revalidationHeaders
97
+ }
98
+ });
99
+ if (response.status === 304 && policy) {
100
+ const { policy: updatedPolicy, modified } = policy.revalidatedPolicy(
101
+ request,
102
+ {
103
+ status: response.status,
104
+ headers: Object.fromEntries(response.headers.entries())
105
+ }
106
+ );
107
+ if (!modified) {
108
+ const ttl = updatedPolicy.timeToLive();
109
+ await options.cache.set(policyKey, updatedPolicy.toObject(), ttl);
110
+ await options.cache.set(
111
+ cacheKey,
112
+ {
113
+ body: cachedBody,
114
+ status: cachedStatus,
115
+ statusText: cachedStatusText,
116
+ headers: cachedHeaders
117
+ },
118
+ ttl
119
+ );
120
+ const headers = updatedPolicy.responseHeaders();
121
+ return new Response(cachedBody, {
122
+ status: cachedStatus,
123
+ statusText: cachedStatusText,
124
+ headers
125
+ });
126
+ }
127
+ }
128
+ if (!response.ok && response.status !== 304) {
129
+ throw new Error(`Fetch failed with status ${response.status}`);
130
+ }
131
+ const body = await response.text();
132
+ const responseForPolicy = {
133
+ status: response.status,
134
+ statusText: response.statusText,
135
+ headers: Object.fromEntries(response.headers.entries())
136
+ };
137
+ const newPolicy = new CachePolicy(request, responseForPolicy);
138
+ if (newPolicy.storable()) {
139
+ const ttl = newPolicy.timeToLive();
140
+ await Promise.all([
141
+ options.cache.set(
142
+ cacheKey,
143
+ {
144
+ body,
145
+ status: response.status,
146
+ statusText: response.statusText,
147
+ headers: responseForPolicy.headers
148
+ },
149
+ ttl
150
+ ),
151
+ options.cache.set(policyKey, newPolicy.toObject(), ttl)
152
+ ]);
153
+ }
154
+ return new Response(body, {
155
+ status: response.status,
156
+ statusText: response.statusText,
157
+ headers: response.headers
158
+ });
159
+ }
160
+ async function get(url, options) {
161
+ const response = await fetch(url, { ...options, method: "GET" });
162
+ const text = await response.text();
163
+ let data;
164
+ try {
165
+ data = JSON.parse(text);
166
+ } catch {
167
+ data = text;
168
+ }
169
+ const newResponse = new Response(text, {
170
+ status: response.status,
171
+ statusText: response.statusText,
172
+ headers: response.headers
173
+ });
174
+ return {
175
+ data,
176
+ response: newResponse
177
+ };
178
+ }
179
+ async function post(url, data, options) {
180
+ let body;
181
+ const headers = { ...options.headers };
182
+ if (typeof data === "string") {
183
+ body = data;
184
+ } else if (data instanceof FormData || data instanceof URLSearchParams || data instanceof Blob) {
185
+ body = data;
186
+ } else {
187
+ body = JSON.stringify(data);
188
+ if (!headers["Content-Type"] && !headers["content-type"]) {
189
+ headers["Content-Type"] = "application/json";
190
+ }
191
+ }
192
+ const response = await fetch(url, {
193
+ ...options,
194
+ headers,
195
+ body,
196
+ method: "POST"
197
+ });
198
+ const text = await response.text();
199
+ let responseData;
200
+ try {
201
+ responseData = JSON.parse(text);
202
+ } catch {
203
+ responseData = text;
204
+ }
205
+ const newResponse = new Response(text, {
206
+ status: response.status,
207
+ statusText: response.statusText,
208
+ headers: response.headers
209
+ });
210
+ return {
211
+ data: responseData,
212
+ response: newResponse
213
+ };
214
+ }
215
+ async function patch(url, data, options) {
216
+ let body;
217
+ const headers = { ...options.headers };
218
+ if (typeof data === "string") {
219
+ body = data;
220
+ } else if (data instanceof FormData || data instanceof URLSearchParams || data instanceof Blob) {
221
+ body = data;
222
+ } else {
223
+ body = JSON.stringify(data);
224
+ if (!headers["Content-Type"] && !headers["content-type"]) {
225
+ headers["Content-Type"] = "application/json";
226
+ }
227
+ }
228
+ const response = await fetch(url, {
229
+ ...options,
230
+ headers,
231
+ body,
232
+ method: "PATCH"
233
+ });
234
+ const text = await response.text();
235
+ let responseData;
236
+ try {
237
+ responseData = JSON.parse(text);
238
+ } catch {
239
+ responseData = text;
240
+ }
241
+ const newResponse = new Response(text, {
242
+ status: response.status,
243
+ statusText: response.statusText,
244
+ headers: response.headers
245
+ });
246
+ return {
247
+ data: responseData,
248
+ response: newResponse
249
+ };
250
+ }
251
+ async function del(url, data, options) {
252
+ let actualData;
253
+ let actualOptions;
254
+ if (data !== void 0 && typeof data === "object" && data !== null && "cache" in data) {
255
+ actualData = void 0;
256
+ actualOptions = data;
257
+ } else if (options) {
258
+ actualData = data;
259
+ actualOptions = options;
260
+ } else {
261
+ throw new Error("Fetch options must include a cache instance or options.");
262
+ }
263
+ let body;
264
+ const headers = { ...actualOptions.headers };
265
+ if (actualData !== void 0) {
266
+ if (typeof actualData === "string") {
267
+ body = actualData;
268
+ } else if (actualData instanceof FormData || actualData instanceof URLSearchParams || actualData instanceof Blob) {
269
+ body = actualData;
270
+ } else {
271
+ body = JSON.stringify(actualData);
272
+ if (!headers["Content-Type"] && !headers["content-type"]) {
273
+ headers["Content-Type"] = "application/json";
274
+ }
275
+ }
276
+ }
277
+ const response = await fetch(url, {
278
+ ...actualOptions,
279
+ headers,
280
+ body,
281
+ method: "DELETE"
282
+ });
283
+ const text = await response.text();
284
+ let responseData;
285
+ try {
286
+ responseData = JSON.parse(text);
287
+ } catch {
288
+ responseData = text;
289
+ }
290
+ const newResponse = new Response(text, {
291
+ status: response.status,
292
+ statusText: response.statusText,
293
+ headers: response.headers
23
294
  });
295
+ return {
296
+ data: responseData,
297
+ response: newResponse
298
+ };
299
+ }
300
+ async function head(url, options) {
301
+ const response = await fetch(url, { ...options, method: "HEAD" });
302
+ return response;
24
303
  }
25
304
 
26
305
  // src/index.ts
27
306
  var CacheableNet = class extends Hookified {
28
307
  _cache = new Cacheable();
308
+ _httpCachePolicy = true;
309
+ _stringify = JSON.stringify;
310
+ _parse = JSON.parse;
29
311
  constructor(options) {
30
312
  super(options);
31
313
  if (options?.cache) {
32
314
  this._cache = options.cache instanceof Cacheable ? options.cache : new Cacheable(options.cache);
33
315
  }
316
+ if (options?.httpCachePolicy !== void 0) {
317
+ this._httpCachePolicy = options.httpCachePolicy;
318
+ }
319
+ if (options?.stringify) {
320
+ this._stringify = options?.stringify;
321
+ }
322
+ if (options?.parse) {
323
+ this._parse = options?.parse;
324
+ }
34
325
  }
326
+ /**
327
+ * Get the stringify function used for converting objects to strings.
328
+ * @returns {StringifyType} The current stringify function
329
+ */
330
+ get stringify() {
331
+ return this._stringify;
332
+ }
333
+ /**
334
+ * Set the stringify function for converting objects to strings.
335
+ * @param {StringifyType} value - The stringify function to use
336
+ */
337
+ set stringify(value) {
338
+ this._stringify = value;
339
+ }
340
+ /**
341
+ * Get the parse function used for converting strings to objects.
342
+ * @returns {ParseType} The current parse function
343
+ */
344
+ get parse() {
345
+ return this._parse;
346
+ }
347
+ /**
348
+ * Set the parse function for converting strings to objects.
349
+ * @param {ParseType} value - The parse function to use
350
+ */
351
+ set parse(value) {
352
+ this._parse = value;
353
+ }
354
+ /**
355
+ * Get the Cacheable instance used for caching fetch operations.
356
+ * @returns {Cacheable} The current Cacheable instance
357
+ */
35
358
  get cache() {
36
359
  return this._cache;
37
360
  }
361
+ /**
362
+ * Set the Cacheable instance for caching fetch operations.
363
+ * @param {Cacheable} value - The Cacheable instance to use for caching
364
+ */
38
365
  set cache(value) {
39
366
  this._cache = value;
40
367
  }
368
+ /**
369
+ * Get the current HTTP cache policy setting.
370
+ * @returns {boolean} Whether HTTP cache semantics are enabled
371
+ */
372
+ get httpCachePolicy() {
373
+ return this._httpCachePolicy;
374
+ }
375
+ /**
376
+ * Set whether to use HTTP cache semantics.
377
+ * @param {boolean} value - Enable or disable HTTP cache semantics
378
+ */
379
+ set httpCachePolicy(value) {
380
+ this._httpCachePolicy = value;
381
+ }
41
382
  /**
42
383
  * Fetch data from a URL with optional request options. Will use the cache that is already set in the instance.
384
+ *
385
+ * When `httpCachePolicy` is enabled (default), cache entries will have their TTL
386
+ * set based on HTTP cache headers (e.g., Cache-Control: max-age). When disabled,
387
+ * the default TTL from the Cacheable instance is used.
388
+ *
43
389
  * @param {string} url The URL to fetch.
44
- * @param {FetchRequestInit} options Optional request options.
390
+ * @param {Omit<FetchOptions, "cache">} options Optional request options.
45
391
  * @returns {Promise<FetchResponse>} The response from the fetch.
46
392
  */
47
393
  async fetch(url, options) {
48
394
  const fetchOptions = {
49
395
  ...options,
50
- cache: this._cache
396
+ cache: this._cache,
397
+ httpCachePolicy: this._httpCachePolicy
51
398
  };
52
399
  return fetch(url, fetchOptions);
53
400
  }
401
+ /**
402
+ * Perform a GET request to a URL with optional request options. By default caching is enabled on all requests. To
403
+ * disable set `options.caching` to false.
404
+ * @param {string} url The URL to fetch.
405
+ * @param {NetFetchOptions} options Optional request options (method will be set to GET).
406
+ * @returns {Promise<DataResponse<T>>} The typed data and response from the fetch.
407
+ */
408
+ async get(url, options) {
409
+ const fetchOptions = {
410
+ ...options,
411
+ cache: this._cache,
412
+ httpCachePolicy: this._httpCachePolicy,
413
+ method: "GET"
414
+ };
415
+ if (options?.caching !== void 0) {
416
+ delete fetchOptions.cache;
417
+ }
418
+ const response = await fetch(url, fetchOptions);
419
+ const text = await response.text();
420
+ let data;
421
+ const parseFn = options?.parse || this._parse;
422
+ try {
423
+ data = parseFn(text);
424
+ } catch {
425
+ data = text;
426
+ }
427
+ const newResponse = new Response(text, {
428
+ status: response.status,
429
+ statusText: response.statusText,
430
+ headers: response.headers
431
+ });
432
+ return {
433
+ data,
434
+ response: newResponse
435
+ };
436
+ }
437
+ /**
438
+ * Perform a POST request to a URL with data and optional request options. By default caching is not enabled. To enable it
439
+ * set `options.caching` to true. Note, setting caching to tru means it will not post if the data is the same.
440
+ * @param {string} url The URL to fetch.
441
+ * @param {unknown} data The data to send in the request body.
442
+ * @param {Omit<NetFetchOptions, "method" | "body" >} options Optional request options (method and body will be set).
443
+ * @returns {Promise<DataResponse<T>>} The typed data and response from the fetch.
444
+ */
445
+ async post(url, data, options) {
446
+ let body;
447
+ const headers = { ...options?.headers };
448
+ if (typeof data === "string") {
449
+ body = data;
450
+ } else if (data instanceof FormData || data instanceof URLSearchParams || data instanceof Blob) {
451
+ body = data;
452
+ } else {
453
+ const stringifyFn = options?.stringify || this._stringify;
454
+ body = stringifyFn(data);
455
+ if (!headers["Content-Type"] && !headers["content-type"]) {
456
+ headers["Content-Type"] = "application/json";
457
+ }
458
+ }
459
+ const fetchOptions = {
460
+ ...options,
461
+ headers,
462
+ body,
463
+ httpCachePolicy: this._httpCachePolicy,
464
+ method: "POST"
465
+ };
466
+ if (options?.caching === true) {
467
+ fetchOptions.cache = this._cache;
468
+ }
469
+ const response = await fetch(url, fetchOptions);
470
+ const text = await response.text();
471
+ let responseData;
472
+ const parseFn = options?.parse || this._parse;
473
+ try {
474
+ responseData = parseFn(text);
475
+ } catch {
476
+ responseData = text;
477
+ }
478
+ const newResponse = new Response(text, {
479
+ status: response.status,
480
+ statusText: response.statusText,
481
+ headers: response.headers
482
+ });
483
+ return {
484
+ data: responseData,
485
+ response: newResponse
486
+ };
487
+ }
488
+ /**
489
+ * Perform a HEAD request to a URL with optional request options. By default caching is enabled on all requests. To
490
+ * disable set `options.caching` to false.
491
+ * @param {string} url The URL to fetch.
492
+ * @param {NetFetchOptions} options Optional request options (method will be set to HEAD).
493
+ * @returns {Promise<FetchResponse>} The response from the fetch (no body).
494
+ */
495
+ async head(url, options) {
496
+ const fetchOptions = {
497
+ ...options,
498
+ cache: this._cache,
499
+ httpCachePolicy: this._httpCachePolicy,
500
+ method: "HEAD"
501
+ };
502
+ if (options?.caching !== void 0 && !options.caching) {
503
+ delete fetchOptions.cache;
504
+ }
505
+ const response = await fetch(url, fetchOptions);
506
+ return response;
507
+ }
508
+ /**
509
+ * Perform a PUT request to a URL with data and optional request options. By default caching is not enabled. To enable it
510
+ * set `options.caching` to true. Note, setting caching to true means it will not put if the data is the same.
511
+ * @param {string} url The URL to fetch.
512
+ * @param {unknown} data The data to send in the request body.
513
+ * @param {Omit<NetFetchOptions, 'method' | 'body'>} options Optional request options (method and body will be set).
514
+ * @returns {Promise<DataResponse<T>>} The typed data and response from the fetch.
515
+ */
516
+ async put(url, data, options) {
517
+ let body;
518
+ const headers = { ...options?.headers };
519
+ if (typeof data === "string") {
520
+ body = data;
521
+ } else if (data instanceof FormData || data instanceof URLSearchParams || data instanceof Blob) {
522
+ body = data;
523
+ } else {
524
+ const stringifyFn = options?.stringify || this._stringify;
525
+ body = stringifyFn(data);
526
+ if (!headers["Content-Type"] && !headers["content-type"]) {
527
+ headers["Content-Type"] = "application/json";
528
+ }
529
+ }
530
+ const fetchOptions = {
531
+ ...options,
532
+ headers,
533
+ body,
534
+ httpCachePolicy: this._httpCachePolicy,
535
+ method: "PUT"
536
+ };
537
+ if (options?.caching === true) {
538
+ fetchOptions.cache = this._cache;
539
+ }
540
+ const response = await fetch(url, fetchOptions);
541
+ const text = await response.text();
542
+ let responseData;
543
+ const parseFn = options?.parse || this._parse;
544
+ try {
545
+ responseData = parseFn(text);
546
+ } catch {
547
+ responseData = text;
548
+ }
549
+ const newResponse = new Response(text, {
550
+ status: response.status,
551
+ statusText: response.statusText,
552
+ headers: response.headers
553
+ });
554
+ return {
555
+ data: responseData,
556
+ response: newResponse
557
+ };
558
+ }
559
+ /**
560
+ * Perform a PATCH request to a URL with data and optional request options. By default caching is not enabled. To enable it
561
+ * set `options.caching` to true. Note, setting caching to true means it will not patch if the data is the same.
562
+ * @param {string} url The URL to fetch.
563
+ * @param {unknown} data The data to send in the request body.
564
+ * @param {Omit<NetFetchOptions, 'method' | 'body'>} options Optional request options (method and body will be set).
565
+ * @returns {Promise<DataResponse<T>>} The typed data and response from the fetch.
566
+ */
567
+ async patch(url, data, options) {
568
+ let body;
569
+ const headers = { ...options?.headers };
570
+ if (typeof data === "string") {
571
+ body = data;
572
+ } else if (data instanceof FormData || data instanceof URLSearchParams || data instanceof Blob) {
573
+ body = data;
574
+ } else {
575
+ const stringifyFn = options?.stringify || this._stringify;
576
+ body = stringifyFn(data);
577
+ if (!headers["Content-Type"] && !headers["content-type"]) {
578
+ headers["Content-Type"] = "application/json";
579
+ }
580
+ }
581
+ const fetchOptions = {
582
+ ...options,
583
+ headers,
584
+ body,
585
+ httpCachePolicy: this._httpCachePolicy,
586
+ method: "PATCH"
587
+ };
588
+ if (options?.caching === true) {
589
+ fetchOptions.cache = this._cache;
590
+ }
591
+ const response = await fetch(url, fetchOptions);
592
+ const text = await response.text();
593
+ let responseData;
594
+ const parseFn = options?.parse || this._parse;
595
+ try {
596
+ responseData = parseFn(text);
597
+ } catch {
598
+ responseData = text;
599
+ }
600
+ const newResponse = new Response(text, {
601
+ status: response.status,
602
+ statusText: response.statusText,
603
+ headers: response.headers
604
+ });
605
+ return {
606
+ data: responseData,
607
+ response: newResponse
608
+ };
609
+ }
610
+ /**
611
+ * Perform a DELETE request to a URL with optional data and request options. By default caching is not enabled. To enable it
612
+ * set `options.caching` to true. Note, setting caching to true means it will not delete if the data is the same.
613
+ * @param {string} url The URL to fetch.
614
+ * @param {unknown} data Optional data to send in the request body.
615
+ * @param {Omit<NetFetchOptions, 'method' | 'body'>} options Optional request options (method and body will be set).
616
+ * @returns {Promise<DataResponse<T>>} The typed data and response from the fetch.
617
+ */
618
+ async delete(url, data, options) {
619
+ let body;
620
+ const headers = { ...options?.headers };
621
+ if (data !== void 0) {
622
+ if (typeof data === "string") {
623
+ body = data;
624
+ } else if (data instanceof FormData || data instanceof URLSearchParams || data instanceof Blob) {
625
+ body = data;
626
+ } else {
627
+ const stringifyFn = options?.stringify || this._stringify;
628
+ body = stringifyFn(data);
629
+ if (!headers["Content-Type"] && !headers["content-type"]) {
630
+ headers["Content-Type"] = "application/json";
631
+ }
632
+ }
633
+ }
634
+ const fetchOptions = {
635
+ ...options,
636
+ headers,
637
+ body,
638
+ httpCachePolicy: this._httpCachePolicy,
639
+ method: "DELETE"
640
+ };
641
+ if (options?.caching === true) {
642
+ fetchOptions.cache = this._cache;
643
+ }
644
+ const response = await fetch(url, fetchOptions);
645
+ const text = await response.text();
646
+ let responseData;
647
+ const parseFn = options?.parse || this._parse;
648
+ try {
649
+ responseData = parseFn(text);
650
+ } catch {
651
+ responseData = text;
652
+ }
653
+ const newResponse = new Response(text, {
654
+ status: response.status,
655
+ statusText: response.statusText,
656
+ headers: response.headers
657
+ });
658
+ return {
659
+ data: responseData,
660
+ response: newResponse
661
+ };
662
+ }
54
663
  };
55
664
  var Net = CacheableNet;
56
665
  export {
57
666
  CacheableNet,
58
667
  Net,
59
- fetch
668
+ del,
669
+ fetch,
670
+ get,
671
+ head,
672
+ patch,
673
+ post
60
674
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cacheable/net",
3
- "version": "1.0.1",
3
+ "version": "2.0.0",
4
4
  "description": "High Performance Network Caching for Node.js with fetch, request, http 1.1, and http 2 support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -21,9 +21,10 @@
21
21
  "license": "MIT",
22
22
  "private": false,
23
23
  "devDependencies": {
24
- "@biomejs/biome": "^2.2.2",
24
+ "@biomejs/biome": "^2.2.4",
25
25
  "@faker-js/faker": "^10.0.0",
26
- "@types/node": "^24.3.0",
26
+ "@types/http-cache-semantics": "^4.0.4",
27
+ "@types/node": "^24.5.2",
27
28
  "@vitest/coverage-v8": "^3.2.4",
28
29
  "rimraf": "^6.0.1",
29
30
  "tsup": "^8.5.0",
@@ -31,9 +32,10 @@
31
32
  "vitest": "^3.2.4"
32
33
  },
33
34
  "dependencies": {
34
- "hookified": "^1.12.0",
35
- "undici": "^7.15.0",
36
- "cacheable": "^1.10.4"
35
+ "hookified": "^1.12.1",
36
+ "http-cache-semantics": "^4.2.0",
37
+ "undici": "^7.16.0",
38
+ "cacheable": "^2.0.3"
37
39
  },
38
40
  "keywords": [
39
41
  "cacheable",