@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.
Files changed (54) hide show
  1. package/README.md +256 -0
  2. package/dist/edge/edge-cache-clear.d.ts +64 -0
  3. package/dist/edge/edge-cache-clear.d.ts.map +1 -0
  4. package/dist/edge/edge-cache-clear.js +245 -0
  5. package/dist/edge/edge-cache-clear.js.map +1 -0
  6. package/dist/handlers/base.d.ts +69 -0
  7. package/dist/handlers/base.d.ts.map +1 -0
  8. package/dist/handlers/base.js +278 -0
  9. package/dist/handlers/base.js.map +1 -0
  10. package/dist/handlers/file.d.ts +62 -0
  11. package/dist/handlers/file.d.ts.map +1 -0
  12. package/dist/handlers/file.js +332 -0
  13. package/dist/handlers/file.js.map +1 -0
  14. package/dist/handlers/gcs.d.ts +66 -0
  15. package/dist/handlers/gcs.d.ts.map +1 -0
  16. package/dist/handlers/gcs.js +407 -0
  17. package/dist/handlers/gcs.js.map +1 -0
  18. package/dist/handlers/index.d.ts +4 -0
  19. package/dist/handlers/index.d.ts.map +1 -0
  20. package/dist/handlers/index.js +4 -0
  21. package/dist/handlers/index.js.map +1 -0
  22. package/dist/index.d.ts +47 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +73 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/types.d.ts +119 -0
  27. package/dist/types.d.ts.map +1 -0
  28. package/dist/types.js +2 -0
  29. package/dist/types.js.map +1 -0
  30. package/dist/utils/build-detection.d.ts +10 -0
  31. package/dist/utils/build-detection.d.ts.map +1 -0
  32. package/dist/utils/build-detection.js +57 -0
  33. package/dist/utils/build-detection.js.map +1 -0
  34. package/dist/utils/index.d.ts +5 -0
  35. package/dist/utils/index.d.ts.map +1 -0
  36. package/dist/utils/index.js +5 -0
  37. package/dist/utils/index.js.map +1 -0
  38. package/dist/utils/logger.d.ts +34 -0
  39. package/dist/utils/logger.d.ts.map +1 -0
  40. package/dist/utils/logger.js +54 -0
  41. package/dist/utils/logger.js.map +1 -0
  42. package/dist/utils/serialization.d.ts +12 -0
  43. package/dist/utils/serialization.d.ts.map +1 -0
  44. package/dist/utils/serialization.js +137 -0
  45. package/dist/utils/serialization.js.map +1 -0
  46. package/dist/utils/static-routes.d.ts +7 -0
  47. package/dist/utils/static-routes.d.ts.map +1 -0
  48. package/dist/utils/static-routes.js +52 -0
  49. package/dist/utils/static-routes.js.map +1 -0
  50. package/dist/utils/tags-buffer.d.ts +63 -0
  51. package/dist/utils/tags-buffer.d.ts.map +1 -0
  52. package/dist/utils/tags-buffer.js +181 -0
  53. package/dist/utils/tags-buffer.js.map +1 -0
  54. package/package.json +58 -0
@@ -0,0 +1,119 @@
1
+ import type { CacheHandler as NextCacheHandler, CacheHandlerValue as NextCacheHandlerValue } from "next/dist/server/lib/incremental-cache";
2
+ import type FileSystemCache from "next/dist/server/lib/incremental-cache/file-system-cache";
3
+ /**
4
+ * Configuration options for creating a cache handler instance.
5
+ */
6
+ export interface CacheHandlerConfig {
7
+ /**
8
+ * Handler type selection:
9
+ * - 'auto': Automatically detect based on environment (GCS if CACHE_BUCKET is set, otherwise file)
10
+ * - 'file': Use file-based caching (local development)
11
+ * - 'gcs': Use Google Cloud Storage (production/Pantheon)
12
+ */
13
+ type?: 'auto' | 'file' | 'gcs';
14
+ }
15
+ export interface CacheContext {
16
+ fetchCache?: boolean;
17
+ fetchUrl?: string;
18
+ fetchIdx: number;
19
+ tags?: string[];
20
+ isImplicitBuildTimeCache: false;
21
+ }
22
+ export interface CacheEntry {
23
+ value: unknown;
24
+ lastModified: number;
25
+ tags: string[];
26
+ }
27
+ export interface CacheData {
28
+ [key: string]: unknown;
29
+ }
30
+ export interface SerializedBuffer {
31
+ type: 'Buffer';
32
+ data: string;
33
+ }
34
+ export interface SerializedMap {
35
+ type: 'Map';
36
+ data: Record<string, unknown>;
37
+ }
38
+ export type SerializableValue = string | number | boolean | null | undefined | SerializedBuffer | SerializedMap | Record<string, unknown> | unknown[];
39
+ export interface SerializedCacheData {
40
+ [key: string]: {
41
+ value: SerializableValue;
42
+ lastModified: number;
43
+ tags: Readonly<string[]>;
44
+ };
45
+ }
46
+ export interface CacheEntryInfo {
47
+ key: string;
48
+ tags: string[];
49
+ lastModified?: number;
50
+ type: 'fetch' | 'route';
51
+ }
52
+ export interface CacheStats {
53
+ size: number;
54
+ keys: string[];
55
+ entries: CacheEntryInfo[];
56
+ }
57
+ export type CacheHandlerParametersGet = Parameters<NextCacheHandler["get"]>;
58
+ export type CacheHandlerParametersSet = Parameters<NextCacheHandler["set"]>;
59
+ export type FileSystemCacheContext = ConstructorParameters<typeof FileSystemCache>[0];
60
+ export type CacheHandlerParametersRevalidateTag = Parameters<NextCacheHandler["revalidateTag"]>;
61
+ export type CacheHandlerValue = NextCacheHandlerValue & {
62
+ /**
63
+ * Timestamp in milliseconds when the cache entry was last modified.
64
+ */
65
+ lastModified: number;
66
+ /**
67
+ * Tags associated with the cache entry. They are used for on-demand revalidation.
68
+ */
69
+ tags: Readonly<string[]>;
70
+ };
71
+ export type Revalidate = false | number;
72
+ /**
73
+ * A set of time periods and timestamps for controlling cache behavior.
74
+ */
75
+ export type LifespanParameters = {
76
+ /**
77
+ * The Unix timestamp (in seconds) for when the cache entry was last modified.
78
+ */
79
+ readonly lastModifiedAt: number;
80
+ /**
81
+ * The Unix timestamp (in seconds) for when the cache entry entry becomes stale.
82
+ * After this time, the entry is considered staled and may be used.
83
+ */
84
+ readonly staleAt: number;
85
+ /**
86
+ * The Unix timestamp (in seconds) for when the cache entry must be removed from the cache.
87
+ * After this time, the entry is considered expired and should not be used.
88
+ */
89
+ readonly expireAt: number;
90
+ /**
91
+ * Time in seconds before the cache entry becomes stale.
92
+ */
93
+ readonly staleAge: number;
94
+ /**
95
+ * Time in seconds before the cache entry becomes expired.
96
+ */
97
+ readonly expireAge: number;
98
+ /**
99
+ * Value from Next.js revalidate option. May be false if the page has no revalidate option or the revalidate option is set to false.
100
+ */
101
+ readonly revalidate: Revalidate | undefined;
102
+ };
103
+ /**
104
+ * Cache handler interface that extends the Next.js CacheHandler.
105
+ * This is the interface that all cache handler implementations must implement.
106
+ */
107
+ export declare class CacheHandler implements NextCacheHandler {
108
+ /**
109
+ * Creates a new CacheHandler instance.
110
+ */
111
+ constructor(context: FileSystemCacheContext);
112
+ get(cacheKey: CacheHandlerParametersGet[0], ctx?: CacheHandlerParametersGet[1]): Promise<CacheHandlerValue | null>;
113
+ set(cacheKey: CacheHandlerParametersSet[0], incrementalCacheValue: CacheHandlerParametersSet[1], ctx: CacheHandlerParametersSet[2] & {
114
+ internal_lastModified?: number;
115
+ }): Promise<void>;
116
+ revalidateTag(tag: CacheHandlerParametersRevalidateTag[0]): Promise<void>;
117
+ resetRequestCache(): void;
118
+ }
119
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Detects if the current process is running during the Next.js build phase.
3
+ */
4
+ export declare function isBuildPhase(): boolean;
5
+ /**
6
+ * Gets the Next.js build ID from the build manifest.
7
+ * This ID is stable and unique per build, unlike file modification times.
8
+ */
9
+ export declare function getBuildId(): string;
10
+ //# sourceMappingURL=build-detection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-detection.d.ts","sourceRoot":"","sources":["../../src/utils/build-detection.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAYnC"}
@@ -0,0 +1,57 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ /**
4
+ * Detects if the current process is running during the Next.js build phase.
5
+ */
6
+ export function isBuildPhase() {
7
+ return process.env.NEXT_PHASE === 'phase-production-build';
8
+ }
9
+ /**
10
+ * Gets the Next.js build ID from the build manifest.
11
+ * This ID is stable and unique per build, unlike file modification times.
12
+ */
13
+ export function getBuildId() {
14
+ const buildIdFromFile = readBuildIdFromFile();
15
+ if (buildIdFromFile) {
16
+ return buildIdFromFile;
17
+ }
18
+ const buildIdFromManifest = extractBuildIdFromManifest();
19
+ if (buildIdFromManifest) {
20
+ return buildIdFromManifest;
21
+ }
22
+ return `fallback-${Date.now()}`;
23
+ }
24
+ function readBuildIdFromFile() {
25
+ try {
26
+ const buildIdPath = path.join(process.cwd(), '.next', 'BUILD_ID');
27
+ if (fs.existsSync(buildIdPath)) {
28
+ return fs.readFileSync(buildIdPath, 'utf-8').trim();
29
+ }
30
+ }
31
+ catch {
32
+ // Ignore errors
33
+ }
34
+ return null;
35
+ }
36
+ function extractBuildIdFromManifest() {
37
+ try {
38
+ const manifestPath = path.join(process.cwd(), '.next', 'build-manifest.json');
39
+ if (!fs.existsSync(manifestPath)) {
40
+ return null;
41
+ }
42
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
43
+ const lowPriorityFiles = manifest.lowPriorityFiles || [];
44
+ // Build ID is in paths like "static/DsOqQ6QE7Bo_OEhUjVFCD/_buildManifest.js"
45
+ for (const file of lowPriorityFiles) {
46
+ const match = file.match(/static\/([^/]+)\/_/);
47
+ if (match) {
48
+ return match[1];
49
+ }
50
+ }
51
+ }
52
+ catch {
53
+ // Ignore errors
54
+ }
55
+ return null;
56
+ }
57
+ //# sourceMappingURL=build-detection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-detection.js","sourceRoot":"","sources":["../../src/utils/build-detection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,wBAAwB,CAAC;AAC7D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,eAAe,GAAG,mBAAmB,EAAE,CAAC;IAC9C,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,MAAM,mBAAmB,GAAG,0BAA0B,EAAE,CAAC;IACzD,IAAI,mBAAmB,EAAE,CAAC;QACxB,OAAO,mBAAmB,CAAC;IAC7B,CAAC;IAED,OAAO,YAAY,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;AAClC,CAAC;AAED,SAAS,mBAAmB;IAC1B,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAClE,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/B,OAAO,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QACtD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB;IAClB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,0BAA0B;IACjC,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,qBAAqB,CAAC,CAAC;QAC9E,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;QACpE,MAAM,gBAAgB,GAAG,QAAQ,CAAC,gBAAgB,IAAI,EAAE,CAAC;QAEzD,6EAA6E;QAC7E,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;YACpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;YAC/C,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB;IAClB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { serializeForStorage, deserializeFromStorage } from './serialization.js';
2
+ export { getBuildId, isBuildPhase } from './build-detection.js';
3
+ export { getStaticRoutes } from './static-routes.js';
4
+ export { createLogger, type Logger } from './logger.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { serializeForStorage, deserializeFromStorage } from './serialization.js';
2
+ export { getBuildId, isBuildPhase } from './build-detection.js';
3
+ export { getStaticRoutes } from './static-routes.js';
4
+ export { createLogger } from './logger.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAe,MAAM,aAAa,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Debug logger that only logs when CACHE_DEBUG environment variable is set.
3
+ * This allows verbose logging during development/debugging without cluttering
4
+ * production logs.
5
+ */
6
+ /**
7
+ * Creates a logger instance for a specific handler.
8
+ * Debug and info logs are only shown when CACHE_DEBUG=true.
9
+ * Warn and error logs are always shown.
10
+ */
11
+ export declare function createLogger(handlerName: string): {
12
+ /**
13
+ * Debug level - only shown when CACHE_DEBUG=true
14
+ * Use for verbose operational logs (GET, SET, HIT, MISS, etc.)
15
+ */
16
+ debug: (message: string, ...args: unknown[]) => void;
17
+ /**
18
+ * Info level - only shown when CACHE_DEBUG=true
19
+ * Use for important operational events (initialization, cache cleared, etc.)
20
+ */
21
+ info: (message: string, ...args: unknown[]) => void;
22
+ /**
23
+ * Warn level - always shown
24
+ * Use for recoverable issues that might need attention
25
+ */
26
+ warn: (message: string, ...args: unknown[]) => void;
27
+ /**
28
+ * Error level - always shown
29
+ * Use for errors that affect cache operations
30
+ */
31
+ error: (message: string, ...args: unknown[]) => void;
32
+ };
33
+ export type Logger = ReturnType<typeof createLogger>;
34
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM;IAE5C;;;OAGG;qBACc,MAAM,WAAW,OAAO,EAAE;IAM3C;;;OAGG;oBACa,MAAM,WAAW,OAAO,EAAE;IAM1C;;;OAGG;oBACa,MAAM,WAAW,OAAO,EAAE;IAI1C;;;OAGG;qBACc,MAAM,WAAW,OAAO,EAAE;EAI9C;AAED,MAAM,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Debug logger that only logs when CACHE_DEBUG environment variable is set.
3
+ * This allows verbose logging during development/debugging without cluttering
4
+ * production logs.
5
+ */
6
+ function isDebugEnabled() {
7
+ const debugValue = process.env.CACHE_DEBUG;
8
+ return debugValue === 'true' || debugValue === '1';
9
+ }
10
+ function formatMessage(handlerName, message) {
11
+ return `[${handlerName}] ${message}`;
12
+ }
13
+ /**
14
+ * Creates a logger instance for a specific handler.
15
+ * Debug and info logs are only shown when CACHE_DEBUG=true.
16
+ * Warn and error logs are always shown.
17
+ */
18
+ export function createLogger(handlerName) {
19
+ return {
20
+ /**
21
+ * Debug level - only shown when CACHE_DEBUG=true
22
+ * Use for verbose operational logs (GET, SET, HIT, MISS, etc.)
23
+ */
24
+ debug: (message, ...args) => {
25
+ if (isDebugEnabled()) {
26
+ console.log(formatMessage(handlerName, message), ...args);
27
+ }
28
+ },
29
+ /**
30
+ * Info level - only shown when CACHE_DEBUG=true
31
+ * Use for important operational events (initialization, cache cleared, etc.)
32
+ */
33
+ info: (message, ...args) => {
34
+ if (isDebugEnabled()) {
35
+ console.log(formatMessage(handlerName, message), ...args);
36
+ }
37
+ },
38
+ /**
39
+ * Warn level - always shown
40
+ * Use for recoverable issues that might need attention
41
+ */
42
+ warn: (message, ...args) => {
43
+ console.warn(formatMessage(handlerName, message), ...args);
44
+ },
45
+ /**
46
+ * Error level - always shown
47
+ * Use for errors that affect cache operations
48
+ */
49
+ error: (message, ...args) => {
50
+ console.error(formatMessage(handlerName, message), ...args);
51
+ },
52
+ };
53
+ }
54
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,SAAS,cAAc;IACrB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IAC3C,OAAO,UAAU,KAAK,MAAM,IAAI,UAAU,KAAK,GAAG,CAAC;AACrD,CAAC;AAED,SAAS,aAAa,CAAC,WAAmB,EAAE,OAAe;IACzD,OAAO,IAAI,WAAW,KAAK,OAAO,EAAE,CAAC;AACvC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,WAAmB;IAC9C,OAAO;QACL;;;WAGG;QACH,KAAK,EAAE,CAAC,OAAe,EAAE,GAAG,IAAe,EAAE,EAAE;YAC7C,IAAI,cAAc,EAAE,EAAE,CAAC;gBACrB,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;QAED;;;WAGG;QACH,IAAI,EAAE,CAAC,OAAe,EAAE,GAAG,IAAe,EAAE,EAAE;YAC5C,IAAI,cAAc,EAAE,EAAE,CAAC;gBACrB,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;QAED;;;WAGG;QACH,IAAI,EAAE,CAAC,OAAe,EAAE,GAAG,IAAe,EAAE,EAAE;YAC5C,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;QAC7D,CAAC;QAED;;;WAGG;QACH,KAAK,EAAE,CAAC,OAAe,EAAE,GAAG,IAAe,EAAE,EAAE;YAC7C,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;QAC9D,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { CacheData, SerializedCacheData } from '../types.js';
2
+ /**
3
+ * Serializes cache data for JSON storage.
4
+ * Converts Buffers to base64 strings and Maps to serializable objects.
5
+ */
6
+ export declare function serializeForStorage(data: CacheData): SerializedCacheData;
7
+ /**
8
+ * Deserializes cache data from JSON storage.
9
+ * Converts base64 strings back to Buffers and serialized Maps back to Map objects.
10
+ */
11
+ export declare function deserializeFromStorage(data: SerializedCacheData): CacheData;
12
+ //# sourceMappingURL=serialization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../../src/utils/serialization.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,mBAAmB,EAIpB,MAAM,aAAa,CAAC;AAErB;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,GAAG,mBAAmB,CAwBxE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,mBAAmB,GAAG,SAAS,CAwB3E"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Serializes cache data for JSON storage.
3
+ * Converts Buffers to base64 strings and Maps to serializable objects.
4
+ */
5
+ export function serializeForStorage(data) {
6
+ const serialized = {};
7
+ for (const [key, entry] of Object.entries(data)) {
8
+ if (!isValidCacheEntry(entry)) {
9
+ serialized[key] = entry;
10
+ continue;
11
+ }
12
+ const value = entry.value;
13
+ if (!value || typeof value !== 'object') {
14
+ serialized[key] = entry;
15
+ continue;
16
+ }
17
+ const serializedValue = serializeValue(value);
18
+ serialized[key] = {
19
+ ...entry,
20
+ value: serializedValue,
21
+ };
22
+ }
23
+ return serialized;
24
+ }
25
+ /**
26
+ * Deserializes cache data from JSON storage.
27
+ * Converts base64 strings back to Buffers and serialized Maps back to Map objects.
28
+ */
29
+ export function deserializeFromStorage(data) {
30
+ const deserialized = {};
31
+ for (const [key, entry] of Object.entries(data)) {
32
+ if (!isValidCacheEntry(entry)) {
33
+ deserialized[key] = entry;
34
+ continue;
35
+ }
36
+ const value = entry.value;
37
+ if (!value || typeof value !== 'object') {
38
+ deserialized[key] = entry;
39
+ continue;
40
+ }
41
+ const deserializedValue = deserializeValue(value);
42
+ deserialized[key] = {
43
+ ...entry,
44
+ value: deserializedValue,
45
+ };
46
+ }
47
+ return deserialized;
48
+ }
49
+ function isValidCacheEntry(entry) {
50
+ return entry !== null && typeof entry === 'object' && 'value' in entry;
51
+ }
52
+ function serializeValue(value) {
53
+ const serializedValue = { ...value };
54
+ // Convert body Buffer to base64 string for storage
55
+ if (isBuffer(serializedValue.body)) {
56
+ serializedValue.body = bufferToSerializable(serializedValue.body);
57
+ }
58
+ // Handle rscData if it's a Buffer
59
+ if (isBuffer(serializedValue.rscData)) {
60
+ serializedValue.rscData = bufferToSerializable(serializedValue.rscData);
61
+ }
62
+ // Handle segmentData if it's a Map with Buffers
63
+ if (serializedValue.segmentData instanceof Map) {
64
+ serializedValue.segmentData = mapToSerializable(serializedValue.segmentData);
65
+ }
66
+ return serializedValue;
67
+ }
68
+ function deserializeValue(value) {
69
+ const deserializedValue = { ...value };
70
+ // Convert base64 string back to Buffer for body
71
+ if (isSerializedBuffer(deserializedValue.body)) {
72
+ deserializedValue.body = serializableToBuffer(deserializedValue.body);
73
+ }
74
+ // Convert base64 string back to Buffer for rscData
75
+ if (isSerializedBuffer(deserializedValue.rscData)) {
76
+ deserializedValue.rscData = serializableToBuffer(deserializedValue.rscData);
77
+ }
78
+ // Convert serialized Map back to Map with Buffers
79
+ if (isSerializedMap(deserializedValue.segmentData)) {
80
+ deserializedValue.segmentData = serializableToMap(deserializedValue.segmentData);
81
+ }
82
+ return deserializedValue;
83
+ }
84
+ function isBuffer(value) {
85
+ return Buffer.isBuffer(value);
86
+ }
87
+ function isSerializedBuffer(value) {
88
+ return (value !== null &&
89
+ typeof value === 'object' &&
90
+ 'type' in value &&
91
+ value.type === 'Buffer' &&
92
+ 'data' in value);
93
+ }
94
+ function isSerializedMap(value) {
95
+ return (value !== null &&
96
+ typeof value === 'object' &&
97
+ 'type' in value &&
98
+ value.type === 'Map' &&
99
+ 'data' in value);
100
+ }
101
+ function bufferToSerializable(buffer) {
102
+ return {
103
+ type: 'Buffer',
104
+ data: buffer.toString('base64'),
105
+ };
106
+ }
107
+ function serializableToBuffer(serialized) {
108
+ return Buffer.from(serialized.data, 'base64');
109
+ }
110
+ function mapToSerializable(map) {
111
+ const segmentObj = {};
112
+ for (const [segKey, segValue] of map.entries()) {
113
+ if (Buffer.isBuffer(segValue)) {
114
+ segmentObj[segKey] = bufferToSerializable(segValue);
115
+ }
116
+ else {
117
+ segmentObj[segKey] = segValue;
118
+ }
119
+ }
120
+ return {
121
+ type: 'Map',
122
+ data: segmentObj,
123
+ };
124
+ }
125
+ function serializableToMap(serialized) {
126
+ const segmentMap = new Map();
127
+ for (const [segKey, segValue] of Object.entries(serialized.data)) {
128
+ if (isSerializedBuffer(segValue)) {
129
+ segmentMap.set(segKey, serializableToBuffer(segValue));
130
+ }
131
+ else {
132
+ segmentMap.set(segKey, segValue);
133
+ }
134
+ }
135
+ return segmentMap;
136
+ }
137
+ //# sourceMappingURL=serialization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialization.js","sourceRoot":"","sources":["../../src/utils/serialization.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Gets static routes from prerender-manifest.json.
3
+ * Static routes have initialRevalidateSeconds: false (never revalidate).
4
+ * These should not be cleared as they are built during build time.
5
+ */
6
+ export declare function getStaticRoutes(): Set<string>;
7
+ //# sourceMappingURL=static-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-routes.d.ts","sourceRoot":"","sources":["../../src/utils/static-routes.ts"],"names":[],"mappings":"AASA;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,GAAG,CAAC,MAAM,CAAC,CAwB7C"}
@@ -0,0 +1,52 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ /**
4
+ * Gets static routes from prerender-manifest.json.
5
+ * Static routes have initialRevalidateSeconds: false (never revalidate).
6
+ * These should not be cleared as they are built during build time.
7
+ */
8
+ export function getStaticRoutes() {
9
+ const staticRoutes = new Set();
10
+ try {
11
+ const manifest = readPrerenderManifest();
12
+ if (!manifest) {
13
+ return staticRoutes;
14
+ }
15
+ const routes = manifest.routes || {};
16
+ for (const [route, config] of Object.entries(routes)) {
17
+ // initialRevalidateSeconds: false means truly static (SSG)
18
+ // initialRevalidateSeconds: number means ISR (can be cleared)
19
+ if (config.initialRevalidateSeconds === false) {
20
+ const cacheKey = routeToCacheKey(route);
21
+ staticRoutes.add(cacheKey);
22
+ }
23
+ }
24
+ }
25
+ catch {
26
+ // If we can't read the manifest, don't preserve any routes
27
+ }
28
+ return staticRoutes;
29
+ }
30
+ function readPrerenderManifest() {
31
+ try {
32
+ const manifestPath = path.join(process.cwd(), '.next', 'prerender-manifest.json');
33
+ if (!fs.existsSync(manifestPath)) {
34
+ return null;
35
+ }
36
+ return JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ /**
43
+ * Converts a route path to cache key format.
44
+ * Example: "/ssg-demo" -> "_ssg-demo", "/" -> "_index"
45
+ */
46
+ function routeToCacheKey(route) {
47
+ if (route === '/') {
48
+ return '_index';
49
+ }
50
+ return route.replace(/\//g, '_');
51
+ }
52
+ //# sourceMappingURL=static-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-routes.js","sourceRoot":"","sources":["../../src/utils/static-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAQ7B;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IAEvC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,qBAAqB,EAAE,CAAC;QACzC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,YAAY,CAAC;QACtB,CAAC;QAED,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC;QAErC,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACrD,2DAA2D;YAC3D,8DAA8D;YAC9D,IAAI,MAAM,CAAC,wBAAwB,KAAK,KAAK,EAAE,CAAC;gBAC9C,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;gBACxC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,2DAA2D;IAC7D,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAS,qBAAqB;IAC5B,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,yBAAyB,CAAC,CAAC;QAClF,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,KAAa;IACpC,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;QAClB,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACnC,CAAC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Buffered tags manager for GCS to avoid rate limiting.
3
+ * GCS has a rate limit of 1 write per second per object.
4
+ * This buffer collects tag updates and flushes them periodically.
5
+ */
6
+ export interface TagsBufferConfig {
7
+ /** Minimum interval between flushes in milliseconds. Default: 1000ms */
8
+ flushIntervalMs?: number;
9
+ /** Read the current tags mapping from storage */
10
+ readTagsMapping: () => Promise<Record<string, string[]>>;
11
+ /** Write the tags mapping to storage */
12
+ writeTagsMapping: (tagsMapping: Record<string, string[]>) => Promise<void>;
13
+ /** Handler name for logging */
14
+ handlerName?: string;
15
+ }
16
+ /**
17
+ * Buffers tag mapping updates to avoid GCS rate limiting.
18
+ * Collects updates in memory and flushes them at most once per second.
19
+ */
20
+ export declare class TagsBuffer {
21
+ private readonly flushIntervalMs;
22
+ private readonly readTagsMapping;
23
+ private readonly writeTagsMapping;
24
+ private readonly log;
25
+ private pendingUpdates;
26
+ private flushTimer;
27
+ private lastFlushTime;
28
+ private isFlushing;
29
+ private flushPromise;
30
+ constructor(config: TagsBufferConfig);
31
+ /**
32
+ * Queue a tag addition for a cache key.
33
+ * The update will be flushed to storage at most once per second.
34
+ */
35
+ addTags(cacheKey: string, tags: string[]): void;
36
+ /**
37
+ * Queue a cache key deletion from all tags.
38
+ * The update will be flushed to storage at most once per second.
39
+ */
40
+ deleteKey(cacheKey: string): void;
41
+ /**
42
+ * Queue multiple cache keys for deletion from all tags.
43
+ */
44
+ deleteKeys(cacheKeys: string[]): void;
45
+ /**
46
+ * Force an immediate flush of pending updates.
47
+ * Use this when you need to ensure updates are persisted (e.g., before reading).
48
+ */
49
+ flush(): Promise<void>;
50
+ /**
51
+ * Get the number of pending updates.
52
+ */
53
+ get pendingCount(): number;
54
+ private scheduleFlush;
55
+ private doFlush;
56
+ private applyUpdates;
57
+ /**
58
+ * Cancel any pending flush timer.
59
+ * Call this when shutting down.
60
+ */
61
+ destroy(): void;
62
+ }
63
+ //# sourceMappingURL=tags-buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tags-buffer.d.ts","sourceRoot":"","sources":["../../src/utils/tags-buffer.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iDAAiD;IACjD,eAAe,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IACzD,wCAAwC;IACxC,gBAAgB,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,+BAA+B;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAQD;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0C;IAC1E,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA2D;IAC5F,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAkC;IAEtD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAA8B;gBAEtC,MAAM,EAAE,gBAAgB;IAOpC;;;OAGG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI;IAc/C;;;OAGG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IASjC;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAarC;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB5B;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,OAAO,CAAC,aAAa;YAiBP,OAAO;IA0CrB,OAAO,CAAC,YAAY;IAmCpB;;;OAGG;IACH,OAAO,IAAI,IAAI;CAMhB"}