@isdk/proxy 0.1.1 โ 0.1.3
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/README.cn.md +249 -9
- package/README.md +249 -7
- package/dist/index.d.mts +374 -41
- package/dist/index.d.ts +374 -41
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/docs/README.md +249 -7
- package/docs/classes/OfflineCacheMissError.md +426 -0
- package/docs/classes/SmartCache.md +81 -13
- package/docs/functions/createCachedFetch.md +1 -1
- package/docs/functions/createFetchWithCache.md +1 -1
- package/docs/functions/extractData.md +34 -5
- package/docs/functions/fetchWithCache.md +18 -9
- package/docs/functions/generateCacheKey.md +34 -4
- package/docs/functions/getSiteConfig.md +39 -0
- package/docs/functions/isAllowed.md +35 -8
- package/docs/functions/isCacheable.md +27 -0
- package/docs/functions/isGlob.md +23 -0
- package/docs/functions/isMatch.md +44 -0
- package/docs/functions/prefetch.md +33 -0
- package/docs/globals.md +15 -0
- package/docs/interfaces/BodyFilterConfig.md +77 -0
- package/docs/interfaces/CacheEntry.md +9 -9
- package/docs/interfaces/CacheMetadata.md +8 -8
- package/docs/interfaces/CacheRule.md +80 -0
- package/docs/interfaces/FetchWithCacheContext.md +44 -16
- package/docs/interfaces/FetchWithCacheOptions.md +40 -12
- package/docs/interfaces/KeyFilterConfig.md +11 -7
- package/docs/interfaces/PrefetchOptions.md +107 -0
- package/docs/interfaces/PrefetchRequest.md +31 -0
- package/docs/interfaces/PrefetchResult.md +47 -0
- package/docs/interfaces/ProxyConfig.md +4 -4
- package/docs/interfaces/SiteCacheConfig.md +56 -11
- package/docs/interfaces/SmartCacheOptions.md +32 -6
- package/docs/variables/OfflineCacheMissErrorCode.md +18 -0
- package/package.json +5 -3
package/docs/README.md
CHANGED
|
@@ -19,6 +19,8 @@ In high-concurrency environmentsโlike **API Proxies**, **Web Scrapers**, or **
|
|
|
19
19
|
## Key Features
|
|
20
20
|
|
|
21
21
|
- **๐ Hybrid Multi-tier Cache**: Extreme speed with L1 (LRU Memory) and persistence with L2 (Content Addressable Disk via `cacache`).
|
|
22
|
+
- **๐ฅ HTTP POST & Method Support**: Full support for caching POST, PUT, and other methods with intelligent request body fingerprinting.
|
|
23
|
+
- **๐ฏ Precision Filtering**: Fine-grained `cacheRules` to intercept specific paths or query parameters.
|
|
22
24
|
- **๐ Streaming Native**: Fully stream-based internal pipeline natively prevents Out-Of-Memory (OOM) issues when proxying large files.
|
|
23
25
|
- **๐ง Intelligent Meta-Residency**: Metadata (Headers, Status, Policy) stays in memory regardless of body size, ensuring nanosecond cache policy evaluations.
|
|
24
26
|
- **๐ Stale-While-Revalidate (SWR)**: Serve stale content instantly while updating the cache silently in the background.
|
|
@@ -37,6 +39,8 @@ pnpm add @isdk/proxy
|
|
|
37
39
|
|
|
38
40
|
The primary way to use `@isdk/proxy` is via the `fetchWithCache` function, which can wrap any HTTP request logic.
|
|
39
41
|
|
|
42
|
+
### Basic Usage (GET)
|
|
43
|
+
|
|
40
44
|
```typescript
|
|
41
45
|
import { SmartCache, createCachedFetch } from '@isdk/proxy';
|
|
42
46
|
|
|
@@ -46,28 +50,112 @@ const cache = new SmartCache({
|
|
|
46
50
|
maxMemorySize: 1024 * 1024 // 1MB threshold
|
|
47
51
|
});
|
|
48
52
|
|
|
49
|
-
// 2. Create a pre-configured cached fetcher
|
|
53
|
+
// 2. Create a pre-configured cached fetcher
|
|
50
54
|
const myFetch = createCachedFetch({
|
|
51
55
|
cache,
|
|
52
56
|
config: {
|
|
53
57
|
staleIfError: true,
|
|
54
|
-
forceCache: false // Set to true to cache everything (ignore no-store) for offline-first apps
|
|
55
58
|
},
|
|
56
59
|
backgroundUpdate: true // Enable SWR
|
|
57
60
|
});
|
|
58
61
|
|
|
59
|
-
// 3. Use it
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
+
// 3. Use it!
|
|
63
|
+
const response = await myFetch(new Request('https://api.example.com/data'), (req) => fetch(req));
|
|
64
|
+
console.log(response.headers.get('x-proxy-cache'));
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Advanced Usage: Caching POST Requests
|
|
68
|
+
|
|
69
|
+
You can cache POST/PUT requests by enabling methods and defining body filters to ignore dynamic fields (like timestamps) in the request body.
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
const myPostFetch = createCachedFetch({
|
|
73
|
+
cache,
|
|
74
|
+
config: {
|
|
75
|
+
methods: ['GET', 'POST'], // Enable POST caching
|
|
76
|
+
body: {
|
|
77
|
+
exclude: ['timestamp', 'nonce'] // Ignore these fields when generating cache keys
|
|
78
|
+
},
|
|
79
|
+
cacheRules: [
|
|
80
|
+
{ method: 'POST', path: '/api/v1/query' } // Only cache specific POST endpoints
|
|
81
|
+
],
|
|
82
|
+
forceCache: true // Often needed for POST if backend doesn't send Cache-Control
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Configuration: `SiteCacheConfig`
|
|
88
|
+
|
|
89
|
+
| Field | Type | Description |
|
|
90
|
+
| :--- | :--- | :--- |
|
|
91
|
+
| `methods` | `string[]` | List of allowed HTTP methods. Default: `['GET', 'HEAD']`. |
|
|
92
|
+
| `cacheRules` | `CacheRule[]` | Fine-grained rules. If set, a request must match at least one rule to be cached. |
|
|
93
|
+
| `query` | `KeyFilterConfig` | Filters for URL search parameters (`include`/`exclude`). |
|
|
94
|
+
| `headers` | `KeyFilterConfig` | Filters for request headers. |
|
|
95
|
+
| `cookies` | `KeyFilterConfig` | Filters for cookies. |
|
|
96
|
+
| `body` | `KeyFilterConfig` | Filters for request body fields. For JSON, supports field-level filtering; also supports extracting key data via `extract` regex. |
|
|
97
|
+
| `staleIfError`| `boolean` | Serve stale cache on network failure. |
|
|
98
|
+
| `forceCache` | `boolean` | Ignore `no-store` and force caching (useful for offline support). |
|
|
99
|
+
| `offline` | `boolean` | Offline mode. Only reads from cache; throws `OfflineCacheMissError` if no cache exists. |
|
|
100
|
+
|
|
101
|
+
### `CacheRule` Object
|
|
102
|
+
|
|
103
|
+
- `method`: HTTP method to match.
|
|
104
|
+
- `path`: URL pathname matching (supports **RegExp**, **Glob**, **Array**, or **prefix match**).
|
|
105
|
+
- `query`: Key-value pairs. Values can be `string` (exact/Glob match), `true` (must exist), `false` (must not exist), or `RegExp`.
|
|
106
|
+
- `bodyType`: Match body type. Supports `'json'`, `'text'`, `'binary'`.
|
|
107
|
+
- `body`: Body content matching (supports **RegExp**, **Glob**, or **Array**).
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
### `fetchWithCache` Advanced Options
|
|
112
|
+
|
|
113
|
+
In addition to `SiteCacheConfig`, `fetchWithCache` supports the following control options:
|
|
114
|
+
|
|
115
|
+
| Option | Type | Description |
|
|
116
|
+
| :--- | :--- | :--- |
|
|
117
|
+
| `backgroundUpdate` | `boolean` | Whether to enable background async update (SWR). Default is `true`. |
|
|
118
|
+
| `onBackgroundUpdate`| `function` | Callback that receives the update Promise when a background update is triggered. Useful for task tracking. |
|
|
119
|
+
| `generateKey` | `function` | Custom cache key generation function. |
|
|
120
|
+
|
|
121
|
+
### Pattern Matching
|
|
122
|
+
|
|
123
|
+
`@isdk/proxy` provides powerful pattern matching for all configurable fields:
|
|
124
|
+
|
|
125
|
+
| Pattern Type | Example | Description |
|
|
126
|
+
| :--- | :--- | :--- |
|
|
127
|
+
| **RegExp** | `/api/v[12]/.*/i` | JavaScript RegExp (in JSON, use string like `"/api/v[12]/.*/i"`) |
|
|
128
|
+
| **Glob** | `/**/*.json` | File path style wildcard matching |
|
|
129
|
+
| **Negation** | `['!/api/private/**', '/api/**']` | Exclude patterns (prefixed with `!`, checked first) |
|
|
130
|
+
| **Array** | `['/api/v1/*', '/api/v2/*']` | Multiple patterns (OR logic, negative takes precedence) |
|
|
131
|
+
| **Boolean** | `true` / `false` | For query params: must/must not exist |
|
|
62
132
|
|
|
63
|
-
|
|
64
|
-
|
|
133
|
+
**Example with advanced pattern matching:**
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
const myFetch = createCachedFetch({
|
|
137
|
+
cache,
|
|
138
|
+
config: {
|
|
139
|
+
cacheRules: [
|
|
140
|
+
{
|
|
141
|
+
path: ['/api/v1/items/*', '!/api/v1/items/private/*'], // v1 items, exclude private
|
|
142
|
+
query: {
|
|
143
|
+
format: '/^(json|xml)$/', // Regex for format param
|
|
144
|
+
'page*': true // Glob: any param starting with 'page' must exist
|
|
145
|
+
},
|
|
146
|
+
body: /\"action\"\s*:\s*\"query\"/ // Regex body match
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
});
|
|
65
151
|
```
|
|
66
152
|
|
|
67
153
|
## Adapters
|
|
68
154
|
|
|
69
155
|
`@isdk/proxy` is designed to be framework-agnostic. While the core library is pure, you can find (or build) adapters for specific environments:
|
|
70
156
|
|
|
157
|
+
- **HTTP Caching Proxy Server (Node.js)**: See [@isdk/proxy-server](https://www.npmjs.com/package/@isdk/proxy-server) (separate package) for running a standalone HTTP forward proxy.
|
|
158
|
+
- **Crawlee Adapter**: See [@isdk/proxy-crawlee](https://www.npmjs.com/package/@isdk/proxy-crawlee) (separate package) for integrating with Crawlee web scraping lifecycle.
|
|
71
159
|
- **MSW Adapter**: See `@isdk/proxy-msw` (separate package) to use this caching engine as an MSW interceptor.
|
|
72
160
|
- **Axios Adapter**: Easily implemented by converting Axios config to Web `Request`.
|
|
73
161
|
|
|
@@ -120,9 +208,163 @@ The hybrid multi-tier storage engine.
|
|
|
120
208
|
- **`options.maxMemorySize`**: Threshold (in bytes) for offloading bodies to disk (default `1048576`, i.e., 1MB).
|
|
121
209
|
- **`options.storagePath`**: Disk storage path for the `cacache` engine (defaults to a system temp folder).
|
|
122
210
|
|
|
211
|
+
### Utility Functions
|
|
212
|
+
|
|
213
|
+
Exported from `@isdk/proxy` for advanced usage:
|
|
214
|
+
|
|
215
|
+
#### `isMatch(pattern, value, usePrefix?)`
|
|
216
|
+
|
|
217
|
+
Universal pattern matching function. Supports RegExp, Glob, array patterns (with negation), and string prefix/exact matching.
|
|
218
|
+
|
|
219
|
+
- **`pattern`**: `string | RegExp | (string | RegExp)[]`
|
|
220
|
+
- **`value`**: The string to test against
|
|
221
|
+
- **`usePrefix`**: For plain strings, use prefix match instead of exact match (default: `false`)
|
|
222
|
+
- **Returns**: `boolean`
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
import { isMatch } from '@isdk/proxy';
|
|
226
|
+
|
|
227
|
+
isMatch('/api/v[12]/.*', '/api/v1/users'); // RegExp
|
|
228
|
+
isMatch('/api/**/*.json', '/api/v1/data.json'); // Glob
|
|
229
|
+
isMatch(['!/private/**', '/api/**'], '/api/data'); // Negation
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
#### `isGlob(pattern)`
|
|
233
|
+
|
|
234
|
+
Check if a pattern is Glob syntax.
|
|
235
|
+
|
|
236
|
+
- **`pattern`**: `string`
|
|
237
|
+
- **Returns**: `boolean`
|
|
238
|
+
|
|
239
|
+
#### `getSiteConfig(urlString, proxyConfig)`
|
|
240
|
+
|
|
241
|
+
Get the site-specific cache configuration for a given URL.
|
|
242
|
+
|
|
243
|
+
- **`urlString`**: Full URL to match
|
|
244
|
+
- **`proxyConfig`**: `ProxyConfig` object with `sites` and `default` config
|
|
245
|
+
- **Returns**: `SiteCacheConfig`
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import { getSiteConfig } from '@isdk/proxy';
|
|
249
|
+
|
|
250
|
+
const config = getSiteConfig('https://api.example.com/data', {
|
|
251
|
+
default: { methods: ['GET'] },
|
|
252
|
+
sites: {
|
|
253
|
+
'api.example.com': { methods: ['GET', 'POST'], forceCache: true },
|
|
254
|
+
'/internal/': { staleIfError: true } // prefix match
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
#### `isAllowed(key, config, defaultAllowed?)`
|
|
260
|
+
|
|
261
|
+
Check if a key is allowed to participate in cache key fingerprinting.
|
|
262
|
+
|
|
263
|
+
- **`key`**: The key name to check
|
|
264
|
+
- **`config`**: `KeyFilterConfig` with `include` (whitelist) or `exclude` (blacklist)
|
|
265
|
+
- **`defaultAllowed`**: Optional. Default value when no config or no match
|
|
266
|
+
- **Returns**: `boolean | undefined`
|
|
267
|
+
|
|
268
|
+
**Priority Logic**:
|
|
269
|
+
|
|
270
|
+
1. `exclude` hit โ returns `false` (highest priority)
|
|
271
|
+
2. `include` exists and hits โ returns `true`
|
|
272
|
+
3. `include` exists but no hit โ returns `false`
|
|
273
|
+
4. No config โ uses `defaultAllowed` (returns `undefined` if not provided)
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
import { isAllowed } from '@isdk/proxy';
|
|
277
|
+
|
|
278
|
+
// No config
|
|
279
|
+
isAllowed('key'); // undefined (falsy)
|
|
280
|
+
|
|
281
|
+
// Whitelist
|
|
282
|
+
isAllowed('id', { include: ['id', 'name'] }); // true
|
|
283
|
+
isAllowed('email', { include: ['id', 'name'] }); // false
|
|
284
|
+
|
|
285
|
+
// Blacklist
|
|
286
|
+
isAllowed('password', { exclude: ['password'] }); // false
|
|
287
|
+
isAllowed('name', { exclude: ['password'] }); // undefined (falsy)
|
|
288
|
+
|
|
289
|
+
// Need defaultAllowed to set default
|
|
290
|
+
isAllowed('name', { exclude: ['password'] }, true); // true
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
#### `extractData(source, config, defaultAllowed?)`
|
|
294
|
+
|
|
295
|
+
Extract and normalize data from a source object based on filter config. Used for generating cache fingerprints.
|
|
296
|
+
|
|
297
|
+
- **`source`**: Original data object (Query, Headers, Cookies, etc.)
|
|
298
|
+
- **`config`**: `KeyFilterConfig` object
|
|
299
|
+
- **`defaultAllowed`**: Optional. Whether to allow extraction when no config or no match (default `false`)
|
|
300
|
+
- **Returns**: `Record<string, string[]>` normalized data with lowercase keys and sorted array values
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
import { extractData } from '@isdk/proxy';
|
|
304
|
+
|
|
305
|
+
const headers = { 'Content-Type': 'application/json', 'X-Request-Id': '123' };
|
|
306
|
+
|
|
307
|
+
// No extraction by default
|
|
308
|
+
extractData(headers); // {}
|
|
309
|
+
|
|
310
|
+
// Extract all keys
|
|
311
|
+
extractData(headers, undefined, true); // { 'content-type': ['application/json'], 'x-request-id': ['123'] }
|
|
312
|
+
|
|
313
|
+
// Whitelist
|
|
314
|
+
extractData(headers, { include: ['content-type'] }); // { 'content-type': ['application/json'] }
|
|
315
|
+
|
|
316
|
+
// Blacklist
|
|
317
|
+
extractData(headers, { include: ['*'], exclude: ['x-request-id'] }, true); // { 'content-type': ['application/json'] }
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### `prefetch(options)`
|
|
321
|
+
|
|
322
|
+
Pre-cache function that fetches and stores a list of URLs into cache ahead of time.
|
|
323
|
+
|
|
324
|
+
- **`urls`**: `PrefetchRequest[]`. Each object contains `url` and optional `request` config.
|
|
325
|
+
- **`config`**: `ProxyConfig` full configuration.
|
|
326
|
+
- **`cache`**: `SmartCache` instance.
|
|
327
|
+
- **`concurrency`**: Concurrency limit (default `3`).
|
|
328
|
+
- **`onProgress`**: Progress callback `(completed, total, url) => void`.
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
import { prefetch } from '@isdk/proxy';
|
|
332
|
+
|
|
333
|
+
const result = await prefetch({
|
|
334
|
+
urls: [
|
|
335
|
+
{ url: 'https://api.example.com/page1' },
|
|
336
|
+
{ url: 'https://api.example.com/api2', request: { method: 'POST', body: '...' } }
|
|
337
|
+
],
|
|
338
|
+
config,
|
|
339
|
+
cache,
|
|
340
|
+
onProgress: (c, t, url) => console.log(`Progress: ${c}/${t} - ${url}`)
|
|
341
|
+
});
|
|
342
|
+
console.log(`Succeeded: ${result.succeeded}, Failed: ${result.failed}`);
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Error Handling: `OfflineCacheMissError`
|
|
346
|
+
|
|
347
|
+
When `offline: true` mode is enabled and a request does not hit the cache, this error is thrown.
|
|
348
|
+
|
|
349
|
+
- **`name`**: `OfflineCacheMissError`
|
|
350
|
+
- **`code`**: `ERR_OFFLINE_CACHE_MISS` (can be imported as `OfflineCacheMissErrorCode`)
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
import { OfflineCacheMissError } from '@isdk/proxy';
|
|
354
|
+
|
|
355
|
+
try {
|
|
356
|
+
await myFetch(request);
|
|
357
|
+
} catch (e) {
|
|
358
|
+
if (e instanceof OfflineCacheMissError) {
|
|
359
|
+
// Handle offline cache miss
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
123
364
|
### Cache Status Headers
|
|
124
365
|
|
|
125
366
|
Every response processed by `@isdk/proxy` will include an `x-proxy-cache` header indicating its lifecycle:
|
|
367
|
+
|
|
126
368
|
- `HIT`: Served entirely from L1 or L2 cache.
|
|
127
369
|
- `MISS`: Bypassed cache and fetched from the origin server.
|
|
128
370
|
- `STALE`: Served from stale cache while a background update was initiated (SWR).
|