@pantheon-systems/nextjs-cache-handler 0.1.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/README.md +256 -0
- package/dist/edge/edge-cache-clear.d.ts +64 -0
- package/dist/edge/edge-cache-clear.d.ts.map +1 -0
- package/dist/edge/edge-cache-clear.js +245 -0
- package/dist/edge/edge-cache-clear.js.map +1 -0
- package/dist/handlers/base.d.ts +69 -0
- package/dist/handlers/base.d.ts.map +1 -0
- package/dist/handlers/base.js +278 -0
- package/dist/handlers/base.js.map +1 -0
- package/dist/handlers/file.d.ts +62 -0
- package/dist/handlers/file.d.ts.map +1 -0
- package/dist/handlers/file.js +332 -0
- package/dist/handlers/file.js.map +1 -0
- package/dist/handlers/gcs.d.ts +66 -0
- package/dist/handlers/gcs.d.ts.map +1 -0
- package/dist/handlers/gcs.js +407 -0
- package/dist/handlers/gcs.js.map +1 -0
- package/dist/handlers/index.d.ts +4 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/index.js +4 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +119 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/build-detection.d.ts +10 -0
- package/dist/utils/build-detection.d.ts.map +1 -0
- package/dist/utils/build-detection.js +57 -0
- package/dist/utils/build-detection.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +34 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +54 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/serialization.d.ts +12 -0
- package/dist/utils/serialization.d.ts.map +1 -0
- package/dist/utils/serialization.js +137 -0
- package/dist/utils/serialization.js.map +1 -0
- package/dist/utils/static-routes.d.ts +7 -0
- package/dist/utils/static-routes.d.ts.map +1 -0
- package/dist/utils/static-routes.js +52 -0
- package/dist/utils/static-routes.js.map +1 -0
- package/dist/utils/tags-buffer.d.ts +63 -0
- package/dist/utils/tags-buffer.d.ts.map +1 -0
- package/dist/utils/tags-buffer.js +181 -0
- package/dist/utils/tags-buffer.js.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# @pantheon-systems/nextjs-cache-handler
|
|
2
|
+
|
|
3
|
+
Custom cache handler for Next.js with support for Google Cloud Storage and file-based caching. Designed for Pantheon's Next.js hosting platform.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Dual Cache Handlers**: Support for both GCS (production) and file-based (development) caching
|
|
8
|
+
- **Tag-Based Invalidation**: Efficient O(1) cache invalidation using tag mapping
|
|
9
|
+
- **Buffer Serialization**: Handles Next.js 15 buffer compatibility issues
|
|
10
|
+
- **Build-Aware Caching**: Automatically invalidates route cache on new builds
|
|
11
|
+
- **Static Route Preservation**: Preserves SSG routes during cache clearing
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @pantheon-systems/nextjs-cache-handler
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
### 1. Create a cache handler file
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// cacheHandler.ts
|
|
25
|
+
import { createCacheHandler } from '@pantheon-systems/nextjs-cache-handler';
|
|
26
|
+
|
|
27
|
+
const CacheHandler = createCacheHandler({
|
|
28
|
+
type: 'auto', // Auto-detect: GCS if CACHE_BUCKET exists, else file-based
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export default CacheHandler;
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 2. Configure Next.js
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
// next.config.mjs
|
|
38
|
+
const nextConfig = {
|
|
39
|
+
cacheHandler: require.resolve('./cacheHandler'),
|
|
40
|
+
cacheMaxMemorySize: 0, // Disable in-memory caching to use custom handler
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default nextConfig;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Configuration
|
|
47
|
+
|
|
48
|
+
### `createCacheHandler(config?)`
|
|
49
|
+
|
|
50
|
+
Creates a cache handler based on the provided configuration.
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
interface CacheHandlerConfig {
|
|
54
|
+
/**
|
|
55
|
+
* Handler type selection:
|
|
56
|
+
* - 'auto': Automatically detect based on environment (GCS if CACHE_BUCKET is set, otherwise file)
|
|
57
|
+
* - 'file': Use file-based caching (local development)
|
|
58
|
+
* - 'gcs': Use Google Cloud Storage (production/Pantheon)
|
|
59
|
+
*/
|
|
60
|
+
type?: 'auto' | 'file' | 'gcs';
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
> **Note:** Debug logging is controlled via the `CACHE_DEBUG` environment variable. See the [Debugging](#debugging) section for details.
|
|
65
|
+
|
|
66
|
+
## Environment Variables
|
|
67
|
+
|
|
68
|
+
| Variable | Description | Required |
|
|
69
|
+
|----------|-------------|----------|
|
|
70
|
+
| `CACHE_BUCKET` | GCS bucket name for storing cache | Required for GCS handler |
|
|
71
|
+
| `OUTBOUND_PROXY_ENDPOINT` | Edge cache proxy endpoint | Optional (enables edge cache clearing) |
|
|
72
|
+
| `CACHE_DEBUG` | Enable debug logging (`true` or `1`) | Optional |
|
|
73
|
+
|
|
74
|
+
## API Reference
|
|
75
|
+
|
|
76
|
+
### `createCacheHandler(config?)`
|
|
77
|
+
|
|
78
|
+
Factory function that returns the appropriate cache handler class based on configuration.
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { createCacheHandler } from '@pantheon-systems/nextjs-cache-handler';
|
|
82
|
+
|
|
83
|
+
// Auto-detect based on environment
|
|
84
|
+
const CacheHandler = createCacheHandler();
|
|
85
|
+
|
|
86
|
+
// Force file-based caching
|
|
87
|
+
const FileCacheHandler = createCacheHandler({ type: 'file' });
|
|
88
|
+
|
|
89
|
+
// Force GCS caching
|
|
90
|
+
const GcsCacheHandler = createCacheHandler({ type: 'gcs' });
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### `getSharedCacheStats()`
|
|
94
|
+
|
|
95
|
+
Returns cache statistics for the current environment.
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { getSharedCacheStats } from '@pantheon-systems/nextjs-cache-handler';
|
|
99
|
+
|
|
100
|
+
const stats = await getSharedCacheStats();
|
|
101
|
+
console.log(stats);
|
|
102
|
+
// {
|
|
103
|
+
// size: 10,
|
|
104
|
+
// keys: ['fetch:abc123', 'route:_index'],
|
|
105
|
+
// entries: [
|
|
106
|
+
// { key: 'fetch:abc123', tags: ['posts'], type: 'fetch', lastModified: 1234567890 }
|
|
107
|
+
// ]
|
|
108
|
+
// }
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### `clearSharedCache()`
|
|
112
|
+
|
|
113
|
+
Clears all cache entries (preserving static SSG routes).
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
import { clearSharedCache } from '@pantheon-systems/nextjs-cache-handler';
|
|
117
|
+
|
|
118
|
+
const clearedCount = await clearSharedCache();
|
|
119
|
+
console.log(`Cleared ${clearedCount} cache entries`);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Direct Handler Access
|
|
123
|
+
|
|
124
|
+
For advanced use cases, you can import the handlers directly:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { FileCacheHandler, GcsCacheHandler } from '@pantheon-systems/nextjs-cache-handler';
|
|
128
|
+
|
|
129
|
+
// Use directly in your configuration
|
|
130
|
+
export default FileCacheHandler;
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Cache Types
|
|
134
|
+
|
|
135
|
+
The handler distinguishes between two cache types:
|
|
136
|
+
|
|
137
|
+
- **Fetch Cache**: Stores data from `fetch()` calls with caching enabled
|
|
138
|
+
- **Route Cache**: Stores rendered pages and route data
|
|
139
|
+
|
|
140
|
+
## Tag-Based Invalidation
|
|
141
|
+
|
|
142
|
+
The handler maintains a tag-to-keys mapping for efficient O(1) cache invalidation:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// When setting cache with tags
|
|
146
|
+
await cacheHandler.set('post-1', data, { tags: ['posts', 'blog'] });
|
|
147
|
+
|
|
148
|
+
// When invalidating by tag
|
|
149
|
+
await cacheHandler.revalidateTag('posts');
|
|
150
|
+
// All entries tagged with 'posts' are invalidated
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Build Invalidation
|
|
154
|
+
|
|
155
|
+
On each new build, the handler automatically:
|
|
156
|
+
|
|
157
|
+
1. Detects the new build ID
|
|
158
|
+
2. Invalidates the route cache (Full Route Cache)
|
|
159
|
+
3. Preserves the data cache (Fetch Cache)
|
|
160
|
+
|
|
161
|
+
This matches Next.js's expected behavior where route cache is invalidated on each deploy but data cache persists.
|
|
162
|
+
|
|
163
|
+
## Debugging
|
|
164
|
+
|
|
165
|
+
Enable debug logging to see detailed cache operations by setting the `CACHE_DEBUG` environment variable:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# Enable debug logging
|
|
169
|
+
CACHE_DEBUG=true npm run start
|
|
170
|
+
|
|
171
|
+
# Or
|
|
172
|
+
CACHE_DEBUG=1 npm run start
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Log Levels
|
|
176
|
+
|
|
177
|
+
The cache handler uses four log levels:
|
|
178
|
+
|
|
179
|
+
| Level | When Shown | Use Case |
|
|
180
|
+
|-------|------------|----------|
|
|
181
|
+
| `debug` | Only when `CACHE_DEBUG=true` | Verbose operational logs (GET, SET, HIT, MISS) |
|
|
182
|
+
| `info` | Only when `CACHE_DEBUG=true` | Important events (initialization, cache cleared) |
|
|
183
|
+
| `warn` | Always | Recoverable issues that might need attention |
|
|
184
|
+
| `error` | Always | Errors that affect cache operations |
|
|
185
|
+
|
|
186
|
+
### Example Output
|
|
187
|
+
|
|
188
|
+
When debug logging is enabled, you'll see output like:
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
[GcsCacheHandler] Initializing cache handler
|
|
192
|
+
[GcsCacheHandler] GET: /api/posts
|
|
193
|
+
[GcsCacheHandler] HIT: /api/posts (route)
|
|
194
|
+
[GcsCacheHandler] SET: /api/users (fetch)
|
|
195
|
+
[EdgeCacheClear] Cleared 3 paths in 45ms
|
|
196
|
+
[GcsCacheHandler] Revalidated 5 entries for tags: posts, blog
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
This helps diagnose cache behavior, verify cache hits/misses, and troubleshoot invalidation issues.
|
|
200
|
+
|
|
201
|
+
## Publishing
|
|
202
|
+
|
|
203
|
+
### Prerequisites
|
|
204
|
+
|
|
205
|
+
1. Ensure you're logged into npm with access to the `@pantheon-systems` scope:
|
|
206
|
+
```bash
|
|
207
|
+
npm login --scope=@pantheon-systems
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
2. Verify your login:
|
|
211
|
+
```bash
|
|
212
|
+
npm whoami
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Publishing Steps
|
|
216
|
+
|
|
217
|
+
1. **Update the version** in `package.json`:
|
|
218
|
+
```bash
|
|
219
|
+
# Patch release (0.1.0 -> 0.1.1)
|
|
220
|
+
npm version patch
|
|
221
|
+
|
|
222
|
+
# Minor release (0.1.0 -> 0.2.0)
|
|
223
|
+
npm version minor
|
|
224
|
+
|
|
225
|
+
# Major release (0.1.0 -> 1.0.0)
|
|
226
|
+
npm version major
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
2. **Build and test**:
|
|
230
|
+
```bash
|
|
231
|
+
npm run build
|
|
232
|
+
npm test
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
3. **Publish to npm**:
|
|
236
|
+
```bash
|
|
237
|
+
npm publish --access public
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
The `--access public` flag is required for scoped packages to be publicly accessible.
|
|
241
|
+
|
|
242
|
+
### Verify Publication
|
|
243
|
+
|
|
244
|
+
After publishing, verify the package is available:
|
|
245
|
+
```bash
|
|
246
|
+
npm view @pantheon-systems/nextjs-cache-handler
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Or install it in a test project:
|
|
250
|
+
```bash
|
|
251
|
+
npm install @pantheon-systems/nextjs-cache-handler
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## License
|
|
255
|
+
|
|
256
|
+
MIT
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result of a cache clear operation.
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
interface CacheClearResult {
|
|
6
|
+
success: boolean;
|
|
7
|
+
error?: string;
|
|
8
|
+
statusCode?: number;
|
|
9
|
+
duration?: number;
|
|
10
|
+
paths?: string[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Edge cache clearer for clearing CDN cache via the outbound proxy.
|
|
14
|
+
* This is an internal class not exposed in the public API.
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
export declare class EdgeCacheClear {
|
|
18
|
+
private baseUrl;
|
|
19
|
+
constructor(endpoint?: string);
|
|
20
|
+
/**
|
|
21
|
+
* Clear the entire edge cache (nuclear option).
|
|
22
|
+
*/
|
|
23
|
+
nukeCache(): Promise<CacheClearResult>;
|
|
24
|
+
/**
|
|
25
|
+
* Clear specific paths from the edge cache (granular invalidation).
|
|
26
|
+
* @param paths Array of paths to clear (e.g., ['/blogs/my-post', '/blogs'])
|
|
27
|
+
*/
|
|
28
|
+
clearPaths(paths: string[]): Promise<CacheClearResult>;
|
|
29
|
+
private clearSinglePath;
|
|
30
|
+
/**
|
|
31
|
+
* Clear a single path from the edge cache.
|
|
32
|
+
*/
|
|
33
|
+
clearPath(routePath: string): Promise<CacheClearResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Clear paths in the background (non-blocking).
|
|
36
|
+
*/
|
|
37
|
+
clearPathsInBackground(paths: string[], context: string): void;
|
|
38
|
+
/**
|
|
39
|
+
* Clear a single path in the background (non-blocking).
|
|
40
|
+
*/
|
|
41
|
+
clearPathInBackground(routePath: string, context: string): void;
|
|
42
|
+
/**
|
|
43
|
+
* Clear cache entries by key/tag.
|
|
44
|
+
* @param keys Array of cache keys/tags to clear
|
|
45
|
+
*/
|
|
46
|
+
clearKeys(keys: string[]): Promise<CacheClearResult>;
|
|
47
|
+
private clearSingleKey;
|
|
48
|
+
/**
|
|
49
|
+
* Clear keys in the background (non-blocking).
|
|
50
|
+
*/
|
|
51
|
+
clearKeysInBackground(keys: string[], context: string): void;
|
|
52
|
+
/**
|
|
53
|
+
* Clear entire cache in the background (non-blocking).
|
|
54
|
+
*/
|
|
55
|
+
nukeCacheInBackground(context: string): void;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Creates an EdgeCacheClear instance if the environment is configured.
|
|
59
|
+
* Returns null if edge cache clearing is not available.
|
|
60
|
+
* @internal
|
|
61
|
+
*/
|
|
62
|
+
export declare function createEdgeCacheClearer(): EdgeCacheClear | null;
|
|
63
|
+
export {};
|
|
64
|
+
//# sourceMappingURL=edge-cache-clear.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edge-cache-clear.d.ts","sourceRoot":"","sources":["../../src/edge/edge-cache-clear.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,UAAU,gBAAgB;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;GAIG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAS;gBAEZ,QAAQ,CAAC,EAAE,MAAM;IAQ7B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAqC5C;;;OAGG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC;YA8B9C,eAAe;IAmC7B;;OAEG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAI7D;;OAEG;IACH,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAgB9D;;OAEG;IACH,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAI/D;;;OAGG;IACG,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC;YA8B5C,cAAc;IAgC5B;;OAEG;IACH,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAgB5D;;OAEG;IACH,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAa7C;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,cAAc,GAAG,IAAI,CAM9D"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { createLogger } from '../utils/logger.js';
|
|
2
|
+
const edgeLog = createLogger('EdgeCacheClear');
|
|
3
|
+
/**
|
|
4
|
+
* Edge cache clearer for clearing CDN cache via the outbound proxy.
|
|
5
|
+
* This is an internal class not exposed in the public API.
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export class EdgeCacheClear {
|
|
9
|
+
constructor(endpoint) {
|
|
10
|
+
const proxyEndpoint = endpoint || process.env.OUTBOUND_PROXY_ENDPOINT;
|
|
11
|
+
if (!proxyEndpoint) {
|
|
12
|
+
throw new Error('OUTBOUND_PROXY_ENDPOINT environment variable is required for edge cache clearing');
|
|
13
|
+
}
|
|
14
|
+
this.baseUrl = `http://${proxyEndpoint}/rest/v0alpha1/cache`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Clear the entire edge cache (nuclear option).
|
|
18
|
+
*/
|
|
19
|
+
async nukeCache() {
|
|
20
|
+
const startTime = Date.now();
|
|
21
|
+
try {
|
|
22
|
+
const controller = new AbortController();
|
|
23
|
+
const timeoutId = setTimeout(() => controller.abort(), 10000);
|
|
24
|
+
const response = await fetch(this.baseUrl, {
|
|
25
|
+
method: 'DELETE',
|
|
26
|
+
headers: {
|
|
27
|
+
'Content-Type': 'application/json',
|
|
28
|
+
},
|
|
29
|
+
signal: controller.signal,
|
|
30
|
+
});
|
|
31
|
+
clearTimeout(timeoutId);
|
|
32
|
+
const duration = Date.now() - startTime;
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
const errorText = await response.text().catch(() => 'Unknown error');
|
|
35
|
+
return {
|
|
36
|
+
success: false,
|
|
37
|
+
error: `HTTP ${response.status}: ${errorText}`,
|
|
38
|
+
statusCode: response.status,
|
|
39
|
+
duration,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
edgeLog.debug(`Cleared entire edge cache in ${duration}ms`);
|
|
43
|
+
return { success: true, statusCode: response.status, duration };
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
const duration = Date.now() - startTime;
|
|
47
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
48
|
+
return { success: false, error: errorMessage, duration };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Clear specific paths from the edge cache (granular invalidation).
|
|
53
|
+
* @param paths Array of paths to clear (e.g., ['/blogs/my-post', '/blogs'])
|
|
54
|
+
*/
|
|
55
|
+
async clearPaths(paths) {
|
|
56
|
+
if (paths.length === 0) {
|
|
57
|
+
return { success: true, duration: 0, paths: [] };
|
|
58
|
+
}
|
|
59
|
+
const startTime = Date.now();
|
|
60
|
+
const results = [];
|
|
61
|
+
try {
|
|
62
|
+
const clearPromises = paths.map((routePath) => this.clearSinglePath(routePath, results));
|
|
63
|
+
await Promise.all(clearPromises);
|
|
64
|
+
const duration = Date.now() - startTime;
|
|
65
|
+
const successCount = results.filter((r) => r.success).length;
|
|
66
|
+
const clearedPaths = results.filter((r) => r.success).map((r) => r.path);
|
|
67
|
+
edgeLog.debug(`Cleared ${successCount}/${paths.length} paths in ${duration}ms`);
|
|
68
|
+
return {
|
|
69
|
+
success: successCount > 0,
|
|
70
|
+
duration,
|
|
71
|
+
paths: clearedPaths,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
const duration = Date.now() - startTime;
|
|
76
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
77
|
+
return { success: false, error: errorMessage, duration, paths: [] };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async clearSinglePath(routePath, results) {
|
|
81
|
+
try {
|
|
82
|
+
const normalizedPath = routePath.startsWith('/') ? routePath : `/${routePath}`;
|
|
83
|
+
const cleanPath = normalizedPath.replace(/\/$/, '') || '/';
|
|
84
|
+
const pathSegment = cleanPath === '/' ? '' : cleanPath.substring(1);
|
|
85
|
+
const url = `${this.baseUrl}/paths/${pathSegment}`;
|
|
86
|
+
const controller = new AbortController();
|
|
87
|
+
const timeoutId = setTimeout(() => controller.abort(), 5000);
|
|
88
|
+
const response = await fetch(url, {
|
|
89
|
+
method: 'DELETE',
|
|
90
|
+
headers: {
|
|
91
|
+
'Content-Type': 'application/json',
|
|
92
|
+
},
|
|
93
|
+
signal: controller.signal,
|
|
94
|
+
});
|
|
95
|
+
clearTimeout(timeoutId);
|
|
96
|
+
if (response.ok) {
|
|
97
|
+
results.push({ path: routePath, success: true });
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
edgeLog.warn(`Failed to clear path ${routePath}: HTTP ${response.status}`);
|
|
101
|
+
results.push({ path: routePath, success: false });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
edgeLog.warn(`Error clearing path ${routePath}:`, error);
|
|
106
|
+
results.push({ path: routePath, success: false });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Clear a single path from the edge cache.
|
|
111
|
+
*/
|
|
112
|
+
async clearPath(routePath) {
|
|
113
|
+
return this.clearPaths([routePath]);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Clear paths in the background (non-blocking).
|
|
117
|
+
*/
|
|
118
|
+
clearPathsInBackground(paths, context) {
|
|
119
|
+
if (paths.length === 0)
|
|
120
|
+
return;
|
|
121
|
+
this.clearPaths(paths)
|
|
122
|
+
.then((result) => {
|
|
123
|
+
if (result.success) {
|
|
124
|
+
edgeLog.debug(`Background path clear for ${context}: ${result.paths?.length} paths cleared`);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
edgeLog.warn(`Background path clear failed for ${context}: ${result.error}`);
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
.catch((error) => {
|
|
131
|
+
edgeLog.error(`Background path clear error for ${context}:`, error);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Clear a single path in the background (non-blocking).
|
|
136
|
+
*/
|
|
137
|
+
clearPathInBackground(routePath, context) {
|
|
138
|
+
this.clearPathsInBackground([routePath], context);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Clear cache entries by key/tag.
|
|
142
|
+
* @param keys Array of cache keys/tags to clear
|
|
143
|
+
*/
|
|
144
|
+
async clearKeys(keys) {
|
|
145
|
+
if (keys.length === 0) {
|
|
146
|
+
return { success: true, duration: 0, paths: [] };
|
|
147
|
+
}
|
|
148
|
+
const startTime = Date.now();
|
|
149
|
+
const results = [];
|
|
150
|
+
try {
|
|
151
|
+
const clearPromises = keys.map((key) => this.clearSingleKey(key, results));
|
|
152
|
+
await Promise.all(clearPromises);
|
|
153
|
+
const duration = Date.now() - startTime;
|
|
154
|
+
const successCount = results.filter((r) => r.success).length;
|
|
155
|
+
const clearedKeys = results.filter((r) => r.success).map((r) => r.key);
|
|
156
|
+
edgeLog.debug(`Cleared ${successCount}/${keys.length} keys in ${duration}ms`);
|
|
157
|
+
return {
|
|
158
|
+
success: successCount > 0,
|
|
159
|
+
duration,
|
|
160
|
+
paths: clearedKeys,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
const duration = Date.now() - startTime;
|
|
165
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
166
|
+
return { success: false, error: errorMessage, duration, paths: [] };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async clearSingleKey(key, results) {
|
|
170
|
+
try {
|
|
171
|
+
const url = `${this.baseUrl}/keys/${encodeURIComponent(key)}`;
|
|
172
|
+
const controller = new AbortController();
|
|
173
|
+
const timeoutId = setTimeout(() => controller.abort(), 5000);
|
|
174
|
+
const response = await fetch(url, {
|
|
175
|
+
method: 'DELETE',
|
|
176
|
+
headers: {
|
|
177
|
+
'Content-Type': 'application/json',
|
|
178
|
+
},
|
|
179
|
+
signal: controller.signal,
|
|
180
|
+
});
|
|
181
|
+
clearTimeout(timeoutId);
|
|
182
|
+
if (response.ok) {
|
|
183
|
+
results.push({ key, success: true });
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
edgeLog.warn(`Failed to clear key ${key}: HTTP ${response.status}`);
|
|
187
|
+
results.push({ key, success: false });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
edgeLog.warn(`Error clearing key ${key}:`, error);
|
|
192
|
+
results.push({ key, success: false });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Clear keys in the background (non-blocking).
|
|
197
|
+
*/
|
|
198
|
+
clearKeysInBackground(keys, context) {
|
|
199
|
+
if (keys.length === 0)
|
|
200
|
+
return;
|
|
201
|
+
this.clearKeys(keys)
|
|
202
|
+
.then((result) => {
|
|
203
|
+
if (result.success) {
|
|
204
|
+
edgeLog.debug(`Background key clear for ${context}: ${result.paths?.length} keys cleared`);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
edgeLog.warn(`Background key clear failed for ${context}: ${result.error}`);
|
|
208
|
+
}
|
|
209
|
+
})
|
|
210
|
+
.catch((error) => {
|
|
211
|
+
edgeLog.error(`Background key clear error for ${context}:`, error);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Clear entire cache in the background (non-blocking).
|
|
216
|
+
*/
|
|
217
|
+
nukeCacheInBackground(context) {
|
|
218
|
+
this.nukeCache()
|
|
219
|
+
.then((result) => {
|
|
220
|
+
if (result.success) {
|
|
221
|
+
edgeLog.debug(`Background nuke successful for ${context} (${result.duration}ms)`);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
edgeLog.warn(`Background nuke failed for ${context}: ${result.error}`);
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
.catch((error) => {
|
|
228
|
+
edgeLog.error(`Background nuke error for ${context}:`, error);
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Creates an EdgeCacheClear instance if the environment is configured.
|
|
234
|
+
* Returns null if edge cache clearing is not available.
|
|
235
|
+
* @internal
|
|
236
|
+
*/
|
|
237
|
+
export function createEdgeCacheClearer() {
|
|
238
|
+
try {
|
|
239
|
+
return new EdgeCacheClear();
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=edge-cache-clear.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edge-cache-clear.js","sourceRoot":"","sources":["../../src/edge/edge-cache-clear.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { CacheData, CacheHandlerParametersGet, CacheHandlerParametersSet, CacheHandlerParametersRevalidateTag, CacheHandlerValue, FileSystemCacheContext, Revalidate, SerializedCacheData } from '../types.js';
|
|
2
|
+
import { type Logger } from '../utils/logger.js';
|
|
3
|
+
/**
|
|
4
|
+
* Reset the build invalidation check flag.
|
|
5
|
+
* Useful for testing purposes.
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export declare function resetBuildInvalidationCheck(): void;
|
|
9
|
+
export interface BuildMeta {
|
|
10
|
+
buildId: string;
|
|
11
|
+
timestamp: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Abstract base class for cache handlers.
|
|
15
|
+
* Provides shared functionality for tag mapping, serialization, and build invalidation.
|
|
16
|
+
*/
|
|
17
|
+
export declare abstract class BaseCacheHandler {
|
|
18
|
+
protected readonly context: FileSystemCacheContext;
|
|
19
|
+
protected readonly handlerName: string;
|
|
20
|
+
protected readonly log: Logger;
|
|
21
|
+
constructor(context: FileSystemCacheContext, handlerName: string);
|
|
22
|
+
/**
|
|
23
|
+
* Initialize the handler. Should be called after construction.
|
|
24
|
+
* Handles build invalidation check and tags mapping initialization.
|
|
25
|
+
*/
|
|
26
|
+
protected initialize(): Promise<void>;
|
|
27
|
+
protected abstract initializeTagsMapping(): Promise<void>;
|
|
28
|
+
protected abstract readTagsMapping(): Promise<Record<string, string[]>>;
|
|
29
|
+
protected abstract writeTagsMapping(tagsMapping: Record<string, string[]>): Promise<void>;
|
|
30
|
+
protected abstract readCacheEntry(cacheKey: string, cacheType: 'fetch' | 'route'): Promise<CacheHandlerValue | null>;
|
|
31
|
+
protected abstract writeCacheEntry(cacheKey: string, cacheValue: CacheHandlerValue, cacheType: 'fetch' | 'route'): Promise<void>;
|
|
32
|
+
protected abstract deleteCacheEntry(cacheKey: string, cacheType: 'fetch' | 'route'): Promise<void>;
|
|
33
|
+
protected abstract readBuildMeta(): Promise<BuildMeta>;
|
|
34
|
+
protected abstract writeBuildMeta(meta: BuildMeta): Promise<void>;
|
|
35
|
+
protected abstract invalidateRouteCache(): Promise<void>;
|
|
36
|
+
protected updateTagsMapping(cacheKey: string, tags: string[], isDelete?: boolean): Promise<void>;
|
|
37
|
+
protected updateTagsMappingBulkDelete(cacheKeysToDelete: string[], tagsMapping: Record<string, string[]>): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Removes cache keys from all tag mappings they're associated with.
|
|
40
|
+
* This is used when cache entries are deleted to keep the tag mapping consistent.
|
|
41
|
+
* Empty tags are cleaned up automatically.
|
|
42
|
+
*/
|
|
43
|
+
private removeKeysFromAllTags;
|
|
44
|
+
private addKeyToTags;
|
|
45
|
+
private checkBuildInvalidation;
|
|
46
|
+
protected serializeForStorage(data: CacheData): SerializedCacheData;
|
|
47
|
+
protected deserializeFromStorage(data: SerializedCacheData): CacheData;
|
|
48
|
+
protected determineCacheType(ctx?: CacheHandlerParametersGet[1]): 'fetch' | 'route';
|
|
49
|
+
protected determineCacheTypeFromValue(incrementalCacheValue: CacheHandlerParametersSet[1]): 'fetch' | 'route';
|
|
50
|
+
get(cacheKey: CacheHandlerParametersGet[0], ctx?: CacheHandlerParametersGet[1]): Promise<CacheHandlerValue | null>;
|
|
51
|
+
set(cacheKey: CacheHandlerParametersSet[0], incrementalCacheValue: CacheHandlerParametersSet[1], ctx: CacheHandlerParametersSet[2] & {
|
|
52
|
+
tags?: string[];
|
|
53
|
+
revalidate?: Revalidate;
|
|
54
|
+
}): Promise<void>;
|
|
55
|
+
revalidateTag(tag: CacheHandlerParametersRevalidateTag[0]): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Hook called after revalidation is complete.
|
|
58
|
+
* Subclasses can override to perform additional cleanup.
|
|
59
|
+
*/
|
|
60
|
+
protected onRevalidateComplete(_tags: string[], _deletedKeys: string[]): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Hook called when a route cache entry is set (ISR page update).
|
|
63
|
+
* Subclasses can override to perform edge cache invalidation.
|
|
64
|
+
*/
|
|
65
|
+
protected onRouteCacheSet(_cacheKey: string): void;
|
|
66
|
+
private tryDeleteCacheEntry;
|
|
67
|
+
resetRequestCache(): void;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/handlers/base.ts"],"names":[],"mappings":"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"}
|