@pantheon-systems/nextjs-cache-handler 0.1.0 → 0.2.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 (58) hide show
  1. package/README.md +110 -0
  2. package/dist/handlers/base.d.ts +9 -0
  3. package/dist/handlers/base.d.ts.map +1 -1
  4. package/dist/handlers/base.js +22 -0
  5. package/dist/handlers/base.js.map +1 -1
  6. package/dist/index.d.ts +5 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +15 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/middleware/index.d.ts +2 -0
  11. package/dist/middleware/index.d.ts.map +1 -0
  12. package/dist/middleware/index.js +2 -0
  13. package/dist/middleware/index.js.map +1 -0
  14. package/dist/middleware/surrogate-key.d.ts +29 -0
  15. package/dist/middleware/surrogate-key.d.ts.map +1 -0
  16. package/dist/middleware/surrogate-key.js +66 -0
  17. package/dist/middleware/surrogate-key.js.map +1 -0
  18. package/dist/use-cache/file-handler.d.ts +71 -0
  19. package/dist/use-cache/file-handler.d.ts.map +1 -0
  20. package/dist/use-cache/file-handler.js +366 -0
  21. package/dist/use-cache/file-handler.js.map +1 -0
  22. package/dist/use-cache/gcs-handler.d.ts +64 -0
  23. package/dist/use-cache/gcs-handler.d.ts.map +1 -0
  24. package/dist/use-cache/gcs-handler.js +406 -0
  25. package/dist/use-cache/gcs-handler.js.map +1 -0
  26. package/dist/use-cache/index.d.ts +58 -0
  27. package/dist/use-cache/index.d.ts.map +1 -0
  28. package/dist/use-cache/index.js +87 -0
  29. package/dist/use-cache/index.js.map +1 -0
  30. package/dist/use-cache/stream-serialization.d.ts +34 -0
  31. package/dist/use-cache/stream-serialization.d.ts.map +1 -0
  32. package/dist/use-cache/stream-serialization.js +96 -0
  33. package/dist/use-cache/stream-serialization.js.map +1 -0
  34. package/dist/use-cache/types.d.ts +202 -0
  35. package/dist/use-cache/types.d.ts.map +1 -0
  36. package/dist/use-cache/types.js +9 -0
  37. package/dist/use-cache/types.js.map +1 -0
  38. package/dist/utils/cache-tag-context.d.ts +66 -0
  39. package/dist/utils/cache-tag-context.d.ts.map +1 -0
  40. package/dist/utils/cache-tag-context.js +126 -0
  41. package/dist/utils/cache-tag-context.js.map +1 -0
  42. package/dist/utils/index.d.ts +3 -0
  43. package/dist/utils/index.d.ts.map +1 -1
  44. package/dist/utils/index.js +3 -0
  45. package/dist/utils/index.js.map +1 -1
  46. package/dist/utils/request-context.d.ts +28 -0
  47. package/dist/utils/request-context.d.ts.map +1 -0
  48. package/dist/utils/request-context.js +54 -0
  49. package/dist/utils/request-context.js.map +1 -0
  50. package/dist/utils/request-context.test.d.ts +2 -0
  51. package/dist/utils/request-context.test.d.ts.map +1 -0
  52. package/dist/utils/request-context.test.js +65 -0
  53. package/dist/utils/request-context.test.js.map +1 -0
  54. package/dist/utils/with-surrogate-key.d.ts +32 -0
  55. package/dist/utils/with-surrogate-key.d.ts.map +1 -0
  56. package/dist/utils/with-surrogate-key.js +113 -0
  57. package/dist/utils/with-surrogate-key.js.map +1 -0
  58. package/package.json +15 -1
@@ -0,0 +1,406 @@
1
+ import { Storage } from '@google-cloud/storage';
2
+ import { serializeUseCacheEntry, deserializeUseCacheEntry, } from './stream-serialization.js';
3
+ import { createLogger } from '../utils/logger.js';
4
+ import { createEdgeCacheClearer } from '../edge/edge-cache-clear.js';
5
+ const log = createLogger('UseCacheGcsHandler');
6
+ /**
7
+ * Next.js internal prefix for path-based cache tags.
8
+ * When revalidatePath('/api/foo') is called, Next.js internally calls
9
+ * revalidateTag('_N_T_/api/foo'). This prefix identifies path tags.
10
+ */
11
+ const NEXTJS_PATH_TAG_PREFIX = '_N_T_';
12
+ /**
13
+ * Symbol used to access CacheTagContext from globalThis.
14
+ * This matches the Symbol.for pattern used by Next.js for @next/request-context.
15
+ */
16
+ const CACHE_TAG_CONTEXT_SYMBOL = Symbol.for('@nextjs-cache-handler/tag-context');
17
+ /**
18
+ * Symbol used to expose registerPathTags on globalThis.
19
+ * This allows withSurrogateKey (which knows the request path and captured tags)
20
+ * to register path→surrogate-key mappings without a direct module import.
21
+ */
22
+ const PATH_TAGS_REGISTRY_SYMBOL = Symbol.for('@nextjs-cache-handler/path-tags-registry');
23
+ /**
24
+ * Access the CacheTagContext via globalThis using Symbol.for.
25
+ * This allows cross-context access without direct module imports.
26
+ */
27
+ function getCacheTagContext() {
28
+ const accessor = globalThis[CACHE_TAG_CONTEXT_SYMBOL];
29
+ return accessor?.get();
30
+ }
31
+ /**
32
+ * Add tags to the CacheTagContext if available.
33
+ * Falls back to global store if CacheTagContext is not active.
34
+ */
35
+ function captureTags(tags) {
36
+ if (tags.length === 0) {
37
+ return { captured: false, source: 'none' };
38
+ }
39
+ // Primary: Try CacheTagContext (Symbol.for pattern)
40
+ const context = getCacheTagContext();
41
+ if (context) {
42
+ context.tags.push(...tags);
43
+ log.debug(`Captured ${tags.length} tags via CacheTagContext: ${tags.join(', ')}`);
44
+ return { captured: true, source: 'CacheTagContext' };
45
+ }
46
+ // Fallback: Use global store (for environments where Symbol.for doesn't propagate)
47
+ let globalTags = globalThis.__pantheonSurrogateKeyTags;
48
+ if (!globalTags) {
49
+ globalTags = [];
50
+ globalThis.__pantheonSurrogateKeyTags = globalTags;
51
+ }
52
+ globalTags.push(...tags);
53
+ log.debug(`Captured ${tags.length} tags via globalStore fallback: ${tags.join(', ')}`);
54
+ return { captured: true, source: 'globalStore' };
55
+ }
56
+ /**
57
+ * Google Cloud Storage cache handler for Next.js 16 'use cache' directive.
58
+ * Implements the cacheHandlers (plural) interface.
59
+ *
60
+ * Suitable for:
61
+ * - Production/Pantheon environments
62
+ * - Multi-instance deployments requiring shared cache
63
+ */
64
+ export class UseCacheGcsHandler {
65
+ constructor() {
66
+ this.tagTimestamps = new Map();
67
+ this.pathToSurrogateKeys = new Map();
68
+ this.initialized = false;
69
+ this.initPromise = null;
70
+ const bucketName = process.env.CACHE_BUCKET;
71
+ if (!bucketName) {
72
+ throw new Error('CACHE_BUCKET environment variable is required for GCS cache handler');
73
+ }
74
+ const storage = new Storage();
75
+ this.bucket = storage.bucket(bucketName);
76
+ this.cachePrefix = 'use-cache/';
77
+ this.tagsKey = `${this.cachePrefix}_tags.json`;
78
+ this.edgeCacheClearer = createEdgeCacheClearer();
79
+ // Expose registerPathTags on globalThis so withSurrogateKey can register
80
+ // path→surrogate-key mappings without direct module coupling
81
+ globalThis[PATH_TAGS_REGISTRY_SYMBOL] =
82
+ (path, tags) => this.registerPathTags(path, tags);
83
+ // Initialize asynchronously but track the promise
84
+ this.initPromise = this.initialize().catch(() => { });
85
+ log.info('Initialized GCS use-cache handler');
86
+ }
87
+ async initialize() {
88
+ if (this.initialized)
89
+ return;
90
+ await this.loadTagTimestamps();
91
+ this.initialized = true;
92
+ }
93
+ async ensureInitialized() {
94
+ if (this.initPromise) {
95
+ await this.initPromise;
96
+ this.initPromise = null;
97
+ }
98
+ }
99
+ async loadTagTimestamps() {
100
+ try {
101
+ const file = this.bucket.file(this.tagsKey);
102
+ const [exists] = await file.exists();
103
+ if (!exists) {
104
+ // Only reset if not already populated by local operations
105
+ if (this.tagTimestamps.size === 0) {
106
+ this.tagTimestamps = new Map();
107
+ }
108
+ return;
109
+ }
110
+ const [data] = await file.download();
111
+ const parsed = JSON.parse(data.toString());
112
+ // Merge with existing in-memory state (local updates take precedence)
113
+ const loadedTimestamps = new Map(Object.entries(parsed));
114
+ for (const [tag, timestamp] of loadedTimestamps) {
115
+ const existing = this.tagTimestamps.get(tag);
116
+ if (!existing || timestamp > existing) {
117
+ this.tagTimestamps.set(tag, timestamp);
118
+ }
119
+ }
120
+ }
121
+ catch (error) {
122
+ log.warn('Error loading tag timestamps:', error);
123
+ // Don't reset - keep existing in-memory state
124
+ }
125
+ }
126
+ async saveTagTimestamps() {
127
+ try {
128
+ const obj = Object.fromEntries(this.tagTimestamps);
129
+ const file = this.bucket.file(this.tagsKey);
130
+ await file.save(JSON.stringify(obj, null, 2), {
131
+ metadata: { contentType: 'application/json' },
132
+ });
133
+ }
134
+ catch (error) {
135
+ log.error('Error saving tag timestamps:', error);
136
+ }
137
+ }
138
+ getCacheKey(cacheKey) {
139
+ // Sanitize cache key for GCS object naming
140
+ const safeKey = cacheKey.replace(/[^a-zA-Z0-9-]/g, '_');
141
+ return `${this.cachePrefix}${safeKey}.json`;
142
+ }
143
+ /**
144
+ * Check if an entry is expired based on revalidate time.
145
+ */
146
+ isExpired(entry) {
147
+ const now = Date.now();
148
+ const age = now - entry.timestamp;
149
+ const revalidateMs = entry.revalidate * 1000;
150
+ // Entry is expired if it's older than revalidate time
151
+ if (age > revalidateMs) {
152
+ return true;
153
+ }
154
+ // Also check if any of the entry's tags have been invalidated
155
+ for (const tag of entry.tags) {
156
+ const tagTimestamp = this.tagTimestamps.get(tag);
157
+ if (tagTimestamp && tagTimestamp > entry.timestamp) {
158
+ return true;
159
+ }
160
+ }
161
+ return false;
162
+ }
163
+ /**
164
+ * Retrieve a cache entry.
165
+ */
166
+ async get(cacheKey, softTags) {
167
+ log.debug(`GET: ${cacheKey}`);
168
+ try {
169
+ const gcsKey = this.getCacheKey(cacheKey);
170
+ const file = this.bucket.file(gcsKey);
171
+ const [exists] = await file.exists();
172
+ if (!exists) {
173
+ log.debug(`MISS: ${cacheKey} (not found)`);
174
+ return undefined;
175
+ }
176
+ const [data] = await file.download();
177
+ const stored = JSON.parse(data.toString());
178
+ const entry = deserializeUseCacheEntry(stored);
179
+ // Check expiration
180
+ if (this.isExpired(entry)) {
181
+ log.debug(`MISS: ${cacheKey} (expired)`);
182
+ // Optionally delete expired entry
183
+ try {
184
+ await file.delete();
185
+ }
186
+ catch {
187
+ // Ignore deletion errors
188
+ }
189
+ return undefined;
190
+ }
191
+ log.debug(`HIT: ${cacheKey}`);
192
+ // Capture tags for Surrogate-Key header propagation
193
+ // Uses Symbol.for pattern to access PantheonContext across async boundaries
194
+ const storedTags = entry.tags ?? [];
195
+ const { captured, source } = captureTags(storedTags);
196
+ if (captured) {
197
+ log.debug(`HIT ${cacheKey}: Captured ${storedTags.length} tags via ${source}`);
198
+ }
199
+ else if (storedTags.length === 0) {
200
+ // TODO: Remove this diagnostic logging once Next.js fixes the empty tags bug
201
+ // See: https://github.com/vercel/next.js/issues/78864
202
+ log.info(`HIT ${cacheKey}: No tags to capture (Next.js empty tags bug)`);
203
+ }
204
+ return entry;
205
+ }
206
+ catch (error) {
207
+ log.error(`Error reading cache for key ${cacheKey}:`, error);
208
+ return undefined;
209
+ }
210
+ }
211
+ /**
212
+ * Store a cache entry.
213
+ * CRITICAL: Must await pendingEntry before storing.
214
+ */
215
+ async set(cacheKey, pendingEntry) {
216
+ log.debug(`SET: ${cacheKey}`);
217
+ try {
218
+ // CRITICAL: Await the pending entry
219
+ const entry = await pendingEntry;
220
+ // TODO: Remove this diagnostic logging once Next.js fixes the empty tags bug
221
+ // Diagnostic logging for empty tags issue
222
+ // See: https://github.com/vercel/next.js/issues/78864
223
+ // See: docs/known-issues-nextjs16.md
224
+ const tagsLength = entry.tags?.length ?? 0;
225
+ if (tagsLength === 0) {
226
+ // Use info level so this is gated behind CACHE_DEBUG
227
+ log.info(`[EMPTY_TAGS_BUG] SET ${cacheKey}: Next.js passed empty tags array. ` +
228
+ `This is a known Next.js bug - cacheTag() values are not propagated to cacheHandlers.set(). ` +
229
+ `See: https://github.com/vercel/next.js/issues/78864`);
230
+ }
231
+ log.info(`SET entry structure for ${cacheKey}:`, {
232
+ hasTags: !!entry.tags,
233
+ tags: entry.tags,
234
+ tagsLength,
235
+ stale: entry.stale,
236
+ revalidate: entry.revalidate,
237
+ expire: entry.expire,
238
+ timestamp: entry.timestamp,
239
+ hasValue: !!entry.value,
240
+ entryKeys: Object.keys(entry),
241
+ });
242
+ const serialized = await serializeUseCacheEntry(entry);
243
+ const gcsKey = this.getCacheKey(cacheKey);
244
+ const file = this.bucket.file(gcsKey);
245
+ await file.save(JSON.stringify(serialized, null, 2), {
246
+ metadata: { contentType: 'application/json' },
247
+ });
248
+ log.debug(`Cached ${cacheKey}`);
249
+ }
250
+ catch (error) {
251
+ log.error(`Error setting cache for key ${cacheKey}:`, error);
252
+ }
253
+ }
254
+ /**
255
+ * Synchronize tag state from external source.
256
+ * Reloads tag timestamps from GCS.
257
+ */
258
+ async refreshTags() {
259
+ log.debug('REFRESH TAGS');
260
+ await this.loadTagTimestamps();
261
+ }
262
+ /**
263
+ * Return maximum revalidation timestamp for given tags.
264
+ */
265
+ async getExpiration(tags) {
266
+ let maxTimestamp = 0;
267
+ for (const tag of tags) {
268
+ const timestamp = this.tagTimestamps.get(tag) ?? 0;
269
+ if (timestamp > maxTimestamp) {
270
+ maxTimestamp = timestamp;
271
+ }
272
+ }
273
+ log.debug(`GET EXPIRATION for [${tags.join(', ')}]: ${maxTimestamp}`);
274
+ return maxTimestamp;
275
+ }
276
+ /**
277
+ * Register the surrogate keys (explicit cacheTag values) associated with a path.
278
+ * Called by withSurrogateKey when tags are captured during a cache HIT,
279
+ * enabling revalidatePath to resolve the correct CDN surrogate keys.
280
+ */
281
+ registerPathTags(path, surrogateKeys) {
282
+ this.pathToSurrogateKeys.set(path, surrogateKeys);
283
+ log.debug(`Registered path tags: ${path} → [${surrogateKeys.join(', ')}]`);
284
+ }
285
+ /**
286
+ * Invalidate cache entries with matching tags.
287
+ */
288
+ async updateTags(tags, durations) {
289
+ log.debug(`UPDATE TAGS: [${tags.join(', ')}]`);
290
+ if (tags.length === 0) {
291
+ return;
292
+ }
293
+ const now = Date.now();
294
+ for (const tag of tags) {
295
+ this.tagTimestamps.set(tag, now);
296
+ }
297
+ await this.saveTagTimestamps();
298
+ // Clear edge cache if configured
299
+ if (this.edgeCacheClearer) {
300
+ // Separate explicit tags from _N_T_ path tags
301
+ const explicitTags = [];
302
+ const pathTags = [];
303
+ for (const tag of tags) {
304
+ if (tag.startsWith(NEXTJS_PATH_TAG_PREFIX)) {
305
+ pathTags.push(tag);
306
+ }
307
+ else {
308
+ explicitTags.push(tag);
309
+ }
310
+ }
311
+ // Purge explicit tags as surrogate keys (these match CDN Surrogate-Key headers directly)
312
+ if (explicitTags.length > 0) {
313
+ this.edgeCacheClearer.clearKeysInBackground(explicitTags, `use-cache tag invalidation: ${explicitTags.join(', ')}`);
314
+ }
315
+ // Resolve _N_T_ path tags to surrogate keys via the registered mapping
316
+ if (pathTags.length > 0) {
317
+ const resolvedKeys = [];
318
+ const unresolvedPaths = [];
319
+ for (const pathTag of pathTags) {
320
+ const path = pathTag.substring(NEXTJS_PATH_TAG_PREFIX.length);
321
+ const surrogateKeys = this.pathToSurrogateKeys.get(path);
322
+ if (surrogateKeys && surrogateKeys.length > 0) {
323
+ resolvedKeys.push(...surrogateKeys);
324
+ log.debug(`Resolved path tag ${pathTag} → surrogate keys: [${surrogateKeys.join(', ')}]`);
325
+ }
326
+ else {
327
+ unresolvedPaths.push(path);
328
+ log.debug(`No surrogate key mapping for path tag ${pathTag}, falling back to path purge`);
329
+ }
330
+ }
331
+ // Purge resolved surrogate keys
332
+ if (resolvedKeys.length > 0) {
333
+ this.edgeCacheClearer.clearKeysInBackground(resolvedKeys, `path revalidation (resolved): ${resolvedKeys.join(', ')}`);
334
+ }
335
+ // Fallback: attempt path-based purge for unmapped paths
336
+ if (unresolvedPaths.length > 0) {
337
+ this.edgeCacheClearer.clearPathsInBackground(unresolvedPaths, `path revalidation (fallback): ${unresolvedPaths.join(', ')}`);
338
+ }
339
+ }
340
+ }
341
+ }
342
+ /**
343
+ * Get cache statistics for the use-cache entries in GCS.
344
+ * Returns information about all valid (non-expired) cache entries.
345
+ */
346
+ async getStats() {
347
+ log.debug('GET STATS');
348
+ const entries = [];
349
+ const keys = [];
350
+ try {
351
+ await this.ensureInitialized();
352
+ // List all files in the use-cache prefix
353
+ const [files] = await this.bucket.getFiles({ prefix: this.cachePrefix });
354
+ for (const file of files) {
355
+ // Skip tags file
356
+ if (file.name === this.tagsKey) {
357
+ continue;
358
+ }
359
+ // Only process .json files
360
+ if (!file.name.endsWith('.json')) {
361
+ continue;
362
+ }
363
+ try {
364
+ const [data] = await file.download();
365
+ const stored = JSON.parse(data.toString());
366
+ // Extract key from filename (remove prefix and .json suffix)
367
+ const key = file.name.replace(this.cachePrefix, '').replace('.json', '');
368
+ // Deserialize to check expiration
369
+ const entry = deserializeUseCacheEntry(stored);
370
+ // Skip expired entries
371
+ if (this.isExpired(entry)) {
372
+ continue;
373
+ }
374
+ // Get file metadata for size
375
+ const [metadata] = await file.getMetadata();
376
+ const entryInfo = {
377
+ key,
378
+ tags: stored.tags || [],
379
+ type: 'use-cache',
380
+ lastModified: new Date(entry.timestamp).toISOString(),
381
+ size: Number(metadata.size) || 0,
382
+ revalidate: entry.revalidate,
383
+ stale: entry.stale,
384
+ expire: entry.expire,
385
+ };
386
+ entries.push(entryInfo);
387
+ keys.push(key);
388
+ }
389
+ catch (error) {
390
+ log.warn(`Error reading cache file ${file.name}:`, error);
391
+ }
392
+ }
393
+ }
394
+ catch (error) {
395
+ log.error('Error getting cache stats:', error);
396
+ }
397
+ log.debug(`Found ${entries.length} valid cache entries`);
398
+ return {
399
+ size: entries.length,
400
+ entries,
401
+ keys,
402
+ };
403
+ }
404
+ }
405
+ export default UseCacheGcsHandler;
406
+ //# sourceMappingURL=gcs-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gcs-handler.js","sourceRoot":"","sources":["../../src/use-cache/gcs-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Next.js 16 'use cache' Handler Module
3
+ *
4
+ * This module provides cache handlers for the new `cacheHandlers` (plural)
5
+ * configuration in Next.js 16, which supports the `'use cache'` directive.
6
+ *
7
+ * @example
8
+ * ```javascript
9
+ * // next.config.mjs
10
+ * import { createUseCacheHandler } from '@pantheon-systems/nextjs-cache-handler/use-cache';
11
+ *
12
+ * const nextConfig = {
13
+ * // Existing handler for ISR, routes, fetch cache
14
+ * cacheHandler: require.resolve('./cache-handler.mjs'),
15
+ *
16
+ * // NEW handler for 'use cache' directive
17
+ * cacheHandlers: {
18
+ * default: require.resolve('./use-cache-handler.mjs'),
19
+ * },
20
+ *
21
+ * cacheComponents: true,
22
+ * };
23
+ *
24
+ * export default nextConfig;
25
+ * ```
26
+ */
27
+ import type { UseCacheHandlerConfig } from './types.js';
28
+ import { UseCacheFileHandler } from './file-handler.js';
29
+ import { UseCacheGcsHandler } from './gcs-handler.js';
30
+ /**
31
+ * Factory function to create a use cache handler based on configuration.
32
+ *
33
+ * @param config - Configuration options for the cache handler
34
+ * @returns A cache handler class that implements the cacheHandlers interface
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * // In your use-cache-handler.ts file:
39
+ * import { createUseCacheHandler } from '@pantheon-systems/nextjs-cache-handler/use-cache';
40
+ *
41
+ * const UseCacheHandler = createUseCacheHandler({
42
+ * type: 'auto', // Auto-detect: GCS if CACHE_BUCKET exists, else file-based
43
+ * });
44
+ *
45
+ * export default UseCacheHandler;
46
+ * ```
47
+ */
48
+ export declare function createUseCacheHandler(config?: UseCacheHandlerConfig): typeof UseCacheFileHandler | typeof UseCacheGcsHandler;
49
+ export { UseCacheFileHandler } from './file-handler.js';
50
+ export { UseCacheGcsHandler } from './gcs-handler.js';
51
+ export type { UseCacheEntry, UseCacheHandler, UseCacheHandlerConfig, SerializedUseCacheEntry, UseCacheStats, UseCacheEntryInfo, } from './types.js';
52
+ /**
53
+ * Get cache statistics for use-cache entries.
54
+ * Automatically detects whether to use file-based or GCS cache stats.
55
+ */
56
+ export declare function getUseCacheStats(): Promise<import('./types.js').UseCacheStats>;
57
+ export { streamToBytes, bytesToStream, serializeUseCacheEntry, deserializeUseCacheEntry, } from './stream-serialization.js';
58
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/use-cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,CAAC,EAAE,qBAAqB,GAC7B,OAAO,mBAAmB,GAAG,OAAO,kBAAkB,CAQxD;AAkBD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAMtD,YAAY,EACV,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,uBAAuB,EACvB,aAAa,EACb,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAMpB;;;GAGG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,YAAY,EAAE,aAAa,CAAC,CAOpF;AAMD,OAAO,EACL,aAAa,EACb,aAAa,EACb,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Next.js 16 'use cache' Handler Module
3
+ *
4
+ * This module provides cache handlers for the new `cacheHandlers` (plural)
5
+ * configuration in Next.js 16, which supports the `'use cache'` directive.
6
+ *
7
+ * @example
8
+ * ```javascript
9
+ * // next.config.mjs
10
+ * import { createUseCacheHandler } from '@pantheon-systems/nextjs-cache-handler/use-cache';
11
+ *
12
+ * const nextConfig = {
13
+ * // Existing handler for ISR, routes, fetch cache
14
+ * cacheHandler: require.resolve('./cache-handler.mjs'),
15
+ *
16
+ * // NEW handler for 'use cache' directive
17
+ * cacheHandlers: {
18
+ * default: require.resolve('./use-cache-handler.mjs'),
19
+ * },
20
+ *
21
+ * cacheComponents: true,
22
+ * };
23
+ *
24
+ * export default nextConfig;
25
+ * ```
26
+ */
27
+ import { UseCacheFileHandler } from './file-handler.js';
28
+ import { UseCacheGcsHandler } from './gcs-handler.js';
29
+ /**
30
+ * Factory function to create a use cache handler based on configuration.
31
+ *
32
+ * @param config - Configuration options for the cache handler
33
+ * @returns A cache handler class that implements the cacheHandlers interface
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * // In your use-cache-handler.ts file:
38
+ * import { createUseCacheHandler } from '@pantheon-systems/nextjs-cache-handler/use-cache';
39
+ *
40
+ * const UseCacheHandler = createUseCacheHandler({
41
+ * type: 'auto', // Auto-detect: GCS if CACHE_BUCKET exists, else file-based
42
+ * });
43
+ *
44
+ * export default UseCacheHandler;
45
+ * ```
46
+ */
47
+ export function createUseCacheHandler(config) {
48
+ const type = config?.type ?? 'auto';
49
+ if (shouldUseGcs(type)) {
50
+ return UseCacheGcsHandler;
51
+ }
52
+ return UseCacheFileHandler;
53
+ }
54
+ function shouldUseGcs(type) {
55
+ if (type === 'gcs') {
56
+ return true;
57
+ }
58
+ if (type === 'auto') {
59
+ return !!process.env.CACHE_BUCKET;
60
+ }
61
+ return false;
62
+ }
63
+ // ============================================================================
64
+ // Handler exports
65
+ // ============================================================================
66
+ export { UseCacheFileHandler } from './file-handler.js';
67
+ export { UseCacheGcsHandler } from './gcs-handler.js';
68
+ // ============================================================================
69
+ // Stats function
70
+ // ============================================================================
71
+ /**
72
+ * Get cache statistics for use-cache entries.
73
+ * Automatically detects whether to use file-based or GCS cache stats.
74
+ */
75
+ export async function getUseCacheStats() {
76
+ if (process.env.CACHE_BUCKET) {
77
+ const handler = new UseCacheGcsHandler();
78
+ return handler.getStats();
79
+ }
80
+ const handler = new UseCacheFileHandler();
81
+ return handler.getStats();
82
+ }
83
+ // ============================================================================
84
+ // Utility exports
85
+ // ============================================================================
86
+ export { streamToBytes, bytesToStream, serializeUseCacheEntry, deserializeUseCacheEntry, } from './stream-serialization.js';
87
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/use-cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAA8B;IAE9B,MAAM,IAAI,GAAG,MAAM,EAAE,IAAI,IAAI,MAAM,CAAC;IAEpC,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IAED,OAAO,mBAAmB,CAAC;AAC7B,CAAC;AAED,SAAS,YAAY,CAAC,IAA6B;IACjD,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IACpC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+EAA+E;AAC/E,kBAAkB;AAClB,+EAA+E;AAE/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAetD,+EAA+E;AAC/E,iBAAiB;AACjB,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,IAAI,kBAAkB,EAAE,CAAC;QACzC,OAAO,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC5B,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,mBAAmB,EAAE,CAAC;IAC1C,OAAO,OAAO,CAAC,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED,+EAA+E;AAC/E,kBAAkB;AAClB,+EAA+E;AAE/E,OAAO,EACL,aAAa,EACb,aAAa,EACb,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,34 @@
1
+ import type { UseCacheEntry, SerializedUseCacheEntry } from './types.js';
2
+ /**
3
+ * Convert a ReadableStream<Uint8Array> to a Uint8Array.
4
+ * Consumes the entire stream and concatenates all chunks.
5
+ *
6
+ * @param stream - The stream to consume
7
+ * @returns A single Uint8Array containing all the stream data
8
+ */
9
+ export declare function streamToBytes(stream: ReadableStream<Uint8Array>): Promise<Uint8Array>;
10
+ /**
11
+ * Convert a Uint8Array to a ReadableStream<Uint8Array>.
12
+ * Creates a stream that emits the entire array as a single chunk.
13
+ *
14
+ * @param bytes - The bytes to convert to a stream
15
+ * @returns A ReadableStream that emits the bytes
16
+ */
17
+ export declare function bytesToStream(bytes: Uint8Array): ReadableStream<Uint8Array>;
18
+ /**
19
+ * Serialize a UseCacheEntry for persistent storage.
20
+ * Converts the ReadableStream value to a base64-encoded string.
21
+ *
22
+ * @param entry - The cache entry to serialize
23
+ * @returns A serialized entry suitable for JSON storage
24
+ */
25
+ export declare function serializeUseCacheEntry(entry: UseCacheEntry): Promise<SerializedUseCacheEntry>;
26
+ /**
27
+ * Deserialize a stored cache entry back to UseCacheEntry.
28
+ * Converts the base64-encoded value back to a ReadableStream.
29
+ *
30
+ * @param stored - The serialized entry from storage
31
+ * @returns A UseCacheEntry with a ReadableStream value
32
+ */
33
+ export declare function deserializeUseCacheEntry(stored: SerializedUseCacheEntry): UseCacheEntry;
34
+ //# sourceMappingURL=stream-serialization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-serialization.d.ts","sourceRoot":"","sources":["../../src/use-cache/stream-serialization.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAEzE;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAgC3F;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,CAO3E;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAenG;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,uBAAuB,GAAG,aAAa,CAkBvF"}