@openclaw/discord 2026.6.11 → 2026.6.34

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 (152) hide show
  1. package/dist/action-runtime-api.js +1 -1
  2. package/dist/{api-4GFMoWu0.js → api-CjnGBhM3.js} +4 -1
  3. package/dist/api.js +14 -14
  4. package/dist/{approval-handler.runtime-SsFtZQA6.js → approval-handler.runtime-BWPQrzpP.js} +9 -4
  5. package/dist/{audit-CAnmyf2A.js → audit-BwJ_2OjL.js} +3 -3
  6. package/dist/{channel-YA7AbYP3.js → channel-DU4jnQgl.js} +15 -15
  7. package/dist/{channel-actions-BJ3n5Z1l.js → channel-actions-CwmIqnYN.js} +2 -2
  8. package/dist/{channel-actions.runtime-D2QTRgZ9.js → channel-actions.runtime-DvpTfaJ4.js} +5 -5
  9. package/dist/channel-plugin-api.js +1 -1
  10. package/dist/{channel.setup-B1zDEAR7.js → channel.setup-glZ5Y98a.js} +2 -2
  11. package/dist/{components-Dm4c_ce6.js → components-j6lTZBsT.js} +1 -1
  12. package/dist/{conversation-identity-DZ0BD7xO.js → conversation-identity-36FFBwm5.js} +2 -2
  13. package/dist/{directory-config-BK1OhHa3.js → directory-config-BYMFzL29.js} +1 -1
  14. package/dist/directory-contract-api.js +1 -1
  15. package/dist/{directory-live-DP3CmwGf.js → directory-live-9JtJCiu8.js} +2 -2
  16. package/dist/{handle-action.guild-admin-B2cOoU2D.js → handle-action.guild-admin-xxGYrp-I.js} +2 -2
  17. package/dist/index.js +1 -1
  18. package/dist/{manager.runtime-CPHxr9B3.js → manager.runtime-NxCd-PVt.js} +3 -3
  19. package/dist/{message-handler-CKaTgBIV.js → message-handler-cizxbaDc.js} +7 -6
  20. package/dist/{message-handler.preflight--eAiaewz.js → message-handler.preflight-CbD0u7U7.js} +10 -10
  21. package/dist/{message-handler.process-PhKAmrEd.js → message-handler.process-Do4EM591.js} +10 -10
  22. package/dist/{message-utils-O1vK3kPu.js → message-utils-CJeAoISH.js} +1 -1
  23. package/dist/{outbound-adapter-fO_7hbTh.js → outbound-adapter-Dxs6iKEq.js} +62 -131
  24. package/dist/{pluralkit-B3MzPaPU.js → pluralkit-DI6RYaVj.js} +1 -1
  25. package/dist/presence-cache-z1N8MbJ3.js +45 -0
  26. package/dist/{probe-CxnDikWm.js → probe-esE_Oqdm.js} +1 -1
  27. package/dist/{probe.runtime-DLFkSDVB.js → probe.runtime-C3Atgpvr.js} +1 -1
  28. package/dist/{provider-BJaJ20MY.js → provider-B-s93q9s.js} +76 -26
  29. package/dist/{provider-session.runtime-D6xc-60s.js → provider-session.runtime-BKMOqHpd.js} +3 -3
  30. package/dist/provider.runtime-CaTJrpnl.js +2 -0
  31. package/dist/{resolve-allowlist-common-BDpBb8dF.js → resolve-allowlist-common-3gB2Gpmm.js} +1 -1
  32. package/dist/{resolve-channels-iJIjYfRw.js → resolve-channels-B3gQf8QL.js} +3 -3
  33. package/dist/{resolve-users-_fv1mm1f.js → resolve-users-BO10y5fJ.js} +3 -3
  34. package/dist/{runtime-ywXByivr.js → runtime-CFlR3L9X.js} +8 -8
  35. package/dist/runtime-api.actions.js +2 -2
  36. package/dist/runtime-api.js +20 -20
  37. package/dist/runtime-api.lookup.js +5 -5
  38. package/dist/runtime-api.monitor-CRiBIQEI.js +6 -0
  39. package/dist/runtime-api.monitor.js +6 -5
  40. package/dist/runtime-api.send.js +5 -5
  41. package/dist/runtime-api.threads.js +3 -3
  42. package/dist/{send-Dc5uQX5H.js → send-JHxfT4Pk.js} +6 -4
  43. package/dist/{send.components-D4bl20xr.js → send.components-CN35E2Ck.js} +11 -6
  44. package/dist/{send.outbound-5axvwLkl.js → send.outbound-B-cA1Esv.js} +15 -8
  45. package/dist/{send.receipt-B21MspvT.js → send.receipt-CGecJDin.js} +10 -1
  46. package/dist/{send.shared-9082A2sO.js → send.shared-vcbfThdy.js} +107 -16
  47. package/dist/session-binding-contract-api.js +1 -1
  48. package/dist/setup-plugin-api.js +1 -1
  49. package/dist/{subagent-hooks-NTv6B4up.js → subagent-hooks-20wXhVzZ.js} +2 -2
  50. package/dist/subagent-hooks-api.js +1 -1
  51. package/dist/{system-events-BzaI1WpN.js → system-events-DR27TE7p.js} +1 -1
  52. package/dist/{target-resolver-agnOrtOU.js → target-resolver-CDi1gI90.js} +2 -2
  53. package/dist/targets-C6yd3y8R.js +3 -0
  54. package/dist/{thread-bindings-DNitaHVh.js → thread-bindings-DU4T6nDo.js} +4 -4
  55. package/dist/{thread-bindings.discord-api-CjYNuvZa.js → thread-bindings.discord-api-CYkr-3Gj.js} +4 -4
  56. package/dist/{thread-bindings.manager-PZvJ4TJx.js → thread-bindings.manager-BqWs1UE2.js} +3 -3
  57. package/dist/{transcripts-source-Bi8N6h5X.js → transcripts-source-D-lBI5ZD.js} +1 -1
  58. package/dist/transcripts-source-api.js +1 -1
  59. package/dist/{typing-BdRqXUN3.js → typing-xr05bL-r.js} +1 -1
  60. package/node_modules/undici/README.md +8 -2
  61. package/node_modules/undici/docs/docs/api/Agent.md +248 -44
  62. package/node_modules/undici/docs/docs/api/BalancedPool.md +246 -48
  63. package/node_modules/undici/docs/docs/api/CacheStorage.md +171 -13
  64. package/node_modules/undici/docs/docs/api/CacheStore.md +294 -98
  65. package/node_modules/undici/docs/docs/api/Client.md +369 -179
  66. package/node_modules/undici/docs/docs/api/ClientStats.md +80 -14
  67. package/node_modules/undici/docs/docs/api/Connector.md +118 -36
  68. package/node_modules/undici/docs/docs/api/ContentType.md +65 -25
  69. package/node_modules/undici/docs/docs/api/Cookies.md +122 -71
  70. package/node_modules/undici/docs/docs/api/Debug.md +34 -18
  71. package/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +364 -164
  72. package/node_modules/undici/docs/docs/api/Dispatcher.md +485 -1102
  73. package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +101 -87
  74. package/node_modules/undici/docs/docs/api/Errors.md +503 -40
  75. package/node_modules/undici/docs/docs/api/EventSource.md +294 -32
  76. package/node_modules/undici/docs/docs/api/Fetch.md +680 -31
  77. package/node_modules/undici/docs/docs/api/GlobalInstallation.md +78 -98
  78. package/node_modules/undici/docs/docs/api/H2CClient.md +298 -176
  79. package/node_modules/undici/docs/docs/api/Interceptors.md +414 -0
  80. package/node_modules/undici/docs/docs/api/MockAgent.md +333 -314
  81. package/node_modules/undici/docs/docs/api/MockCallHistory.md +272 -98
  82. package/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +189 -26
  83. package/node_modules/undici/docs/docs/api/MockClient.md +151 -33
  84. package/node_modules/undici/docs/docs/api/MockErrors.md +56 -5
  85. package/node_modules/undici/docs/docs/api/MockPool.md +321 -258
  86. package/node_modules/undici/docs/docs/api/Pool.md +235 -43
  87. package/node_modules/undici/docs/docs/api/PoolStats.md +119 -13
  88. package/node_modules/undici/docs/docs/api/ProxyAgent.md +179 -160
  89. package/node_modules/undici/docs/docs/api/RedirectHandler.md +238 -63
  90. package/node_modules/undici/docs/docs/api/RetryAgent.md +113 -26
  91. package/node_modules/undici/docs/docs/api/RetryHandler.md +161 -77
  92. package/node_modules/undici/docs/docs/api/RoundRobinPool.md +166 -72
  93. package/node_modules/undici/docs/docs/api/SnapshotAgent.md +264 -542
  94. package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +162 -187
  95. package/node_modules/undici/docs/docs/api/Util.md +68 -11
  96. package/node_modules/undici/docs/docs/api/WebSocket.md +475 -80
  97. package/node_modules/undici/docs/docs/api/api-lifecycle.md +100 -32
  98. package/node_modules/undici/docs/docs/best-practices/client-certificate.md +2 -0
  99. package/node_modules/undici/docs/docs/best-practices/crawling.md +3 -1
  100. package/node_modules/undici/docs/docs/best-practices/migrating-from-v7-to-v8.md +6 -4
  101. package/node_modules/undici/docs/docs/best-practices/mocking-request.md +9 -7
  102. package/node_modules/undici/docs/docs/best-practices/proxy.md +3 -1
  103. package/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +10 -8
  104. package/node_modules/undici/docs/docs/best-practices/writing-tests.md +2 -0
  105. package/node_modules/undici/docs/docs/{GettingStarted.md → getting-started.md} +22 -19
  106. package/node_modules/undici/docs/docs/index.md +784 -0
  107. package/node_modules/undici/docs/docs/site.json +125 -0
  108. package/node_modules/undici/docs/docs/type-map.json +79 -0
  109. package/node_modules/undici/lib/api/api-request.js +7 -1
  110. package/node_modules/undici/lib/api/readable.js +47 -2
  111. package/node_modules/undici/lib/cache/memory-cache-store.js +54 -9
  112. package/node_modules/undici/lib/cache/sqlite-cache-store.js +7 -1
  113. package/node_modules/undici/lib/core/errors.js +20 -0
  114. package/node_modules/undici/lib/core/request.js +14 -3
  115. package/node_modules/undici/lib/core/util.js +30 -2
  116. package/node_modules/undici/lib/dispatcher/agent.js +3 -3
  117. package/node_modules/undici/lib/dispatcher/client-h1.js +65 -8
  118. package/node_modules/undici/lib/dispatcher/client-h2.js +265 -142
  119. package/node_modules/undici/lib/dispatcher/proxy-agent.js +40 -6
  120. package/node_modules/undici/lib/global.js +36 -16
  121. package/node_modules/undici/lib/handler/cache-handler.js +269 -61
  122. package/node_modules/undici/lib/handler/cache-revalidation-handler.js +13 -3
  123. package/node_modules/undici/lib/handler/redirect-handler.js +6 -2
  124. package/node_modules/undici/lib/handler/retry-handler.js +87 -23
  125. package/node_modules/undici/lib/interceptor/cache.js +159 -52
  126. package/node_modules/undici/lib/interceptor/decompress.js +9 -2
  127. package/node_modules/undici/lib/mock/mock-interceptor.js +25 -7
  128. package/node_modules/undici/lib/mock/mock-utils.js +39 -10
  129. package/node_modules/undici/lib/util/cache.js +372 -68
  130. package/node_modules/undici/lib/util/date.js +23 -6
  131. package/node_modules/undici/lib/web/cookies/parse.js +3 -2
  132. package/node_modules/undici/lib/web/cookies/util.js +79 -9
  133. package/node_modules/undici/lib/web/eventsource/util.js +1 -1
  134. package/node_modules/undici/lib/web/fetch/body.js +2 -1
  135. package/node_modules/undici/lib/web/fetch/constants.js +1 -1
  136. package/node_modules/undici/lib/web/fetch/index.js +11 -2
  137. package/node_modules/undici/lib/web/fetch/response.js +1 -3
  138. package/node_modules/undici/lib/web/fetch/util.js +4 -1
  139. package/node_modules/undici/package.json +2 -2
  140. package/node_modules/undici/types/client.d.ts +3 -3
  141. package/node_modules/undici/types/cookies.d.ts +1 -1
  142. package/node_modules/undici/types/dispatcher.d.ts +3 -3
  143. package/node_modules/undici/types/errors.d.ts +10 -0
  144. package/node_modules/undici/types/handlers.d.ts +2 -0
  145. package/node_modules/undici/types/mock-interceptor.d.ts +5 -1
  146. package/node_modules/undici/types/proxy-agent.d.ts +7 -0
  147. package/npm-shrinkwrap.json +7 -7
  148. package/package.json +5 -5
  149. package/dist/gateway-registry-DPxmW0Db.js +0 -74
  150. package/dist/provider.runtime-jNlHxUSW.js +0 -2
  151. package/dist/runtime-api.monitor-Bb5AaRzg.js +0 -6
  152. package/dist/targets-ClUPljCU.js +0 -3
@@ -0,0 +1,414 @@
1
+ # Interceptors
2
+
3
+ Undici ships with a set of built-in interceptors that can be composed via
4
+ `dispatcher.compose()` to add cross-cutting behaviour such as automatic
5
+ retries, response decompression, redirect following, DNS caching, and more.
6
+
7
+ ## Usage
8
+
9
+ ```js
10
+ import { Agent, interceptors } from 'undici'
11
+
12
+ const { retry, redirect, decompress, dump, responseError, dns, cache, deduplicate } = interceptors
13
+
14
+ const agent = new Agent().compose([
15
+ retry({ maxRetries: 3 }),
16
+ redirect({ maxRedirections: 5 }),
17
+ decompress()
18
+ ])
19
+
20
+ const response = await agent.request({ origin: 'https://example.com', path: '/', method: 'GET' })
21
+ ```
22
+
23
+ You can also apply interceptors to a single `Client` or `Pool`:
24
+
25
+ ```js
26
+ import { Client, interceptors } from 'undici'
27
+
28
+ const client = new Client('https://example.com').compose(
29
+ interceptors.retry({ maxRetries: 2 })
30
+ )
31
+ ```
32
+
33
+ ---
34
+
35
+ ## Custom interceptors
36
+
37
+ Custom interceptors use the same shape as
38
+ [`dispatcher.compose()`](./Dispatcher.md#dispatchercomposeinterceptors-interceptor):
39
+ an interceptor takes a `dispatch` function and returns another dispatch-like
40
+ function with the same `(options, handler)` signature.
41
+
42
+ When an interceptor wraps the handler, forward the callbacks that it does not
43
+ handle itself. The complete handler callback list is documented under
44
+ [`dispatcher.dispatch(options, handler)`](./Dispatcher.md#dispatcherdispatchoptions-handler).
45
+
46
+ ```js
47
+ import { Agent } from 'undici'
48
+
49
+ const timingInterceptor = dispatch => {
50
+ return (options, handler) => {
51
+ const started = performance.now()
52
+
53
+ return dispatch(options, {
54
+ ...handler,
55
+ onResponseStart (controller, statusCode, headers, statusMessage) {
56
+ const duration = Math.round(performance.now() - started)
57
+ const method = options.method ?? 'GET'
58
+ const origin = options.origin ?? ''
59
+
60
+ console.log(`${method} ${origin}${options.path} -> ${statusCode} in ${duration}ms`)
61
+
62
+ return handler.onResponseStart?.(
63
+ controller,
64
+ statusCode,
65
+ headers,
66
+ statusMessage
67
+ )
68
+ },
69
+ onResponseError (controller, error) {
70
+ const duration = Math.round(performance.now() - started)
71
+
72
+ console.error(`request failed after ${duration}ms`, error)
73
+
74
+ return handler.onResponseError?.(controller, error)
75
+ }
76
+ })
77
+ }
78
+ }
79
+
80
+ const dispatcher = new Agent().compose(timingInterceptor)
81
+
82
+ const { body } = await dispatcher.request({
83
+ origin: 'https://example.com',
84
+ path: '/',
85
+ method: 'GET'
86
+ })
87
+
88
+ await body.dump()
89
+ await dispatcher.close()
90
+ ```
91
+
92
+ ---
93
+
94
+ ## `interceptors.dump([opts])`
95
+
96
+ Reads and discards the response body up to a configurable size limit. Useful
97
+ for keeping a connection alive after an error response without reading the
98
+ body yourself.
99
+
100
+ **Parameters**
101
+
102
+ * `opts` {Object} (optional)
103
+ * `maxSize` {number} Maximum number of bytes to read and discard. Responses
104
+ whose `Content-Length` exceeds this value are aborted. **Default:**
105
+ `1_048_576` (1 MiB).
106
+
107
+ Per-request override: set `dumpMaxSize` on the dispatch options to override
108
+ the global `maxSize` for a specific request.
109
+
110
+ **Returns:** {Dispatcher.DispatcherComposeInterceptor}
111
+
112
+ **Example**
113
+
114
+ ```js
115
+ import { Agent, interceptors } from 'undici'
116
+
117
+ const agent = new Agent().compose(
118
+ interceptors.dump({ maxSize: 128 * 1024 }) // discard up to 128 KiB
119
+ )
120
+ ```
121
+
122
+ ---
123
+
124
+ ## `interceptors.retry([opts])`
125
+
126
+ Automatically retries failed requests using the same options accepted by
127
+ [`RetryHandler`](./RetryHandler.md).
128
+
129
+ **Parameters**
130
+
131
+ * `opts` {RetryHandler.RetryOptions} (optional) Global retry options applied
132
+ to every request. Individual requests can override via `opts.retryOptions`.
133
+ See [`RetryOptions`](./RetryHandler.md#retryoptions) for the full list of
134
+ accepted fields.
135
+
136
+ **Returns:** {Dispatcher.DispatcherComposeInterceptor}
137
+
138
+ **Example**
139
+
140
+ ```js
141
+ import { Agent, interceptors } from 'undici'
142
+
143
+ const agent = new Agent().compose(
144
+ interceptors.retry({
145
+ maxRetries: 5,
146
+ minTimeout: 200,
147
+ maxTimeout: 5000,
148
+ timeoutFactor: 2,
149
+ statusCodes: [429, 502, 503, 504]
150
+ })
151
+ )
152
+ ```
153
+
154
+ ---
155
+
156
+ ## `interceptors.redirect([opts])`
157
+
158
+ Follows HTTP redirects (3xx responses) automatically.
159
+
160
+ **Parameters**
161
+
162
+ * `opts` {Object} (optional)
163
+ * `maxRedirections` {number} Maximum number of redirects to follow. Passing
164
+ `0` disables redirect following entirely. **Default:** `undefined`
165
+ (inherits from the per-request `maxRedirections` option).
166
+ * `throwOnMaxRedirect` {boolean} When `true`, throws an error once the
167
+ redirect limit is reached instead of returning the final redirect response.
168
+ **Default:** `false`.
169
+ * `stripHeadersOnRedirect` {string[]} List of header names to remove from
170
+ the request when following any redirect. **Default:** `[]`.
171
+ * `stripHeadersOnCrossOriginRedirect` {string[]} List of header names to
172
+ remove from the request when following a cross-origin redirect (i.e. the
173
+ redirect target has a different origin). Useful for stripping
174
+ `Authorization` on cross-origin hops. **Default:** `[]`.
175
+
176
+ Per-request override: any of the four options above can also be set directly
177
+ on the dispatch options to override the interceptor defaults for a specific
178
+ request.
179
+
180
+ **Returns:** {Dispatcher.DispatcherComposeInterceptor}
181
+
182
+ **Example**
183
+
184
+ ```js
185
+ import { Agent, interceptors } from 'undici'
186
+
187
+ const agent = new Agent().compose(
188
+ interceptors.redirect({
189
+ maxRedirections: 10,
190
+ throwOnMaxRedirect: true,
191
+ stripHeadersOnCrossOriginRedirect: ['authorization', 'cookie']
192
+ })
193
+ )
194
+ ```
195
+
196
+ ---
197
+
198
+ ## `interceptors.decompress([opts])`
199
+
200
+ Automatically decompresses response bodies encoded with `gzip`, `x-gzip`,
201
+ `br` (Brotli), `deflate`, `compress`, `x-compress`, or `zstd`.
202
+
203
+ > **Experimental:** This interceptor is experimental and subject to change.
204
+ > A one-time `ExperimentalWarning` is emitted on first use.
205
+
206
+ **Parameters**
207
+
208
+ * `opts` {Object} (optional)
209
+ * `skipStatusCodes` {number[]} Status codes for which decompression is
210
+ skipped. **Default:** `[204, 304]`.
211
+ * `skipErrorResponses` {boolean} When `true`, responses with a status code
212
+ >= 400 are not decompressed. **Default:** `true`.
213
+
214
+ **Returns:** {Dispatcher.DispatcherComposeInterceptor}
215
+
216
+ **Example**
217
+
218
+ ```js
219
+ import { Agent, interceptors } from 'undici'
220
+
221
+ const agent = new Agent().compose(
222
+ interceptors.decompress({
223
+ skipStatusCodes: [204, 304],
224
+ skipErrorResponses: false // decompress error bodies too
225
+ })
226
+ )
227
+ ```
228
+
229
+ ---
230
+
231
+ ## `interceptors.responseError([opts])`
232
+
233
+ Converts 4xx/5xx responses into thrown `ResponseError` instances, making it
234
+ easy to handle HTTP errors with a standard `try/catch` block.
235
+
236
+ The error body is automatically decoded for `application/json` and
237
+ `text/plain` responses. For JSON responses the body is parsed and exposed as
238
+ `error.body`.
239
+
240
+ **Parameters**
241
+
242
+ * `opts` {Object} (optional) — currently reserved for future use; may be
243
+ omitted.
244
+
245
+ **Returns:** {Dispatcher.DispatcherComposeInterceptor}
246
+
247
+ **Example**
248
+
249
+ ```js
250
+ import { Agent, interceptors, errors } from 'undici'
251
+
252
+ const agent = new Agent().compose(interceptors.responseError())
253
+
254
+ try {
255
+ await agent.request({ origin: 'https://example.com', path: '/not-found', method: 'GET' })
256
+ } catch (err) {
257
+ if (err instanceof errors.ResponseError) {
258
+ console.error(err.status, err.body)
259
+ }
260
+ }
261
+ ```
262
+
263
+ ---
264
+
265
+ ## `interceptors.dns([opts])`
266
+
267
+ Caches DNS lookups so that repeated requests to the same origin reuse the
268
+ resolved IP address instead of performing a fresh lookup every time. Supports
269
+ dual-stack (IPv4 + IPv6) and custom lookup/storage implementations.
270
+
271
+ **Parameters**
272
+
273
+ * `opts` {Object} (optional)
274
+ * `maxTTL` {number} Maximum number of milliseconds a DNS record is cached,
275
+ regardless of the TTL returned by the resolver. **Default:** `0`
276
+ (use the TTL from the DNS record).
277
+ * `maxItems` {number} Maximum number of origins to cache simultaneously.
278
+ Oldest entries are evicted when the limit is reached. **Default:**
279
+ `Infinity`.
280
+ * `dualStack` {boolean} When `true`, both IPv4 (`A`) and IPv6 (`AAAA`)
281
+ records are looked up and the interceptor picks between them based on
282
+ `affinity`. **Default:** `true`.
283
+ * `affinity` {4 | 6 | null} Preferred IP family when `dualStack` is
284
+ enabled. `null` lets the interceptor alternate between families.
285
+ **Default:** `null`.
286
+ * `lookup` {Function} (optional) Custom DNS resolution function with the
287
+ same signature as `node:dns`'s `lookup` callback form:
288
+ `(origin, options, callback) => void`.
289
+ * `pick` {Function} (optional) Custom record-selection function called with
290
+ `(origin, records, affinity)` to choose which resolved address to use.
291
+ * `storage` {DNSStorage} (optional) Custom storage backend. Must implement
292
+ `get`, `set`, `delete`, `full`, and `size`.
293
+
294
+ **`DNSStorage` interface**
295
+
296
+ ```ts
297
+ interface DNSStorage {
298
+ size: number
299
+ get(origin: string): DNSInterceptorOriginRecords | null
300
+ set(origin: string, records: DNSInterceptorOriginRecords | null, options: { ttl: number }): void
301
+ delete(origin: string): void
302
+ full(): boolean
303
+ }
304
+ ```
305
+
306
+ **Returns:** {Dispatcher.DispatcherComposeInterceptor}
307
+
308
+ **Example**
309
+
310
+ ```js
311
+ import { Agent, interceptors } from 'undici'
312
+
313
+ const agent = new Agent().compose(
314
+ interceptors.dns({
315
+ maxTTL: 60_000, // cache for at most 60 seconds
316
+ dualStack: true,
317
+ affinity: 4 // prefer IPv4
318
+ })
319
+ )
320
+ ```
321
+
322
+ ---
323
+
324
+ ## `interceptors.cache([opts])`
325
+
326
+ Caches HTTP responses according to RFC 9111 (HTTP Caching). See
327
+ [`CacheStore`](./CacheStore.md) for information on providing a custom
328
+ backing store.
329
+
330
+ **Parameters**
331
+
332
+ * `opts` {CacheHandler.CacheOptions} (optional) See the
333
+ [`CacheStore`](./CacheStore.md) documentation for accepted fields.
334
+
335
+ **Returns:** {Dispatcher.DispatcherComposeInterceptor}
336
+
337
+ **Example**
338
+
339
+ ```js
340
+ import { Agent, interceptors, cacheStores } from 'undici'
341
+
342
+ const agent = new Agent().compose(
343
+ interceptors.cache({ store: new cacheStores.MemoryCacheStore() })
344
+ )
345
+ ```
346
+
347
+ ---
348
+
349
+ ## `interceptors.deduplicate([opts])`
350
+
351
+ Deduplicates concurrent identical requests so that only one is sent over the
352
+ wire. All waiting callers receive the same response once the in-flight request
353
+ completes. Only safe HTTP methods (e.g. `GET`, `HEAD`) may be deduplicated.
354
+
355
+ **Parameters**
356
+
357
+ * `opts` {Object} (optional)
358
+ * `methods` {string[]} HTTP methods to deduplicate. Must be safe HTTP
359
+ methods (`GET`, `HEAD`, `OPTIONS`, `TRACE`). **Default:** `['GET']`.
360
+ * `skipHeaderNames` {string[]} Header names whose presence in a request
361
+ causes it to bypass deduplication entirely. Matching is
362
+ case-insensitive. **Default:** `[]`.
363
+ * `excludeHeaderNames` {string[]} Header names to exclude from the
364
+ deduplication key. Requests that differ only in these headers are still
365
+ deduplicated together. Useful for headers like `x-request-id` that vary
366
+ per request but should not prevent deduplication. Matching is
367
+ case-insensitive. **Default:** `[]`.
368
+ * `maxBufferSize` {number} Maximum number of bytes buffered per paused
369
+ waiting handler. If a waiting handler exceeds this threshold it is failed
370
+ with an `AbortError` to prevent unbounded memory growth. **Default:**
371
+ `5_242_880` (5 MiB).
372
+
373
+ **Returns:** {Dispatcher.DispatcherComposeInterceptor}
374
+
375
+ **Example**
376
+
377
+ ```js
378
+ import { Agent, interceptors } from 'undici'
379
+
380
+ const agent = new Agent().compose(
381
+ interceptors.deduplicate({
382
+ methods: ['GET', 'HEAD'],
383
+ excludeHeaderNames: ['x-request-id', 'x-trace-id'],
384
+ maxBufferSize: 2 * 1024 * 1024
385
+ })
386
+ )
387
+ ```
388
+
389
+ ---
390
+
391
+ ## Composing multiple interceptors
392
+
393
+ Interceptors are applied in the order they appear in the `compose()` call.
394
+ The first interceptor in the array wraps the outermost layer.
395
+
396
+ ```js
397
+ import { Agent, interceptors } from 'undici'
398
+
399
+ const agent = new Agent().compose([
400
+ interceptors.dns({ maxTTL: 30_000 }),
401
+ interceptors.retry({ maxRetries: 3 }),
402
+ interceptors.redirect({ maxRedirections: 5 }),
403
+ interceptors.decompress(),
404
+ interceptors.responseError()
405
+ ])
406
+ ```
407
+
408
+ In the example above the request flow is:
409
+
410
+ 1. **dns** — resolves and caches the target IP
411
+ 2. **retry** — retries the dispatch on transient failures
412
+ 3. **redirect** — follows any 3xx redirects
413
+ 4. **decompress** — decompresses the response body
414
+ 5. **responseError** — converts 4xx/5xx into thrown errors