nlcurl 0.5.0 → 0.7.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 (178) hide show
  1. package/README.md +41 -8
  2. package/dist/cache/store.d.ts +89 -0
  3. package/dist/cache/store.d.ts.map +1 -0
  4. package/dist/cache/store.js +402 -0
  5. package/dist/cache/store.js.map +1 -0
  6. package/dist/cache/types.d.ts +101 -0
  7. package/dist/cache/types.d.ts.map +1 -0
  8. package/dist/cache/types.js +2 -0
  9. package/dist/cache/types.js.map +1 -0
  10. package/dist/cookies/jar.d.ts +20 -0
  11. package/dist/cookies/jar.d.ts.map +1 -1
  12. package/dist/cookies/jar.js +64 -10
  13. package/dist/cookies/jar.js.map +1 -1
  14. package/dist/cookies/parser.d.ts +2 -10
  15. package/dist/cookies/parser.d.ts.map +1 -1
  16. package/dist/cookies/parser.js +49 -2
  17. package/dist/cookies/parser.js.map +1 -1
  18. package/dist/cookies/psl-data.d.ts +12 -0
  19. package/dist/cookies/psl-data.d.ts.map +1 -0
  20. package/dist/cookies/psl-data.js +10166 -0
  21. package/dist/cookies/psl-data.js.map +1 -0
  22. package/dist/cookies/public-suffix.d.ts +37 -0
  23. package/dist/cookies/public-suffix.d.ts.map +1 -0
  24. package/dist/cookies/public-suffix.js +140 -0
  25. package/dist/cookies/public-suffix.js.map +1 -0
  26. package/dist/core/client.js +4 -0
  27. package/dist/core/client.js.map +1 -1
  28. package/dist/core/request.d.ts +73 -3
  29. package/dist/core/request.d.ts.map +1 -1
  30. package/dist/core/response.d.ts +22 -0
  31. package/dist/core/response.d.ts.map +1 -1
  32. package/dist/core/response.js +32 -0
  33. package/dist/core/response.js.map +1 -1
  34. package/dist/core/session.d.ts +23 -0
  35. package/dist/core/session.d.ts.map +1 -1
  36. package/dist/core/session.js +108 -4
  37. package/dist/core/session.js.map +1 -1
  38. package/dist/core/validation.d.ts +11 -0
  39. package/dist/core/validation.d.ts.map +1 -1
  40. package/dist/core/validation.js +22 -1
  41. package/dist/core/validation.js.map +1 -1
  42. package/dist/dns/codec.d.ts +37 -0
  43. package/dist/dns/codec.d.ts.map +1 -0
  44. package/dist/dns/codec.js +254 -0
  45. package/dist/dns/codec.js.map +1 -0
  46. package/dist/dns/doh-resolver.d.ts +52 -0
  47. package/dist/dns/doh-resolver.d.ts.map +1 -0
  48. package/dist/dns/doh-resolver.js +192 -0
  49. package/dist/dns/doh-resolver.js.map +1 -0
  50. package/dist/dns/https-rr.d.ts +51 -0
  51. package/dist/dns/https-rr.d.ts.map +1 -0
  52. package/dist/dns/https-rr.js +127 -0
  53. package/dist/dns/https-rr.js.map +1 -0
  54. package/dist/dns/types.d.ts +110 -0
  55. package/dist/dns/types.d.ts.map +1 -0
  56. package/dist/dns/types.js +34 -0
  57. package/dist/dns/types.js.map +1 -0
  58. package/dist/hsts/store.d.ts +41 -0
  59. package/dist/hsts/store.d.ts.map +1 -0
  60. package/dist/hsts/store.js +171 -0
  61. package/dist/hsts/store.js.map +1 -0
  62. package/dist/hsts/types.d.ts +28 -0
  63. package/dist/hsts/types.d.ts.map +1 -0
  64. package/dist/hsts/types.js +2 -0
  65. package/dist/hsts/types.js.map +1 -0
  66. package/dist/http/alt-svc.d.ts +85 -0
  67. package/dist/http/alt-svc.d.ts.map +1 -0
  68. package/dist/http/alt-svc.js +220 -0
  69. package/dist/http/alt-svc.js.map +1 -0
  70. package/dist/http/form-data.d.ts +59 -0
  71. package/dist/http/form-data.d.ts.map +1 -0
  72. package/dist/http/form-data.js +90 -0
  73. package/dist/http/form-data.js.map +1 -0
  74. package/dist/http/h1/client.d.ts.map +1 -1
  75. package/dist/http/h1/client.js +21 -3
  76. package/dist/http/h1/client.js.map +1 -1
  77. package/dist/http/h1/encoder.d.ts +17 -0
  78. package/dist/http/h1/encoder.d.ts.map +1 -1
  79. package/dist/http/h1/encoder.js +53 -5
  80. package/dist/http/h1/encoder.js.map +1 -1
  81. package/dist/http/h1/parser.d.ts.map +1 -1
  82. package/dist/http/h1/parser.js +7 -1
  83. package/dist/http/h1/parser.js.map +1 -1
  84. package/dist/http/h2/client.d.ts.map +1 -1
  85. package/dist/http/h2/client.js +58 -8
  86. package/dist/http/h2/client.js.map +1 -1
  87. package/dist/http/h2/hpack.d.ts +7 -0
  88. package/dist/http/h2/hpack.d.ts.map +1 -1
  89. package/dist/http/h2/hpack.js +13 -0
  90. package/dist/http/h2/hpack.js.map +1 -1
  91. package/dist/http/h3/detection.d.ts +17 -0
  92. package/dist/http/h3/detection.d.ts.map +1 -0
  93. package/dist/http/h3/detection.js +59 -0
  94. package/dist/http/h3/detection.js.map +1 -0
  95. package/dist/http/negotiator.d.ts +26 -1
  96. package/dist/http/negotiator.d.ts.map +1 -1
  97. package/dist/http/negotiator.js +93 -18
  98. package/dist/http/negotiator.js.map +1 -1
  99. package/dist/http/pool.d.ts +2 -2
  100. package/dist/http/pool.d.ts.map +1 -1
  101. package/dist/http/pool.js.map +1 -1
  102. package/dist/index.d.ts +19 -1
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +14 -0
  105. package/dist/index.js.map +1 -1
  106. package/dist/middleware/rate-limiter.d.ts.map +1 -1
  107. package/dist/middleware/rate-limiter.js +4 -0
  108. package/dist/middleware/rate-limiter.js.map +1 -1
  109. package/dist/middleware/retry.js +2 -2
  110. package/dist/middleware/retry.js.map +1 -1
  111. package/dist/proxy/env-proxy.d.ts +21 -0
  112. package/dist/proxy/env-proxy.d.ts.map +1 -0
  113. package/dist/proxy/env-proxy.js +74 -0
  114. package/dist/proxy/env-proxy.js.map +1 -0
  115. package/dist/proxy/http-proxy.d.ts +2 -0
  116. package/dist/proxy/http-proxy.d.ts.map +1 -1
  117. package/dist/proxy/http-proxy.js +29 -6
  118. package/dist/proxy/http-proxy.js.map +1 -1
  119. package/dist/proxy/socks.js +10 -1
  120. package/dist/proxy/socks.js.map +1 -1
  121. package/dist/sse/parser.d.ts +70 -0
  122. package/dist/sse/parser.d.ts.map +1 -0
  123. package/dist/sse/parser.js +153 -0
  124. package/dist/sse/parser.js.map +1 -0
  125. package/dist/tls/ech.d.ts +147 -0
  126. package/dist/tls/ech.d.ts.map +1 -0
  127. package/dist/tls/ech.js +401 -0
  128. package/dist/tls/ech.js.map +1 -0
  129. package/dist/tls/node-engine.d.ts +9 -1
  130. package/dist/tls/node-engine.d.ts.map +1 -1
  131. package/dist/tls/node-engine.js +54 -1
  132. package/dist/tls/node-engine.js.map +1 -1
  133. package/dist/tls/pin-verification.d.ts +9 -0
  134. package/dist/tls/pin-verification.d.ts.map +1 -0
  135. package/dist/tls/pin-verification.js +34 -0
  136. package/dist/tls/pin-verification.js.map +1 -0
  137. package/dist/tls/session-cache.d.ts +70 -0
  138. package/dist/tls/session-cache.d.ts.map +1 -0
  139. package/dist/tls/session-cache.js +80 -0
  140. package/dist/tls/session-cache.js.map +1 -0
  141. package/dist/tls/stealth/client-hello.d.ts +21 -0
  142. package/dist/tls/stealth/client-hello.d.ts.map +1 -1
  143. package/dist/tls/stealth/client-hello.js +116 -0
  144. package/dist/tls/stealth/client-hello.js.map +1 -1
  145. package/dist/tls/stealth/engine.d.ts.map +1 -1
  146. package/dist/tls/stealth/engine.js +152 -30
  147. package/dist/tls/stealth/engine.js.map +1 -1
  148. package/dist/tls/stealth/handshake.d.ts +2 -1
  149. package/dist/tls/stealth/handshake.d.ts.map +1 -1
  150. package/dist/tls/stealth/handshake.js +118 -5
  151. package/dist/tls/stealth/handshake.js.map +1 -1
  152. package/dist/tls/stealth/tls12-handshake.d.ts +14 -0
  153. package/dist/tls/stealth/tls12-handshake.d.ts.map +1 -0
  154. package/dist/tls/stealth/tls12-handshake.js +462 -0
  155. package/dist/tls/stealth/tls12-handshake.js.map +1 -0
  156. package/dist/tls/types.d.ts +40 -0
  157. package/dist/tls/types.d.ts.map +1 -1
  158. package/dist/utils/encoding.d.ts +8 -6
  159. package/dist/utils/encoding.d.ts.map +1 -1
  160. package/dist/utils/encoding.js +92 -24
  161. package/dist/utils/encoding.js.map +1 -1
  162. package/dist/utils/happy-eyeballs.d.ts +3 -0
  163. package/dist/utils/happy-eyeballs.d.ts.map +1 -1
  164. package/dist/utils/happy-eyeballs.js +42 -2
  165. package/dist/utils/happy-eyeballs.js.map +1 -1
  166. package/dist/ws/client.d.ts +3 -0
  167. package/dist/ws/client.d.ts.map +1 -1
  168. package/dist/ws/client.js +63 -7
  169. package/dist/ws/client.js.map +1 -1
  170. package/dist/ws/frame.d.ts +4 -2
  171. package/dist/ws/frame.d.ts.map +1 -1
  172. package/dist/ws/frame.js +18 -18
  173. package/dist/ws/frame.js.map +1 -1
  174. package/dist/ws/permessage-deflate.d.ts +58 -0
  175. package/dist/ws/permessage-deflate.d.ts.map +1 -0
  176. package/dist/ws/permessage-deflate.js +148 -0
  177. package/dist/ws/permessage-deflate.js.map +1 -0
  178. package/package.json +3 -2
package/README.md CHANGED
@@ -11,10 +11,14 @@ NLcURL provides session-based and one-shot HTTP APIs, browser profile impersonat
11
11
  - HTTP/1.1 and HTTP/2 (ALPN negotiated) with RFC 9113 flow control
12
12
  - Browser profile impersonation (Chrome, Firefox, Safari, Edge, Tor)
13
13
  - Optional custom JA3 and Akamai H2 fingerprint values in request model
14
- - Cookie jar with RFC 6265-like behavior; `Set-Cookie` headers preserved individually via `getAll()`
14
+ - Cookie jar with RFC 6265 behavior, Public Suffix List enforcement, `SameSite=Lax` default, and `__Host-`/`__Secure-` prefix validation
15
+ - `FormData` class for `multipart/form-data` uploads (RFC 7578)
16
+ - mTLS and custom CA trust via `TLSOptions` (`cert`, `key`, `pfx`, `ca`, `passphrase`)
17
+ - `ReadableStream<Uint8Array>` upload bodies (auto-drained before encoding)
18
+ - Header validation per RFC 7230 (rejects CR/LF/NUL injection)
15
19
  - Streaming response support (`stream: true`) with automatic decompression
16
20
  - Automatic dual-stack connectivity via Happy Eyeballs (RFC 8305) — falls back to IPv4 instantly when IPv6 is unreachable, with optional `dnsFamily` pin
17
- - Automatic retry on H2 RST_STREAM protocol errors (codes 1, 2, 7, 11)
21
+ - Automatic retry on H2 RST_STREAM protocol errors (codes 1, 2, 7, 8, 11, 13) with capped exponential backoff
18
22
  - CLI (`nlcurl`) for scripted and interactive use
19
23
  - WebSocket client with optional impersonated TLS handshake
20
24
 
@@ -52,6 +56,34 @@ console.log(response.status);
52
56
  console.log(response.json());
53
57
  ```
54
58
 
59
+ ### Multipart form upload
60
+
61
+ ```ts
62
+ import { post, FormData } from "nlcurl";
63
+
64
+ const form = new FormData();
65
+ form.append("username", "alice");
66
+ form.append("avatar", { data: Buffer.from("..."), filename: "avatar.png", contentType: "image/png" });
67
+
68
+ const res = await post("https://httpbin.org/post", form);
69
+ console.log(res.json());
70
+ ```
71
+
72
+ ### mTLS / custom CA
73
+
74
+ ```ts
75
+ import { request } from "nlcurl";
76
+
77
+ const res = await request({
78
+ url: "https://internal-api.example.com/data",
79
+ tls: {
80
+ cert: fs.readFileSync("client.pem"),
81
+ key: fs.readFileSync("client-key.pem"),
82
+ ca: fs.readFileSync("ca.pem"),
83
+ },
84
+ });
85
+ ```
86
+
55
87
  ### Session-based usage
56
88
 
57
89
  ```ts
@@ -142,12 +174,13 @@ Additional commands:
142
174
 
143
175
  ## Documentation Index
144
176
 
145
- - `docs/API.md`: exported API reference
146
- - `docs/MODULES.md`: module-by-module usage guide
147
- - `docs/ARCHITECTURE.md`: system architecture and request flow
148
- - `docs/SETUP.md`: setup, build, and test instructions
149
- - `docs/CONFIGURATION.md`: request/session/CLI configuration
150
- - `docs/ONBOARDING.md`: contributor onboarding guide
177
+ - `docs/API.md` exported API reference
178
+ - `docs/MODULES.md` module-by-module usage guide
179
+ - `docs/ARCHITECTURE.md` system architecture and request flow
180
+ - `docs/SETUP.md` setup, build, and test instructions
181
+ - `docs/CONFIGURATION.md` request/session/CLI configuration
182
+ - `docs/EXAMPLES.md` comprehensive usage examples (API + CLI)
183
+ - `docs/ONBOARDING.md` — contributor onboarding guide
151
184
 
152
185
  ## License
153
186
 
@@ -0,0 +1,89 @@
1
+ import type { CacheConfig, CacheDirectives, CacheEntry, CacheLookupResult, CacheMode } from "./types.js";
2
+ import type { NLcURLRequest } from "../core/request.js";
3
+ import { NLcURLResponse } from "../core/response.js";
4
+ /**
5
+ * In-memory HTTP response cache implementing RFC 9111.
6
+ *
7
+ * Features:
8
+ * - Cache-Control directive parsing and freshness calculation
9
+ * - ETag / Last-Modified conditional request header injection
10
+ * - 304 Not Modified response merging
11
+ * - Vary header support
12
+ * - LRU eviction by entry count and total body size
13
+ * - Range request passthrough (does not cache partial responses by default)
14
+ */
15
+ export declare class CacheStore {
16
+ private readonly entries;
17
+ private readonly maxEntries;
18
+ private readonly maxSize;
19
+ private currentSize;
20
+ private readonly mode;
21
+ /** Monotonic counter for deterministic LRU ordering within the same ms. */
22
+ private accessCounter;
23
+ constructor(config?: CacheConfig);
24
+ /**
25
+ * Generates a cache key from a request. The key is `METHOD:URL`.
26
+ */
27
+ static cacheKey(method: string, url: string): string;
28
+ /**
29
+ * Looks up a cached response and evaluates its freshness.
30
+ *
31
+ * @param req - The outgoing request to match against cache.
32
+ * @returns A lookup result with the entry and freshness status.
33
+ */
34
+ lookup(req: NLcURLRequest): CacheLookupResult;
35
+ /**
36
+ * Determines what action to take for a request given the cache state
37
+ * and the configured cache mode.
38
+ *
39
+ * Returns conditional headers to add (If-None-Match / If-Modified-Since)
40
+ * when the entry is stale and needs revalidation.
41
+ */
42
+ evaluate(req: NLcURLRequest, modeOverride?: CacheMode): {
43
+ conditionalHeaders?: Record<string, string>;
44
+ shouldStore: boolean;
45
+ matchedEntry?: CacheEntry;
46
+ serveCached?: CacheEntry;
47
+ };
48
+ /**
49
+ * Stores a response in the cache if it is cacheable per RFC 9111 §3.
50
+ */
51
+ store(req: NLcURLRequest, response: NLcURLResponse): void;
52
+ /**
53
+ * Merges a 304 Not Modified response with a cached entry, producing
54
+ * a full response with updated headers.
55
+ */
56
+ mergeNotModified(entry: CacheEntry, response304: NLcURLResponse): NLcURLResponse;
57
+ /**
58
+ * Constructs a full NLcURLResponse from a cache entry for direct serving.
59
+ */
60
+ responseFromEntry(entry: CacheEntry, req: NLcURLRequest): NLcURLResponse;
61
+ /** Returns the number of cached entries. */
62
+ get size(): number;
63
+ /** Returns the total byte size of all cached response bodies. */
64
+ get totalSize(): number;
65
+ /** Clears all cached entries. */
66
+ clear(): void;
67
+ /**
68
+ * Removes a specific cache entry by method and URL.
69
+ */
70
+ delete(method: string, url: string): boolean;
71
+ /**
72
+ * Checks whether request headers match the stored Vary fields.
73
+ */
74
+ private varyMatches;
75
+ /**
76
+ * Finds the key of the least recently accessed entry.
77
+ */
78
+ private findLRUKey;
79
+ /**
80
+ * Evicts least-recently-used entries until there is room for a new entry
81
+ * of the given size.
82
+ */
83
+ private evictIfNeeded;
84
+ }
85
+ /**
86
+ * Parses a `Cache-Control` header value into structured directives.
87
+ */
88
+ export declare function parseCacheControl(value: string): CacheDirectives;
89
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/cache/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,UAAU,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACzG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAWrD;;;;;;;;;;GAUG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;IACjC,2EAA2E;IAC3E,OAAO,CAAC,aAAa,CAAK;gBAEd,MAAM,CAAC,EAAE,WAAW;IAMhC;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IAIpD;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,aAAa,GAAG,iBAAiB;IA8B7C;;;;;;OAMG;IACH,QAAQ,CACN,GAAG,EAAE,aAAa,EAClB,YAAY,CAAC,EAAE,SAAS,GACvB;QACD,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC5C,WAAW,EAAE,OAAO,CAAC;QACrB,YAAY,CAAC,EAAE,UAAU,CAAC;QAC1B,WAAW,CAAC,EAAE,UAAU,CAAC;KAC1B;IA6CD;;OAEG;IACH,KAAK,CAAC,GAAG,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI;IAyDzD;;;OAGG;IACH,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,GAAG,cAAc;IA0BhF;;OAEG;IACH,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,aAAa,GAAG,cAAc;IAcxE,4CAA4C;IAC5C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,iEAAiE;IACjE,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,iCAAiC;IACjC,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IAW5C;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB;;OAEG;IACH,OAAO,CAAC,UAAU;IAYlB;;;OAGG;IACH,OAAO,CAAC,aAAa;CAiBtB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,CA0EhE"}
@@ -0,0 +1,402 @@
1
+ import { NLcURLResponse } from "../core/response.js";
2
+ const DEFAULT_MAX_ENTRIES = 1000;
3
+ const DEFAULT_MAX_SIZE = 50 * 1024 * 1024;
4
+ /** HTTP methods whose responses may be cached (RFC 9111 §3). */
5
+ const CACHEABLE_METHODS = new Set(["GET", "HEAD"]);
6
+ /** Status codes that are cacheable by default (RFC 9111 §3). */
7
+ const CACHEABLE_STATUS = new Set([200, 203, 204, 206, 300, 301, 308, 404, 405, 410, 414, 501]);
8
+ /**
9
+ * In-memory HTTP response cache implementing RFC 9111.
10
+ *
11
+ * Features:
12
+ * - Cache-Control directive parsing and freshness calculation
13
+ * - ETag / Last-Modified conditional request header injection
14
+ * - 304 Not Modified response merging
15
+ * - Vary header support
16
+ * - LRU eviction by entry count and total body size
17
+ * - Range request passthrough (does not cache partial responses by default)
18
+ */
19
+ export class CacheStore {
20
+ entries = new Map();
21
+ maxEntries;
22
+ maxSize;
23
+ currentSize = 0;
24
+ mode;
25
+ /** Monotonic counter for deterministic LRU ordering within the same ms. */
26
+ accessCounter = 0;
27
+ constructor(config) {
28
+ this.maxEntries = config?.maxEntries ?? DEFAULT_MAX_ENTRIES;
29
+ this.maxSize = config?.maxSize ?? DEFAULT_MAX_SIZE;
30
+ this.mode = config?.mode ?? "default";
31
+ }
32
+ /**
33
+ * Generates a cache key from a request. The key is `METHOD:URL`.
34
+ */
35
+ static cacheKey(method, url) {
36
+ return `${method.toUpperCase()}:${url}`;
37
+ }
38
+ /**
39
+ * Looks up a cached response and evaluates its freshness.
40
+ *
41
+ * @param req - The outgoing request to match against cache.
42
+ * @returns A lookup result with the entry and freshness status.
43
+ */
44
+ lookup(req) {
45
+ const method = (req.method ?? "GET").toUpperCase();
46
+ if (!CACHEABLE_METHODS.has(method)) {
47
+ return { fresh: false, staleWhileRevalidate: false };
48
+ }
49
+ const key = CacheStore.cacheKey(method, req.url);
50
+ const entry = this.entries.get(key);
51
+ if (!entry) {
52
+ return { fresh: false, staleWhileRevalidate: false };
53
+ }
54
+ if (!this.varyMatches(entry, req)) {
55
+ return { fresh: false, staleWhileRevalidate: false };
56
+ }
57
+ entry.lastAccessedAt = ++this.accessCounter;
58
+ const age = (Date.now() - entry.storedAt) / 1000;
59
+ const freshness = computeFreshnessLifetime(entry);
60
+ const fresh = age < freshness;
61
+ let staleWhileRevalidate = false;
62
+ if (!fresh && entry.directives.staleWhileRevalidate !== undefined) {
63
+ staleWhileRevalidate = age < freshness + entry.directives.staleWhileRevalidate;
64
+ }
65
+ return { entry, fresh, staleWhileRevalidate };
66
+ }
67
+ /**
68
+ * Determines what action to take for a request given the cache state
69
+ * and the configured cache mode.
70
+ *
71
+ * Returns conditional headers to add (If-None-Match / If-Modified-Since)
72
+ * when the entry is stale and needs revalidation.
73
+ */
74
+ evaluate(req, modeOverride) {
75
+ const mode = modeOverride ?? this.mode;
76
+ if (mode === "no-store") {
77
+ return { shouldStore: false };
78
+ }
79
+ const result = this.lookup(req);
80
+ if (mode === "force-cache" && result.entry) {
81
+ return { serveCached: result.entry, shouldStore: false };
82
+ }
83
+ if (mode === "only-if-cached") {
84
+ if (result.entry) {
85
+ return { serveCached: result.entry, shouldStore: false };
86
+ }
87
+ return { shouldStore: false };
88
+ }
89
+ if (result.fresh && mode === "default") {
90
+ return { serveCached: result.entry, shouldStore: false };
91
+ }
92
+ const conditionalHeaders = {};
93
+ let matchedEntry;
94
+ if (result.entry) {
95
+ matchedEntry = result.entry;
96
+ if (result.entry.etag) {
97
+ conditionalHeaders["if-none-match"] = result.entry.etag;
98
+ }
99
+ if (result.entry.lastModified) {
100
+ conditionalHeaders["if-modified-since"] = result.entry.lastModified;
101
+ }
102
+ }
103
+ const hasConditional = Object.keys(conditionalHeaders).length > 0;
104
+ return {
105
+ conditionalHeaders: hasConditional ? conditionalHeaders : undefined,
106
+ shouldStore: true,
107
+ matchedEntry,
108
+ };
109
+ }
110
+ /**
111
+ * Stores a response in the cache if it is cacheable per RFC 9111 §3.
112
+ */
113
+ store(req, response) {
114
+ const method = (req.method ?? "GET").toUpperCase();
115
+ if (!CACHEABLE_METHODS.has(method))
116
+ return;
117
+ const directives = parseCacheControl(response.headers["cache-control"] ?? "");
118
+ if (directives.noStore)
119
+ return;
120
+ if (!CACHEABLE_STATUS.has(response.status) && directives.maxAge === undefined && directives.sMaxAge === undefined) {
121
+ return;
122
+ }
123
+ if (response.status === 206)
124
+ return;
125
+ const key = CacheStore.cacheKey(method, req.url);
126
+ const varyFields = parseVary(response.headers["vary"] ?? "");
127
+ if (varyFields.includes("*"))
128
+ return;
129
+ const varyHeaders = {};
130
+ for (const field of varyFields) {
131
+ varyHeaders[field] = req.headers?.[field] ?? "";
132
+ }
133
+ const bodySize = response.rawBody.length;
134
+ this.evictIfNeeded(bodySize);
135
+ const existing = this.entries.get(key);
136
+ if (existing) {
137
+ this.currentSize -= existing.bodySize;
138
+ this.entries.delete(key);
139
+ }
140
+ const now = Date.now();
141
+ const entry = {
142
+ key,
143
+ status: response.status,
144
+ statusText: response.statusText,
145
+ headers: { ...response.headers },
146
+ body: Buffer.from(response.rawBody),
147
+ httpVersion: response.httpVersion,
148
+ url: response.url,
149
+ storedAt: now,
150
+ etag: response.headers["etag"],
151
+ lastModified: response.headers["last-modified"],
152
+ directives,
153
+ varyFields,
154
+ varyHeaders,
155
+ bodySize,
156
+ lastAccessedAt: ++this.accessCounter,
157
+ };
158
+ this.entries.set(key, entry);
159
+ this.currentSize += bodySize;
160
+ }
161
+ /**
162
+ * Merges a 304 Not Modified response with a cached entry, producing
163
+ * a full response with updated headers.
164
+ */
165
+ mergeNotModified(entry, response304) {
166
+ const mergedHeaders = { ...entry.headers };
167
+ for (const [k, v] of Object.entries(response304.headers)) {
168
+ if (k === "content-length" || k === "content-encoding" || k === "transfer-encoding")
169
+ continue;
170
+ mergedHeaders[k] = v;
171
+ }
172
+ entry.headers = mergedHeaders;
173
+ entry.storedAt = Date.now();
174
+ if (response304.headers["etag"])
175
+ entry.etag = response304.headers["etag"];
176
+ if (response304.headers["last-modified"])
177
+ entry.lastModified = response304.headers["last-modified"];
178
+ entry.directives = parseCacheControl(mergedHeaders["cache-control"] ?? "");
179
+ return new NLcURLResponse({
180
+ status: entry.status,
181
+ statusText: entry.statusText,
182
+ headers: mergedHeaders,
183
+ rawBody: entry.body,
184
+ httpVersion: entry.httpVersion,
185
+ url: entry.url,
186
+ redirectCount: response304.redirectCount,
187
+ timings: response304.timings,
188
+ request: response304.request,
189
+ });
190
+ }
191
+ /**
192
+ * Constructs a full NLcURLResponse from a cache entry for direct serving.
193
+ */
194
+ responseFromEntry(entry, req) {
195
+ return new NLcURLResponse({
196
+ status: entry.status,
197
+ statusText: entry.statusText,
198
+ headers: { ...entry.headers },
199
+ rawBody: entry.body,
200
+ httpVersion: entry.httpVersion,
201
+ url: entry.url,
202
+ redirectCount: 0,
203
+ timings: { dns: 0, connect: 0, tls: 0, firstByte: 0, total: 0 },
204
+ request: { url: req.url, method: (req.method ?? "GET"), headers: req.headers ?? {} },
205
+ });
206
+ }
207
+ /** Returns the number of cached entries. */
208
+ get size() {
209
+ return this.entries.size;
210
+ }
211
+ /** Returns the total byte size of all cached response bodies. */
212
+ get totalSize() {
213
+ return this.currentSize;
214
+ }
215
+ /** Clears all cached entries. */
216
+ clear() {
217
+ this.entries.clear();
218
+ this.currentSize = 0;
219
+ }
220
+ /**
221
+ * Removes a specific cache entry by method and URL.
222
+ */
223
+ delete(method, url) {
224
+ const key = CacheStore.cacheKey(method, url);
225
+ const entry = this.entries.get(key);
226
+ if (entry) {
227
+ this.currentSize -= entry.bodySize;
228
+ this.entries.delete(key);
229
+ return true;
230
+ }
231
+ return false;
232
+ }
233
+ /**
234
+ * Checks whether request headers match the stored Vary fields.
235
+ */
236
+ varyMatches(entry, req) {
237
+ for (const field of entry.varyFields) {
238
+ const stored = entry.varyHeaders[field] ?? "";
239
+ const current = req.headers?.[field] ?? "";
240
+ if (stored !== current)
241
+ return false;
242
+ }
243
+ return true;
244
+ }
245
+ /**
246
+ * Finds the key of the least recently accessed entry.
247
+ */
248
+ findLRUKey() {
249
+ let lruKey;
250
+ let lruTime = Infinity;
251
+ for (const [key, entry] of this.entries) {
252
+ if (entry.lastAccessedAt < lruTime) {
253
+ lruTime = entry.lastAccessedAt;
254
+ lruKey = key;
255
+ }
256
+ }
257
+ return lruKey;
258
+ }
259
+ /**
260
+ * Evicts least-recently-used entries until there is room for a new entry
261
+ * of the given size.
262
+ */
263
+ evictIfNeeded(incomingSize) {
264
+ while (this.entries.size >= this.maxEntries) {
265
+ const lruKey = this.findLRUKey();
266
+ if (lruKey === undefined)
267
+ break;
268
+ const entry = this.entries.get(lruKey);
269
+ if (entry)
270
+ this.currentSize -= entry.bodySize;
271
+ this.entries.delete(lruKey);
272
+ }
273
+ while (this.currentSize + incomingSize > this.maxSize && this.entries.size > 0) {
274
+ const lruKey = this.findLRUKey();
275
+ if (lruKey === undefined)
276
+ break;
277
+ const entry = this.entries.get(lruKey);
278
+ if (entry)
279
+ this.currentSize -= entry.bodySize;
280
+ this.entries.delete(lruKey);
281
+ }
282
+ }
283
+ }
284
+ /**
285
+ * Parses a `Cache-Control` header value into structured directives.
286
+ */
287
+ export function parseCacheControl(value) {
288
+ const directives = {
289
+ noCache: false,
290
+ noStore: false,
291
+ mustRevalidate: false,
292
+ proxyRevalidate: false,
293
+ public: false,
294
+ private: false,
295
+ immutable: false,
296
+ };
297
+ if (!value)
298
+ return directives;
299
+ const parts = value.toLowerCase().split(",");
300
+ for (const part of parts) {
301
+ const trimmed = part.trim();
302
+ if (!trimmed)
303
+ continue;
304
+ const eqIdx = trimmed.indexOf("=");
305
+ const name = eqIdx === -1 ? trimmed : trimmed.slice(0, eqIdx).trim();
306
+ const val = eqIdx === -1
307
+ ? undefined
308
+ : trimmed
309
+ .slice(eqIdx + 1)
310
+ .trim()
311
+ .replace(/^"|"$/g, "");
312
+ switch (name) {
313
+ case "max-age": {
314
+ const n = parseInt(val ?? "", 10);
315
+ if (Number.isFinite(n) && n >= 0)
316
+ directives.maxAge = n;
317
+ break;
318
+ }
319
+ case "s-maxage": {
320
+ const n = parseInt(val ?? "", 10);
321
+ if (Number.isFinite(n) && n >= 0)
322
+ directives.sMaxAge = n;
323
+ break;
324
+ }
325
+ case "no-cache":
326
+ directives.noCache = true;
327
+ break;
328
+ case "no-store":
329
+ directives.noStore = true;
330
+ break;
331
+ case "must-revalidate":
332
+ directives.mustRevalidate = true;
333
+ break;
334
+ case "proxy-revalidate":
335
+ directives.proxyRevalidate = true;
336
+ break;
337
+ case "public":
338
+ directives.public = true;
339
+ break;
340
+ case "private":
341
+ directives.private = true;
342
+ break;
343
+ case "immutable":
344
+ directives.immutable = true;
345
+ break;
346
+ case "stale-while-revalidate": {
347
+ const n = parseInt(val ?? "", 10);
348
+ if (Number.isFinite(n) && n >= 0)
349
+ directives.staleWhileRevalidate = n;
350
+ break;
351
+ }
352
+ case "stale-if-error": {
353
+ const n = parseInt(val ?? "", 10);
354
+ if (Number.isFinite(n) && n >= 0)
355
+ directives.staleIfError = n;
356
+ break;
357
+ }
358
+ }
359
+ }
360
+ return directives;
361
+ }
362
+ /**
363
+ * Computes the freshness lifetime in seconds for a cache entry (RFC 9111 §4.2).
364
+ *
365
+ * Priority: Cache-Control max-age > Expires header > heuristic.
366
+ */
367
+ function computeFreshnessLifetime(entry) {
368
+ if (entry.directives.maxAge !== undefined) {
369
+ return entry.directives.maxAge;
370
+ }
371
+ const expires = entry.headers["expires"];
372
+ if (expires) {
373
+ const expTime = Date.parse(expires);
374
+ if (!Number.isNaN(expTime)) {
375
+ const dateHeader = entry.headers["date"];
376
+ const responseDate = dateHeader ? Date.parse(dateHeader) : entry.storedAt;
377
+ if (!Number.isNaN(responseDate)) {
378
+ return Math.max(0, (expTime - responseDate) / 1000);
379
+ }
380
+ }
381
+ }
382
+ if (entry.lastModified) {
383
+ const lmTime = Date.parse(entry.lastModified);
384
+ if (!Number.isNaN(lmTime)) {
385
+ const age = (entry.storedAt - lmTime) / 1000;
386
+ return Math.min(age * 0.1, 86400);
387
+ }
388
+ }
389
+ return 0;
390
+ }
391
+ /**
392
+ * Parses a Vary header into an array of lowercased field names.
393
+ */
394
+ function parseVary(value) {
395
+ if (!value)
396
+ return [];
397
+ return value
398
+ .split(",")
399
+ .map((v) => v.trim().toLowerCase())
400
+ .filter(Boolean);
401
+ }
402
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/cache/store.ts"],"names":[],"mappings":"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"}