@nxtedition/nxt-undici 7.4.2 → 7.5.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/lib/index.d.ts +27 -1
- package/lib/index.js +15 -0
- package/lib/interceptor/cache.js +667 -115
- package/lib/interceptor/dns.js +101 -2
- package/lib/interceptor/log.js +126 -59
- package/lib/interceptor/lookup.js +53 -1
- package/lib/interceptor/pressure.js +86 -3
- package/lib/interceptor/priority.js +73 -3
- package/lib/interceptor/proxy.js +4 -1
- package/lib/interceptor/redirect.js +26 -0
- package/lib/interceptor/response-retry.js +32 -2
- package/lib/interceptor/response-verify.js +36 -0
- package/lib/sqlite-cache-store.js +141 -15
- package/lib/trace.js +87 -0
- package/lib/utils.js +288 -8
- package/package.json +2 -2
package/lib/index.d.ts
CHANGED
|
@@ -55,6 +55,13 @@ export interface LoggerLike {
|
|
|
55
55
|
info(obj: unknown, msg?: string): void
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/** The @nxtedition/trace writer contract: `write` is the emit fn while tracing
|
|
59
|
+
* is enabled and null while disabled (it flips between the two at runtime).
|
|
60
|
+
* The per-thread fallback writer lives in the Symbol.for('@nxtedition/app/trace')
|
|
61
|
+
* slot and must be installed via the package's installTrace(). */
|
|
62
|
+
export type { TraceWriter } from '@nxtedition/trace'
|
|
63
|
+
import type { TraceWriter } from '@nxtedition/trace'
|
|
64
|
+
|
|
58
65
|
export type BodyFactoryResult =
|
|
59
66
|
| Readable
|
|
60
67
|
| Uint8Array
|
|
@@ -98,6 +105,10 @@ export interface DispatchOptions {
|
|
|
98
105
|
error?: boolean | null
|
|
99
106
|
verify?: VerifyOptions | boolean | null
|
|
100
107
|
logger?: LoggerLike | null
|
|
108
|
+
/** Per-request trace writer: undefined falls back to the per-thread writer
|
|
109
|
+
* installed via @nxtedition/trace's installTrace(), null disables tracing
|
|
110
|
+
* for this request. */
|
|
111
|
+
trace?: TraceWriter | null
|
|
101
112
|
dns?: DnsOptions | boolean | null
|
|
102
113
|
connect?: Record<string, unknown> | null
|
|
103
114
|
priority?: Priority | null
|
|
@@ -134,8 +145,15 @@ export interface ProxyOptions {
|
|
|
134
145
|
export interface CacheOptions {
|
|
135
146
|
store?: CacheStore
|
|
136
147
|
maxEntrySize?: number
|
|
137
|
-
/** Upper bound on an entry's freshness lifetime, in seconds
|
|
148
|
+
/** Upper bound on an entry's freshness lifetime AND retention, in seconds
|
|
149
|
+
* (default 30 days). */
|
|
138
150
|
maxEntryTTL?: number
|
|
151
|
+
/** Opt-in RFC 9111 §4.2.2 heuristic freshness (10% of time since
|
|
152
|
+
* Last-Modified) for 200 responses without explicit expiration. */
|
|
153
|
+
heuristic?: boolean
|
|
154
|
+
/** Opt-in fallback freshness lifetime in seconds for 200 responses without
|
|
155
|
+
* any expiration information. */
|
|
156
|
+
defaultTTL?: number
|
|
139
157
|
}
|
|
140
158
|
|
|
141
159
|
export interface VerifyOptions {
|
|
@@ -245,6 +263,8 @@ export interface CacheValue {
|
|
|
245
263
|
etag?: string
|
|
246
264
|
vary?: Record<string, string | string[]>
|
|
247
265
|
cachedAt: number
|
|
266
|
+
/** Optional on set(): omitting it defaults to deleteAt (staleAt === deleteAt). */
|
|
267
|
+
staleAt?: number
|
|
248
268
|
deleteAt?: number
|
|
249
269
|
}
|
|
250
270
|
|
|
@@ -257,6 +277,7 @@ export interface CacheGetResult {
|
|
|
257
277
|
cacheControlDirectives?: Record<string, unknown>
|
|
258
278
|
vary?: Record<string, string | string[]>
|
|
259
279
|
cachedAt: number
|
|
280
|
+
staleAt: number
|
|
260
281
|
deleteAt: number
|
|
261
282
|
}
|
|
262
283
|
|
|
@@ -266,6 +287,9 @@ export interface CacheStore {
|
|
|
266
287
|
key: CacheKey,
|
|
267
288
|
value: CacheValue & { body: null | Buffer | Buffer[]; start: number; end: number },
|
|
268
289
|
): void
|
|
290
|
+
/** RFC 9111 §4.4 invalidation — optional; the cache interceptor
|
|
291
|
+
* feature-detects it and skips invalidation when absent. */
|
|
292
|
+
delete?(key: CacheKey): void
|
|
269
293
|
gc(): void
|
|
270
294
|
clear(): void
|
|
271
295
|
close(): void
|
|
@@ -338,6 +362,8 @@ export class SqliteCacheStore implements CacheStore {
|
|
|
338
362
|
key: CacheKey,
|
|
339
363
|
value: CacheValue & { body: null | Buffer | Buffer[]; start: number; end: number },
|
|
340
364
|
): void
|
|
365
|
+
/** RFC 9111 §4.4: invalidates every stored response for the key's URI. */
|
|
366
|
+
delete(key: CacheKey): void
|
|
341
367
|
gc(): void
|
|
342
368
|
clear(): void
|
|
343
369
|
close(): void
|
package/lib/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { Scheduler } from '@nxtedition/scheduler'
|
|
|
4
4
|
import { parseHeaders } from './utils.js'
|
|
5
5
|
import { request as _request } from './request.js'
|
|
6
6
|
import { SqliteCacheStore } from './sqlite-cache-store.js'
|
|
7
|
+
import { validateTrace } from './trace.js'
|
|
7
8
|
|
|
8
9
|
const dispatcherCache = new WeakMap()
|
|
9
10
|
|
|
@@ -118,6 +119,13 @@ function wrapDispatch(dispatcher) {
|
|
|
118
119
|
interceptors.proxy(),
|
|
119
120
|
interceptors.cache(),
|
|
120
121
|
interceptors.redirect(),
|
|
122
|
+
// log also emits the undici:request trace start/end docs. Later entries
|
|
123
|
+
// in this list wrap earlier ones, so it sits OUTSIDE everything that
|
|
124
|
+
// does real work (redirect, cache, proxy, retry, dns) — durationMs
|
|
125
|
+
// spans the whole inner pipeline including retries, dns and cache
|
|
126
|
+
// lookups — but INSIDE requestId, so opts.id is already stamped and
|
|
127
|
+
// the emitted docs correlate with logs and undici:retry docs by
|
|
128
|
+
// request id.
|
|
121
129
|
interceptors.log(),
|
|
122
130
|
interceptors.lookup(),
|
|
123
131
|
interceptors.requestId(),
|
|
@@ -186,6 +194,13 @@ function wrapDispatch(dispatcher) {
|
|
|
186
194
|
error: opts.error ?? opts.throwOnError ?? true,
|
|
187
195
|
verify: opts.verify ?? { size: true, hash: false },
|
|
188
196
|
logger: opts.logger ?? null,
|
|
197
|
+
// Deliberately NOT defaulted: undefined means "fall back to the
|
|
198
|
+
// per-thread writer installed via installTrace()" (resolved lazily
|
|
199
|
+
// at each emission site — the writer may be installed after startup
|
|
200
|
+
// and its `write` flips at runtime), null means "tracing disabled
|
|
201
|
+
// for this request" (see lib/trace.js). Validation throws
|
|
202
|
+
// InvalidArgumentError for anything that is not a writer.
|
|
203
|
+
trace: validateTrace(opts.trace),
|
|
189
204
|
dns: opts.dns ?? true,
|
|
190
205
|
connect: opts.connect,
|
|
191
206
|
// A duplicated nxt-priority request header parses to an array; the
|