undici 7.16.0 → 7.17.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.
Files changed (69) hide show
  1. package/README.md +47 -1
  2. package/docs/docs/api/Client.md +1 -0
  3. package/docs/docs/api/DiagnosticsChannel.md +57 -0
  4. package/docs/docs/api/Dispatcher.md +86 -0
  5. package/docs/docs/api/RoundRobinPool.md +145 -0
  6. package/docs/docs/api/WebSocket.md +21 -0
  7. package/docs/docs/best-practices/crawling.md +58 -0
  8. package/index.js +4 -1
  9. package/lib/api/api-upgrade.js +2 -1
  10. package/lib/core/connect.js +4 -1
  11. package/lib/core/diagnostics.js +28 -1
  12. package/lib/core/symbols.js +3 -0
  13. package/lib/core/util.js +29 -31
  14. package/lib/dispatcher/balanced-pool.js +10 -0
  15. package/lib/dispatcher/client-h1.js +0 -16
  16. package/lib/dispatcher/client-h2.js +153 -23
  17. package/lib/dispatcher/client.js +7 -2
  18. package/lib/dispatcher/dispatcher-base.js +11 -12
  19. package/lib/dispatcher/h2c-client.js +7 -78
  20. package/lib/dispatcher/pool-base.js +1 -1
  21. package/lib/dispatcher/proxy-agent.js +13 -2
  22. package/lib/dispatcher/round-robin-pool.js +137 -0
  23. package/lib/encoding/index.js +33 -0
  24. package/lib/handler/cache-handler.js +84 -27
  25. package/lib/handler/deduplication-handler.js +216 -0
  26. package/lib/handler/retry-handler.js +0 -2
  27. package/lib/interceptor/cache.js +35 -17
  28. package/lib/interceptor/decompress.js +2 -1
  29. package/lib/interceptor/deduplicate.js +109 -0
  30. package/lib/interceptor/dns.js +55 -13
  31. package/lib/mock/mock-utils.js +1 -2
  32. package/lib/mock/snapshot-agent.js +11 -5
  33. package/lib/mock/snapshot-recorder.js +12 -4
  34. package/lib/mock/snapshot-utils.js +4 -4
  35. package/lib/util/cache.js +29 -1
  36. package/lib/util/runtime-features.js +124 -0
  37. package/lib/web/cookies/parse.js +1 -1
  38. package/lib/web/fetch/body.js +29 -39
  39. package/lib/web/fetch/data-url.js +12 -160
  40. package/lib/web/fetch/formdata-parser.js +204 -127
  41. package/lib/web/fetch/index.js +9 -6
  42. package/lib/web/fetch/request.js +6 -0
  43. package/lib/web/fetch/response.js +2 -3
  44. package/lib/web/fetch/util.js +2 -65
  45. package/lib/web/infra/index.js +229 -0
  46. package/lib/web/subresource-integrity/subresource-integrity.js +6 -5
  47. package/lib/web/webidl/index.js +4 -2
  48. package/lib/web/websocket/connection.js +31 -21
  49. package/lib/web/websocket/frame.js +9 -15
  50. package/lib/web/websocket/stream/websocketstream.js +1 -1
  51. package/lib/web/websocket/util.js +2 -1
  52. package/package.json +5 -4
  53. package/types/agent.d.ts +1 -1
  54. package/types/api.d.ts +2 -2
  55. package/types/balanced-pool.d.ts +2 -1
  56. package/types/cache-interceptor.d.ts +1 -0
  57. package/types/client.d.ts +1 -1
  58. package/types/connector.d.ts +2 -2
  59. package/types/diagnostics-channel.d.ts +2 -2
  60. package/types/dispatcher.d.ts +12 -12
  61. package/types/fetch.d.ts +4 -4
  62. package/types/formdata.d.ts +1 -1
  63. package/types/h2c-client.d.ts +1 -1
  64. package/types/index.d.ts +9 -1
  65. package/types/interceptors.d.ts +36 -2
  66. package/types/pool.d.ts +1 -1
  67. package/types/readable.d.ts +2 -2
  68. package/types/round-robin-pool.d.ts +41 -0
  69. package/types/websocket.d.ts +9 -9
package/types/index.d.ts CHANGED
@@ -5,6 +5,7 @@ import Pool from './pool'
5
5
  import { RedirectHandler, DecoratorHandler } from './handlers'
6
6
 
7
7
  import BalancedPool from './balanced-pool'
8
+ import RoundRobinPool from './round-robin-pool'
8
9
  import Client from './client'
9
10
  import H2CClient from './h2c-client'
10
11
  import buildConnector from './connector'
@@ -23,6 +24,12 @@ import RetryAgent from './retry-agent'
23
24
  import { request, pipeline, stream, connect, upgrade } from './api'
24
25
  import interceptors from './interceptors'
25
26
 
27
+ import CacheInterceptor from './cache-interceptor'
28
+ declare const cacheStores: {
29
+ MemoryCacheStore: typeof CacheInterceptor.MemoryCacheStore;
30
+ SqliteCacheStore: typeof CacheInterceptor.SqliteCacheStore;
31
+ }
32
+
26
33
  export * from './util'
27
34
  export * from './cookies'
28
35
  export * from './eventsource'
@@ -36,7 +43,7 @@ export { Interceptable } from './mock-interceptor'
36
43
 
37
44
  declare function globalThisInstall (): void
38
45
 
39
- export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, interceptors, MockClient, MockPool, MockAgent, SnapshotAgent, MockCallHistory, MockCallHistoryLog, mockErrors, ProxyAgent, EnvHttpProxyAgent, RedirectHandler, DecoratorHandler, RetryHandler, RetryAgent, H2CClient, globalThisInstall as install }
46
+ export { Dispatcher, BalancedPool, RoundRobinPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, interceptors, cacheStores, MockClient, MockPool, MockAgent, SnapshotAgent, MockCallHistory, MockCallHistoryLog, mockErrors, ProxyAgent, EnvHttpProxyAgent, RedirectHandler, DecoratorHandler, RetryHandler, RetryAgent, H2CClient, globalThisInstall as install }
40
47
  export default Undici
41
48
 
42
49
  declare namespace Undici {
@@ -46,6 +53,7 @@ declare namespace Undici {
46
53
  const DecoratorHandler: typeof import ('./handlers').DecoratorHandler
47
54
  const RetryHandler: typeof import ('./retry-handler').default
48
55
  const BalancedPool: typeof import('./balanced-pool').default
56
+ const RoundRobinPool: typeof import('./round-robin-pool').default
49
57
  const Client: typeof import('./client').default
50
58
  const H2CClient: typeof import('./h2c-client').default
51
59
  const buildConnector: typeof import('./connector').default
@@ -19,14 +19,47 @@ declare namespace Interceptors {
19
19
 
20
20
  // DNS interceptor
21
21
  export type DNSInterceptorRecord = { address: string, ttl: number, family: 4 | 6 }
22
- export type DNSInterceptorOriginRecords = { 4: { ips: DNSInterceptorRecord[] } | null, 6: { ips: DNSInterceptorRecord[] } | null }
22
+ export type DNSInterceptorOriginRecords = { records: { 4: { ips: DNSInterceptorRecord[] } | null, 6: { ips: DNSInterceptorRecord[] } | null } }
23
+ export type DNSStorage = {
24
+ size: number
25
+ get(origin: string): DNSInterceptorOriginRecords | null
26
+ set(origin: string, records: DNSInterceptorOriginRecords | null, options: { ttl: number }): void
27
+ delete(origin: string): void
28
+ full(): boolean
29
+ }
23
30
  export type DNSInterceptorOpts = {
24
31
  maxTTL?: number
25
32
  maxItems?: number
26
- lookup?: (hostname: string, options: LookupOptions, callback: (err: NodeJS.ErrnoException | null, addresses: DNSInterceptorRecord[]) => void) => void
33
+ lookup?: (origin: URL, options: LookupOptions, callback: (err: NodeJS.ErrnoException | null, addresses: DNSInterceptorRecord[]) => void) => void
27
34
  pick?: (origin: URL, records: DNSInterceptorOriginRecords, affinity: 4 | 6) => DNSInterceptorRecord
28
35
  dualStack?: boolean
29
36
  affinity?: 4 | 6
37
+ storage?: DNSStorage
38
+ }
39
+
40
+ // Deduplicate interceptor
41
+ export type DeduplicateMethods = 'GET' | 'HEAD' | 'OPTIONS' | 'TRACE'
42
+ export type DeduplicateInterceptorOpts = {
43
+ /**
44
+ * The HTTP methods to deduplicate.
45
+ * Note: Only safe HTTP methods can be deduplicated.
46
+ * @default ['GET']
47
+ */
48
+ methods?: DeduplicateMethods[]
49
+ /**
50
+ * Header names that, if present in a request, will cause the request to skip deduplication.
51
+ * Header name matching is case-insensitive.
52
+ * @default []
53
+ */
54
+ skipHeaderNames?: string[]
55
+ /**
56
+ * Header names to exclude from the deduplication key.
57
+ * Requests with different values for these headers will still be deduplicated together.
58
+ * Useful for headers like `x-request-id` that vary per request but shouldn't affect deduplication.
59
+ * Header name matching is case-insensitive.
60
+ * @default []
61
+ */
62
+ excludeHeaderNames?: string[]
30
63
  }
31
64
 
32
65
  export function dump (opts?: DumpInterceptorOpts): Dispatcher.DispatcherComposeInterceptor
@@ -36,4 +69,5 @@ declare namespace Interceptors {
36
69
  export function responseError (opts?: ResponseErrorInterceptorOpts): Dispatcher.DispatcherComposeInterceptor
37
70
  export function dns (opts?: DNSInterceptorOpts): Dispatcher.DispatcherComposeInterceptor
38
71
  export function cache (opts?: CacheInterceptorOpts): Dispatcher.DispatcherComposeInterceptor
72
+ export function deduplicate (opts?: DeduplicateInterceptorOpts): Dispatcher.DispatcherComposeInterceptor
39
73
  }
package/types/pool.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import Client from './client'
2
2
  import TPoolStats from './pool-stats'
3
- import { URL } from 'url'
3
+ import { URL } from 'node:url'
4
4
  import Dispatcher from './dispatcher'
5
5
 
6
6
  export default Pool
@@ -1,5 +1,5 @@
1
- import { Readable } from 'stream'
2
- import { Blob } from 'buffer'
1
+ import { Readable } from 'node:stream'
2
+ import { Blob } from 'node:buffer'
3
3
 
4
4
  export default BodyReadable
5
5
 
@@ -0,0 +1,41 @@
1
+ import Client from './client'
2
+ import TPoolStats from './pool-stats'
3
+ import { URL } from 'node:url'
4
+ import Dispatcher from './dispatcher'
5
+
6
+ export default RoundRobinPool
7
+
8
+ type RoundRobinPoolConnectOptions = Omit<Dispatcher.ConnectOptions, 'origin'>
9
+
10
+ declare class RoundRobinPool extends Dispatcher {
11
+ constructor (url: string | URL, options?: RoundRobinPool.Options)
12
+ /** `true` after `pool.close()` has been called. */
13
+ closed: boolean
14
+ /** `true` after `pool.destroyed()` has been called or `pool.close()` has been called and the pool shutdown has completed. */
15
+ destroyed: boolean
16
+ /** Aggregate stats for a RoundRobinPool. */
17
+ readonly stats: TPoolStats
18
+
19
+ // Override dispatcher APIs.
20
+ override connect (
21
+ options: RoundRobinPoolConnectOptions
22
+ ): Promise<Dispatcher.ConnectData>
23
+ override connect (
24
+ options: RoundRobinPoolConnectOptions,
25
+ callback: (err: Error | null, data: Dispatcher.ConnectData) => void
26
+ ): void
27
+ }
28
+
29
+ declare namespace RoundRobinPool {
30
+ export type RoundRobinPoolStats = TPoolStats
31
+ export interface Options extends Client.Options {
32
+ /** Default: `(origin, opts) => new Client(origin, opts)`. */
33
+ factory?(origin: URL, opts: object): Dispatcher;
34
+ /** The max number of clients to create. `null` if no limit. Default `null`. */
35
+ connections?: number | null;
36
+ /** The amount of time before a client is removed from the pool and closed. `null` if no time limit. Default `null` */
37
+ clientTtl?: number | null;
38
+
39
+ interceptors?: { RoundRobinPool?: readonly Dispatcher.DispatchInterceptor[] } & Client.Options['interceptors']
40
+ }
41
+ }
@@ -1,8 +1,8 @@
1
1
  /// <reference types="node" />
2
2
 
3
- import type { Blob } from 'buffer'
4
- import type { ReadableStream, WritableStream } from 'stream/web'
5
- import type { MessagePort } from 'worker_threads'
3
+ import type { Blob } from 'node:buffer'
4
+ import type { ReadableStream, WritableStream } from 'node:stream/web'
5
+ import type { MessagePort } from 'node:worker_threads'
6
6
  import {
7
7
  EventInit,
8
8
  EventListenerOptions,
@@ -96,16 +96,16 @@ interface MessageEventInit<T = any> extends EventInit {
96
96
  data?: T
97
97
  lastEventId?: string
98
98
  origin?: string
99
- ports?: (typeof MessagePort)[]
100
- source?: typeof MessagePort | null
99
+ ports?: MessagePort[]
100
+ source?: MessagePort | null
101
101
  }
102
102
 
103
103
  interface MessageEvent<T = any> extends Event {
104
104
  readonly data: T
105
105
  readonly lastEventId: string
106
106
  readonly origin: string
107
- readonly ports: ReadonlyArray<typeof MessagePort>
108
- readonly source: typeof MessagePort | null
107
+ readonly ports: readonly MessagePort[]
108
+ readonly source: MessagePort | null
109
109
  initMessageEvent(
110
110
  type: string,
111
111
  bubbles?: boolean,
@@ -113,8 +113,8 @@ interface MessageEvent<T = any> extends Event {
113
113
  data?: any,
114
114
  origin?: string,
115
115
  lastEventId?: string,
116
- source?: typeof MessagePort | null,
117
- ports?: (typeof MessagePort)[]
116
+ source?: MessagePort | null,
117
+ ports?: MessagePort[]
118
118
  ): void;
119
119
  }
120
120