@mrjasonroy/cache-components-cache-handler 16.0.0-alpha.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 (50) hide show
  1. package/README.md +437 -0
  2. package/dist/data-cache/memory.d.ts +47 -0
  3. package/dist/data-cache/memory.d.ts.map +1 -0
  4. package/dist/data-cache/memory.js +310 -0
  5. package/dist/data-cache/memory.js.map +1 -0
  6. package/dist/data-cache/redis.d.ts +83 -0
  7. package/dist/data-cache/redis.d.ts.map +1 -0
  8. package/dist/data-cache/redis.js +240 -0
  9. package/dist/data-cache/redis.js.map +1 -0
  10. package/dist/data-cache/types.d.ts +85 -0
  11. package/dist/data-cache/types.d.ts.map +1 -0
  12. package/dist/data-cache/types.js +7 -0
  13. package/dist/data-cache/types.js.map +1 -0
  14. package/dist/handlers/composite.d.ts +70 -0
  15. package/dist/handlers/composite.d.ts.map +1 -0
  16. package/dist/handlers/composite.js +123 -0
  17. package/dist/handlers/composite.js.map +1 -0
  18. package/dist/handlers/memory.d.ts +77 -0
  19. package/dist/handlers/memory.d.ts.map +1 -0
  20. package/dist/handlers/memory.js +145 -0
  21. package/dist/handlers/memory.js.map +1 -0
  22. package/dist/handlers/redis.d.ts +80 -0
  23. package/dist/handlers/redis.d.ts.map +1 -0
  24. package/dist/handlers/redis.js +210 -0
  25. package/dist/handlers/redis.js.map +1 -0
  26. package/dist/helpers/buffer.d.ts +25 -0
  27. package/dist/helpers/buffer.d.ts.map +1 -0
  28. package/dist/helpers/buffer.js +45 -0
  29. package/dist/helpers/buffer.js.map +1 -0
  30. package/dist/helpers/is-implicit-tag.d.ts +9 -0
  31. package/dist/helpers/is-implicit-tag.d.ts.map +1 -0
  32. package/dist/helpers/is-implicit-tag.js +16 -0
  33. package/dist/helpers/is-implicit-tag.js.map +1 -0
  34. package/dist/helpers/lifespan.d.ts +18 -0
  35. package/dist/helpers/lifespan.d.ts.map +1 -0
  36. package/dist/helpers/lifespan.js +43 -0
  37. package/dist/helpers/lifespan.js.map +1 -0
  38. package/dist/helpers/next-config.d.ts +97 -0
  39. package/dist/helpers/next-config.d.ts.map +1 -0
  40. package/dist/helpers/next-config.js +96 -0
  41. package/dist/helpers/next-config.js.map +1 -0
  42. package/dist/index.d.ts +17 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +23 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/types.d.ts +163 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/dist/types.js +9 -0
  49. package/dist/types.js.map +1 -0
  50. package/package.json +67 -0
@@ -0,0 +1,210 @@
1
+ import Redis from "ioredis";
2
+ import { calculateLifespan, isExpired } from "../helpers/lifespan.js";
3
+ /**
4
+ * Redis cache handler for Next.js 16+ with Cache Components support
5
+ *
6
+ * Features:
7
+ * - Persistent caching across server restarts
8
+ * - Tag-based revalidation with Redis Sets
9
+ * - TTL support with automatic expiration
10
+ * - Compatible with Redis, ElastiCache, and Valkey
11
+ * - Connection pooling via ioredis
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * // In cache-handler.mjs or data-cache-handler.mjs
16
+ * import { RedisCacheHandler } from "@mrjasonroy/cache-components-cache-handler/handlers/redis";
17
+ *
18
+ * export default class NextCacheHandler extends RedisCacheHandler {
19
+ * constructor(options) {
20
+ * super({
21
+ * ...options,
22
+ * redis: process.env.REDIS_URL || "redis://localhost:6379",
23
+ * keyPrefix: "nextjs:cache:",
24
+ * defaultTTL: 3600
25
+ * });
26
+ * }
27
+ * }
28
+ * ```
29
+ */
30
+ export class RedisCacheHandler {
31
+ name = "redis";
32
+ redis;
33
+ keyPrefix;
34
+ tagPrefix;
35
+ defaultTTL;
36
+ debug;
37
+ constructor(options = {}) {
38
+ // Initialize Redis connection
39
+ if (typeof options.redis === "string") {
40
+ this.redis = new Redis(options.redis);
41
+ }
42
+ else {
43
+ this.redis = new Redis(options.redis || {});
44
+ }
45
+ this.keyPrefix = options.keyPrefix ?? "nextjs:cache:";
46
+ this.tagPrefix = options.tagPrefix ?? "nextjs:tags:";
47
+ this.defaultTTL = options.defaultTTL;
48
+ this.debug = options.debug ?? false;
49
+ // Handle Redis connection errors
50
+ this.redis.on("error", (err) => {
51
+ console.error("[RedisCacheHandler] Redis connection error:", err);
52
+ });
53
+ if (this.debug) {
54
+ console.log("[RedisCacheHandler] Initialized", {
55
+ keyPrefix: this.keyPrefix,
56
+ tagPrefix: this.tagPrefix,
57
+ defaultTTL: this.defaultTTL,
58
+ });
59
+ }
60
+ }
61
+ log(...args) {
62
+ if (this.debug) {
63
+ console.log("[RedisCacheHandler]", ...args);
64
+ }
65
+ }
66
+ getCacheKey(key) {
67
+ return `${this.keyPrefix}${key}`;
68
+ }
69
+ getTagKey(tag) {
70
+ return `${this.tagPrefix}${tag}`;
71
+ }
72
+ async get(key, meta) {
73
+ try {
74
+ const cacheKey = this.getCacheKey(key);
75
+ this.log("GET", cacheKey);
76
+ // Get the cached entry
77
+ const data = await this.redis.get(cacheKey);
78
+ if (!data) {
79
+ this.log("GET", cacheKey, "MISS");
80
+ return null;
81
+ }
82
+ // Parse the stored entry
83
+ const entry = JSON.parse(data);
84
+ // Check if expired based on lifespan
85
+ if (entry.lifespan && isExpired(entry.lifespan)) {
86
+ this.log("GET", cacheKey, "EXPIRED");
87
+ await this.delete(key);
88
+ return null;
89
+ }
90
+ // Check if any tag (explicit or implicit) has been revalidated
91
+ const allTags = [...entry.tags, ...(meta?.implicitTags ?? [])];
92
+ for (const tag of allTags) {
93
+ const tagKey = this.getTagKey(tag);
94
+ const revalidatedAt = await this.redis.get(tagKey);
95
+ // If tag was revalidated after entry was last modified, entry is stale
96
+ if (revalidatedAt && Number.parseInt(revalidatedAt) > entry.lastModified) {
97
+ this.log("GET", cacheKey, "STALE (tag revalidated)", tag);
98
+ await this.delete(key);
99
+ return null;
100
+ }
101
+ }
102
+ this.log("GET", cacheKey, "HIT");
103
+ return entry.value;
104
+ }
105
+ catch (error) {
106
+ console.error("[RedisCacheHandler] GET error:", error);
107
+ return null;
108
+ }
109
+ }
110
+ async set(key, value, context) {
111
+ try {
112
+ const cacheKey = this.getCacheKey(key);
113
+ // Calculate lifespan and TTL
114
+ const lifespan = calculateLifespan(context?.revalidate, this.defaultTTL);
115
+ const tags = context?.tags ?? [];
116
+ const entry = {
117
+ lastModified: Date.now(),
118
+ lifespan,
119
+ tags,
120
+ value,
121
+ };
122
+ const serialized = JSON.stringify(entry);
123
+ // Determine TTL for Redis
124
+ let ttl;
125
+ if (lifespan?.expireAt) {
126
+ // Use expire time as TTL
127
+ ttl = Math.ceil((lifespan.expireAt - Date.now()) / 1000);
128
+ if (ttl <= 0) {
129
+ this.log("SET", cacheKey, "SKIP (already expired)");
130
+ return;
131
+ }
132
+ }
133
+ // Store in Redis with optional TTL
134
+ if (ttl) {
135
+ await this.redis.setex(cacheKey, ttl, serialized);
136
+ this.log("SET", cacheKey, `TTL=${ttl}s`, `kind=${value.kind}`);
137
+ }
138
+ else {
139
+ await this.redis.set(cacheKey, serialized);
140
+ this.log("SET", cacheKey, "NO_TTL", `kind=${value.kind}`);
141
+ }
142
+ // Track tags -> keys mapping for revalidation
143
+ if (tags.length > 0) {
144
+ const pipeline = this.redis.pipeline();
145
+ for (const tag of tags) {
146
+ const tagKey = this.getTagKey(tag);
147
+ // Use a set to store all cache keys with this tag
148
+ pipeline.sadd(`${tagKey}:keys`, cacheKey);
149
+ // Set expiration on the tag's key set if we have a TTL
150
+ if (ttl) {
151
+ pipeline.expire(`${tagKey}:keys`, ttl);
152
+ }
153
+ }
154
+ await pipeline.exec();
155
+ this.log("SET", cacheKey, "tags:", tags);
156
+ }
157
+ }
158
+ catch (error) {
159
+ console.error("[RedisCacheHandler] SET error:", error);
160
+ }
161
+ }
162
+ async revalidateTag(tag, _profile) {
163
+ try {
164
+ const tagKey = this.getTagKey(tag);
165
+ // Store revalidation timestamp
166
+ await this.redis.set(tagKey, Date.now().toString());
167
+ this.log("revalidateTag", tag);
168
+ // Delete all cache keys associated with this tag
169
+ const keysSetKey = `${tagKey}:keys`;
170
+ const cacheKeys = await this.redis.smembers(keysSetKey);
171
+ if (cacheKeys.length > 0) {
172
+ const pipeline = this.redis.pipeline();
173
+ for (const cacheKey of cacheKeys) {
174
+ pipeline.del(cacheKey);
175
+ }
176
+ // Clear the tag's keys set
177
+ pipeline.del(keysSetKey);
178
+ await pipeline.exec();
179
+ this.log("revalidateTag", tag, `deleted ${cacheKeys.length} entries`);
180
+ }
181
+ }
182
+ catch (error) {
183
+ console.error("[RedisCacheHandler] revalidateTag error:", error);
184
+ }
185
+ }
186
+ async delete(key) {
187
+ try {
188
+ const cacheKey = this.getCacheKey(key);
189
+ await this.redis.del(cacheKey);
190
+ this.log("DELETE", cacheKey);
191
+ }
192
+ catch (error) {
193
+ console.error("[RedisCacheHandler] DELETE error:", error);
194
+ }
195
+ }
196
+ /**
197
+ * Close the Redis connection
198
+ * Call this when shutting down your application
199
+ */
200
+ async close() {
201
+ try {
202
+ await this.redis.quit();
203
+ this.log("Connection closed");
204
+ }
205
+ catch (error) {
206
+ console.error("[RedisCacheHandler] close error:", error);
207
+ }
208
+ }
209
+ }
210
+ //# sourceMappingURL=redis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/handlers/redis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Buffer conversion utilities for Next.js 15+ compatibility
3
+ * Next.js 15 changed body/rscData from strings to Buffers
4
+ */
5
+ /**
6
+ * Convert a value to base64 string if it's a Buffer
7
+ * Used when storing cache values (e.g., in Redis)
8
+ *
9
+ * @param value - Value that might be a Buffer
10
+ * @returns Base64 string if Buffer, original value otherwise
11
+ */
12
+ export declare function bufferToString(value: unknown): unknown;
13
+ /**
14
+ * Convert a base64 string back to Buffer if it was originally a Buffer
15
+ * Used when retrieving cache values (e.g., from Redis)
16
+ *
17
+ * This is a simplified version - in production you'd need to track
18
+ * which fields were originally Buffers
19
+ *
20
+ * @param value - Value that might be a base64 string
21
+ * @param isBuffer - Whether this value should be converted to Buffer
22
+ * @returns Buffer if isBuffer is true, original value otherwise
23
+ */
24
+ export declare function stringToBuffer(value: string, isBuffer: boolean): Buffer | string;
25
+ //# sourceMappingURL=buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffer.d.ts","sourceRoot":"","sources":["../../src/helpers/buffer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAkBtD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAKhF"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Buffer conversion utilities for Next.js 15+ compatibility
3
+ * Next.js 15 changed body/rscData from strings to Buffers
4
+ */
5
+ /**
6
+ * Convert a value to base64 string if it's a Buffer
7
+ * Used when storing cache values (e.g., in Redis)
8
+ *
9
+ * @param value - Value that might be a Buffer
10
+ * @returns Base64 string if Buffer, original value otherwise
11
+ */
12
+ export function bufferToString(value) {
13
+ if (Buffer.isBuffer(value)) {
14
+ return value.toString("base64");
15
+ }
16
+ if (typeof value === "object" && value !== null) {
17
+ const result = {};
18
+ for (const [key, val] of Object.entries(value)) {
19
+ result[key] = bufferToString(val);
20
+ }
21
+ return result;
22
+ }
23
+ if (Array.isArray(value)) {
24
+ return value.map(bufferToString);
25
+ }
26
+ return value;
27
+ }
28
+ /**
29
+ * Convert a base64 string back to Buffer if it was originally a Buffer
30
+ * Used when retrieving cache values (e.g., from Redis)
31
+ *
32
+ * This is a simplified version - in production you'd need to track
33
+ * which fields were originally Buffers
34
+ *
35
+ * @param value - Value that might be a base64 string
36
+ * @param isBuffer - Whether this value should be converted to Buffer
37
+ * @returns Buffer if isBuffer is true, original value otherwise
38
+ */
39
+ export function stringToBuffer(value, isBuffer) {
40
+ if (isBuffer && typeof value === "string") {
41
+ return Buffer.from(value, "base64");
42
+ }
43
+ return value;
44
+ }
45
+ //# sourceMappingURL=buffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffer.js","sourceRoot":"","sources":["../../src/helpers/buffer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/C,MAAM,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACpC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa,EAAE,QAAiB;IAC7D,IAAI,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC1C,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Check if a tag is an implicit (system-generated) tag
3
+ * Implicit tags are generated by Next.js with the _N_T_ prefix
4
+ *
5
+ * @param tag - The tag to check
6
+ * @returns True if the tag is implicit, false otherwise
7
+ */
8
+ export declare function isImplicitTag(tag: string): boolean;
9
+ //# sourceMappingURL=is-implicit-tag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-implicit-tag.d.ts","sourceRoot":"","sources":["../../src/helpers/is-implicit-tag.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAMlD"}
@@ -0,0 +1,16 @@
1
+ import { IMPLICIT_TAG_PREFIX } from "../types.js";
2
+ /**
3
+ * Check if a tag is an implicit (system-generated) tag
4
+ * Implicit tags are generated by Next.js with the _N_T_ prefix
5
+ *
6
+ * @param tag - The tag to check
7
+ * @returns True if the tag is implicit, false otherwise
8
+ */
9
+ export function isImplicitTag(tag) {
10
+ // Guard against non-string values that Next.js might pass
11
+ if (typeof tag !== "string") {
12
+ return false;
13
+ }
14
+ return tag.startsWith(IMPLICIT_TAG_PREFIX);
15
+ }
16
+ //# sourceMappingURL=is-implicit-tag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-implicit-tag.js","sourceRoot":"","sources":["../../src/helpers/is-implicit-tag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,0DAA0D;IAC1D,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,GAAG,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { LifespanParameters } from "../types.js";
2
+ /**
3
+ * Calculate lifespan parameters from revalidate value
4
+ * CRITICAL: All timestamps are in SECONDS, not milliseconds
5
+ *
6
+ * @param revalidate - Revalidation period in seconds, or false to disable
7
+ * @param defaultTTL - Default TTL in seconds if revalidate is undefined
8
+ * @returns Lifespan parameters or null if no expiration
9
+ */
10
+ export declare function calculateLifespan(revalidate: number | false | undefined, defaultTTL?: number): LifespanParameters | null;
11
+ /**
12
+ * Check if a cache entry has expired based on its lifespan
13
+ *
14
+ * @param lifespan - Lifespan parameters (null means never expires)
15
+ * @returns True if expired, false otherwise
16
+ */
17
+ export declare function isExpired(lifespan: LifespanParameters | null): boolean;
18
+ //# sourceMappingURL=lifespan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifespan.d.ts","sourceRoot":"","sources":["../../src/helpers/lifespan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,EACtC,UAAU,CAAC,EAAE,MAAM,GAClB,kBAAkB,GAAG,IAAI,CAwB3B;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,GAAG,OAAO,CAOtE"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Calculate lifespan parameters from revalidate value
3
+ * CRITICAL: All timestamps are in SECONDS, not milliseconds
4
+ *
5
+ * @param revalidate - Revalidation period in seconds, or false to disable
6
+ * @param defaultTTL - Default TTL in seconds if revalidate is undefined
7
+ * @returns Lifespan parameters or null if no expiration
8
+ */
9
+ export function calculateLifespan(revalidate, defaultTTL) {
10
+ // If revalidate is explicitly false, no expiration
11
+ if (revalidate === false) {
12
+ return null;
13
+ }
14
+ // Use revalidate value or default TTL
15
+ const ttlSeconds = typeof revalidate === "number" ? revalidate : defaultTTL;
16
+ // If no TTL specified, no expiration
17
+ if (!ttlSeconds) {
18
+ return null;
19
+ }
20
+ const nowSeconds = Math.floor(Date.now() / 1000);
21
+ return {
22
+ lastModifiedAt: nowSeconds,
23
+ staleAt: nowSeconds + ttlSeconds,
24
+ expireAt: nowSeconds + ttlSeconds,
25
+ staleAge: ttlSeconds,
26
+ expireAge: ttlSeconds,
27
+ revalidate,
28
+ };
29
+ }
30
+ /**
31
+ * Check if a cache entry has expired based on its lifespan
32
+ *
33
+ * @param lifespan - Lifespan parameters (null means never expires)
34
+ * @returns True if expired, false otherwise
35
+ */
36
+ export function isExpired(lifespan) {
37
+ if (!lifespan) {
38
+ return false;
39
+ }
40
+ const nowSeconds = Math.floor(Date.now() / 1000);
41
+ return nowSeconds >= lifespan.expireAt;
42
+ }
43
+ //# sourceMappingURL=lifespan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifespan.js","sourceRoot":"","sources":["../../src/helpers/lifespan.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAAsC,EACtC,UAAmB;IAEnB,mDAAmD;IACnD,IAAI,UAAU,KAAK,KAAK,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,sCAAsC;IACtC,MAAM,UAAU,GAAG,OAAO,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC;IAE5E,qCAAqC;IACrC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAEjD,OAAO;QACL,cAAc,EAAE,UAAU;QAC1B,OAAO,EAAE,UAAU,GAAG,UAAU;QAChC,QAAQ,EAAE,UAAU,GAAG,UAAU;QACjC,QAAQ,EAAE,UAAU;QACpB,SAAS,EAAE,UAAU;QACrB,UAAU;KACX,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,QAAmC;IAC3D,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IACjD,OAAO,UAAU,IAAI,QAAQ,CAAC,QAAQ,CAAC;AACzC,CAAC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Helper functions for configuring Next.js cache handlers
3
+ */
4
+ export interface CacheHandlerConfig {
5
+ /**
6
+ * Path to ISR cache handler (for cacheHandler in next.config)
7
+ */
8
+ cacheHandler: string;
9
+ /**
10
+ * Paths to data cache handlers (for cacheHandlers in next.config)
11
+ */
12
+ cacheHandlers: {
13
+ default: string;
14
+ remote: string;
15
+ };
16
+ /**
17
+ * Disable Next.js default in-memory cache for "use cache"
18
+ * Set to 0 to use your own handlers exclusively
19
+ */
20
+ cacheMaxMemorySize?: number;
21
+ }
22
+ /**
23
+ * Create Next.js cache handler configuration for both ISR and Data Cache
24
+ *
25
+ * This generates the config needed for both:
26
+ * - `cacheHandler`: ISR cache (Incremental Static Regeneration)
27
+ * - `cacheHandlers`: Data cache ("use cache" and "use cache: remote")
28
+ *
29
+ * @param options - Configuration options
30
+ * @param options.isrHandlerPath - Path to ISR cache handler file (for cacheHandler)
31
+ * @param options.dataCacheHandlerPath - Path to data cache handler file (for cacheHandlers.default and cacheHandlers.remote)
32
+ * @param options.disableDefaultMemoryCache - Set to true to disable Next.js default in-memory cache (default: true)
33
+ *
34
+ * @returns Configuration object to spread into next.config
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * // next.config.mjs
39
+ * import { createCacheConfig } from "@mrjasonroy/better-nextjs-cache-handler";
40
+ * import { resolve } from "path";
41
+ *
42
+ * const cacheConfig = createCacheConfig({
43
+ * isrHandlerPath: resolve(process.cwd(), "./cache-handler.mjs"),
44
+ * dataCacheHandlerPath: resolve(process.cwd(), "./data-cache-handler.mjs"),
45
+ * });
46
+ *
47
+ * export default {
48
+ * ...cacheConfig,
49
+ * // other Next.js config
50
+ * };
51
+ * ```
52
+ */
53
+ export declare function createCacheConfig(options: {
54
+ isrHandlerPath: string;
55
+ dataCacheHandlerPath: string;
56
+ disableDefaultMemoryCache?: boolean;
57
+ }): CacheHandlerConfig;
58
+ /**
59
+ * Create Next.js cache handler configuration with separate handlers for default and remote
60
+ *
61
+ * This allows you to use different cache handlers for:
62
+ * - `default`: Used by "use cache" (typically faster, in-memory or local)
63
+ * - `remote`: Used by "use cache: remote" (typically slower, database or API results)
64
+ *
65
+ * @param options - Configuration options
66
+ * @param options.isrHandlerPath - Path to ISR cache handler file (for cacheHandler)
67
+ * @param options.defaultDataCacheHandlerPath - Path to data cache handler for "use cache"
68
+ * @param options.remoteDataCacheHandlerPath - Path to data cache handler for "use cache: remote"
69
+ * @param options.disableDefaultMemoryCache - Set to true to disable Next.js default in-memory cache (default: true)
70
+ *
71
+ * @returns Configuration object to spread into next.config
72
+ *
73
+ * @example
74
+ * ```ts
75
+ * // next.config.mjs
76
+ * import { createCacheConfigWithProfiles } from "@mrjasonroy/better-nextjs-cache-handler";
77
+ * import { resolve } from "path";
78
+ *
79
+ * const cacheConfig = createCacheConfigWithProfiles({
80
+ * isrHandlerPath: resolve(process.cwd(), "./cache-handler.mjs"),
81
+ * defaultDataCacheHandlerPath: resolve(process.cwd(), "./data-cache-memory.mjs"),
82
+ * remoteDataCacheHandlerPath: resolve(process.cwd(), "./data-cache-redis.mjs"),
83
+ * });
84
+ *
85
+ * export default {
86
+ * ...cacheConfig,
87
+ * // other Next.js config
88
+ * };
89
+ * ```
90
+ */
91
+ export declare function createCacheConfigWithProfiles(options: {
92
+ isrHandlerPath: string;
93
+ defaultDataCacheHandlerPath: string;
94
+ remoteDataCacheHandlerPath: string;
95
+ disableDefaultMemoryCache?: boolean;
96
+ }): CacheHandlerConfig;
97
+ //# sourceMappingURL=next-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next-config.d.ts","sourceRoot":"","sources":["../../src/helpers/next-config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,aAAa,EAAE;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IAEF;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC,GAAG,kBAAkB,CAcrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE;IACrD,cAAc,EAAE,MAAM,CAAC;IACvB,2BAA2B,EAAE,MAAM,CAAC;IACpC,0BAA0B,EAAE,MAAM,CAAC;IACnC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC,GAAG,kBAAkB,CAmBrB"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Helper functions for configuring Next.js cache handlers
3
+ */
4
+ /**
5
+ * Create Next.js cache handler configuration for both ISR and Data Cache
6
+ *
7
+ * This generates the config needed for both:
8
+ * - `cacheHandler`: ISR cache (Incremental Static Regeneration)
9
+ * - `cacheHandlers`: Data cache ("use cache" and "use cache: remote")
10
+ *
11
+ * @param options - Configuration options
12
+ * @param options.isrHandlerPath - Path to ISR cache handler file (for cacheHandler)
13
+ * @param options.dataCacheHandlerPath - Path to data cache handler file (for cacheHandlers.default and cacheHandlers.remote)
14
+ * @param options.disableDefaultMemoryCache - Set to true to disable Next.js default in-memory cache (default: true)
15
+ *
16
+ * @returns Configuration object to spread into next.config
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * // next.config.mjs
21
+ * import { createCacheConfig } from "@mrjasonroy/better-nextjs-cache-handler";
22
+ * import { resolve } from "path";
23
+ *
24
+ * const cacheConfig = createCacheConfig({
25
+ * isrHandlerPath: resolve(process.cwd(), "./cache-handler.mjs"),
26
+ * dataCacheHandlerPath: resolve(process.cwd(), "./data-cache-handler.mjs"),
27
+ * });
28
+ *
29
+ * export default {
30
+ * ...cacheConfig,
31
+ * // other Next.js config
32
+ * };
33
+ * ```
34
+ */
35
+ export function createCacheConfig(options) {
36
+ const { isrHandlerPath, dataCacheHandlerPath, disableDefaultMemoryCache = true } = options;
37
+ return {
38
+ cacheHandler: isrHandlerPath,
39
+ cacheHandlers: {
40
+ // "use cache" uses this (default cache profile)
41
+ default: dataCacheHandlerPath,
42
+ // "use cache: remote" uses this (for DB queries, API calls)
43
+ remote: dataCacheHandlerPath,
44
+ },
45
+ // Disable Next.js default in-memory cache to use our handlers exclusively
46
+ cacheMaxMemorySize: disableDefaultMemoryCache ? 0 : undefined,
47
+ };
48
+ }
49
+ /**
50
+ * Create Next.js cache handler configuration with separate handlers for default and remote
51
+ *
52
+ * This allows you to use different cache handlers for:
53
+ * - `default`: Used by "use cache" (typically faster, in-memory or local)
54
+ * - `remote`: Used by "use cache: remote" (typically slower, database or API results)
55
+ *
56
+ * @param options - Configuration options
57
+ * @param options.isrHandlerPath - Path to ISR cache handler file (for cacheHandler)
58
+ * @param options.defaultDataCacheHandlerPath - Path to data cache handler for "use cache"
59
+ * @param options.remoteDataCacheHandlerPath - Path to data cache handler for "use cache: remote"
60
+ * @param options.disableDefaultMemoryCache - Set to true to disable Next.js default in-memory cache (default: true)
61
+ *
62
+ * @returns Configuration object to spread into next.config
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * // next.config.mjs
67
+ * import { createCacheConfigWithProfiles } from "@mrjasonroy/better-nextjs-cache-handler";
68
+ * import { resolve } from "path";
69
+ *
70
+ * const cacheConfig = createCacheConfigWithProfiles({
71
+ * isrHandlerPath: resolve(process.cwd(), "./cache-handler.mjs"),
72
+ * defaultDataCacheHandlerPath: resolve(process.cwd(), "./data-cache-memory.mjs"),
73
+ * remoteDataCacheHandlerPath: resolve(process.cwd(), "./data-cache-redis.mjs"),
74
+ * });
75
+ *
76
+ * export default {
77
+ * ...cacheConfig,
78
+ * // other Next.js config
79
+ * };
80
+ * ```
81
+ */
82
+ export function createCacheConfigWithProfiles(options) {
83
+ const { isrHandlerPath, defaultDataCacheHandlerPath, remoteDataCacheHandlerPath, disableDefaultMemoryCache = true, } = options;
84
+ return {
85
+ cacheHandler: isrHandlerPath,
86
+ cacheHandlers: {
87
+ // "use cache" uses this (default cache profile)
88
+ default: defaultDataCacheHandlerPath,
89
+ // "use cache: remote" uses this (for DB queries, API calls)
90
+ remote: remoteDataCacheHandlerPath,
91
+ },
92
+ // Disable Next.js default in-memory cache to use our handlers exclusively
93
+ cacheMaxMemorySize: disableDefaultMemoryCache ? 0 : undefined,
94
+ };
95
+ }
96
+ //# sourceMappingURL=next-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next-config.js","sourceRoot":"","sources":["../../src/helpers/next-config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAuBH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAIjC;IACC,MAAM,EAAE,cAAc,EAAE,oBAAoB,EAAE,yBAAyB,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAE3F,OAAO;QACL,YAAY,EAAE,cAAc;QAC5B,aAAa,EAAE;YACb,gDAAgD;YAChD,OAAO,EAAE,oBAAoB;YAC7B,4DAA4D;YAC5D,MAAM,EAAE,oBAAoB;SAC7B;QACD,0EAA0E;QAC1E,kBAAkB,EAAE,yBAAyB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;KAC9D,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,6BAA6B,CAAC,OAK7C;IACC,MAAM,EACJ,cAAc,EACd,2BAA2B,EAC3B,0BAA0B,EAC1B,yBAAyB,GAAG,IAAI,GACjC,GAAG,OAAO,CAAC;IAEZ,OAAO;QACL,YAAY,EAAE,cAAc;QAC5B,aAAa,EAAE;YACb,gDAAgD;YAChD,OAAO,EAAE,2BAA2B;YACpC,4DAA4D;YAC5D,MAAM,EAAE,0BAA0B;SACnC;QACD,0EAA0E;QAC1E,kBAAkB,EAAE,yBAAyB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;KAC9D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @mrjasonroy/better-nextjs-cache-handler
3
+ * Modern cache handler for Next.js 16+ with support for ISR and 'use cache' directive
4
+ */
5
+ export { CompositeHandler, type CompositeHandlerOptions, createCompositeHandler, } from "./handlers/composite.js";
6
+ export { createMemoryCacheHandler, MemoryCacheHandler, type MemoryCacheHandlerOptions, } from "./handlers/memory.js";
7
+ export { RedisCacheHandler, type RedisCacheHandlerOptions, } from "./handlers/redis.js";
8
+ export { bufferToString, stringToBuffer } from "./helpers/buffer.js";
9
+ export { isImplicitTag } from "./helpers/is-implicit-tag.js";
10
+ export { calculateLifespan, isExpired } from "./helpers/lifespan.js";
11
+ export { createCacheConfig, createCacheConfigWithProfiles, type CacheHandlerConfig, } from "./helpers/next-config.js";
12
+ export type { CacheHandler, CacheHandlerContext, CacheHandlerGetMeta, CacheHandlerOptions, CacheHandlerValue, CacheValue, LifespanParameters, } from "./types.js";
13
+ export { IMPLICIT_TAG_PREFIX } from "./types.js";
14
+ export { createMemoryDataCacheHandler, type MemoryDataCacheHandlerOptions, } from "./data-cache/memory.js";
15
+ export { createRedisDataCacheHandler, type RedisClient, type RedisDataCacheHandlerOptions, } from "./data-cache/redis.js";
16
+ export type { DataCacheEntry, DataCacheHandler, Timestamp, } from "./data-cache/types.js";
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,wBAAwB,EACxB,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,iBAAiB,EACjB,KAAK,wBAAwB,GAC9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EACL,iBAAiB,EACjB,6BAA6B,EAC7B,KAAK,kBAAkB,GACxB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EACV,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,kBAAkB,GACnB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAMjD,OAAO,EACL,4BAA4B,EAC5B,KAAK,6BAA6B,GACnC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,2BAA2B,EAC3B,KAAK,WAAW,EAChB,KAAK,4BAA4B,GAClC,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,SAAS,GACV,MAAM,uBAAuB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @mrjasonroy/better-nextjs-cache-handler
3
+ * Modern cache handler for Next.js 16+ with support for ISR and 'use cache' directive
4
+ */
5
+ // =============================================================================
6
+ // ISR Cache Handlers (for Incremental Static Regeneration)
7
+ // =============================================================================
8
+ export { CompositeHandler, createCompositeHandler, } from "./handlers/composite.js";
9
+ // Handlers
10
+ export { createMemoryCacheHandler, MemoryCacheHandler, } from "./handlers/memory.js";
11
+ export { RedisCacheHandler, } from "./handlers/redis.js";
12
+ export { bufferToString, stringToBuffer } from "./helpers/buffer.js";
13
+ // Helpers
14
+ export { isImplicitTag } from "./helpers/is-implicit-tag.js";
15
+ export { calculateLifespan, isExpired } from "./helpers/lifespan.js";
16
+ export { createCacheConfig, createCacheConfigWithProfiles, } from "./helpers/next-config.js";
17
+ export { IMPLICIT_TAG_PREFIX } from "./types.js";
18
+ // =============================================================================
19
+ // Data Cache Handlers (for "use cache" directive)
20
+ // =============================================================================
21
+ export { createMemoryDataCacheHandler, } from "./data-cache/memory.js";
22
+ export { createRedisDataCacheHandler, } from "./data-cache/redis.js";
23
+ //# sourceMappingURL=index.js.map