@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
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { createLogger } from './logger.js';
|
|
2
|
+
/**
|
|
3
|
+
* Buffers tag mapping updates to avoid GCS rate limiting.
|
|
4
|
+
* Collects updates in memory and flushes them at most once per second.
|
|
5
|
+
*/
|
|
6
|
+
export class TagsBuffer {
|
|
7
|
+
constructor(config) {
|
|
8
|
+
this.pendingUpdates = [];
|
|
9
|
+
this.flushTimer = null;
|
|
10
|
+
this.lastFlushTime = 0;
|
|
11
|
+
this.isFlushing = false;
|
|
12
|
+
this.flushPromise = null;
|
|
13
|
+
this.flushIntervalMs = config.flushIntervalMs ?? 1000;
|
|
14
|
+
this.readTagsMapping = config.readTagsMapping;
|
|
15
|
+
this.writeTagsMapping = config.writeTagsMapping;
|
|
16
|
+
this.log = createLogger(config.handlerName ?? 'TagsBuffer');
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Queue a tag addition for a cache key.
|
|
20
|
+
* The update will be flushed to storage at most once per second.
|
|
21
|
+
*/
|
|
22
|
+
addTags(cacheKey, tags) {
|
|
23
|
+
if (tags.length === 0) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
this.pendingUpdates.push({
|
|
27
|
+
type: 'add',
|
|
28
|
+
cacheKey,
|
|
29
|
+
tags,
|
|
30
|
+
});
|
|
31
|
+
this.scheduleFlush();
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Queue a cache key deletion from all tags.
|
|
35
|
+
* The update will be flushed to storage at most once per second.
|
|
36
|
+
*/
|
|
37
|
+
deleteKey(cacheKey) {
|
|
38
|
+
this.pendingUpdates.push({
|
|
39
|
+
type: 'delete',
|
|
40
|
+
cacheKey,
|
|
41
|
+
});
|
|
42
|
+
this.scheduleFlush();
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Queue multiple cache keys for deletion from all tags.
|
|
46
|
+
*/
|
|
47
|
+
deleteKeys(cacheKeys) {
|
|
48
|
+
for (const cacheKey of cacheKeys) {
|
|
49
|
+
this.pendingUpdates.push({
|
|
50
|
+
type: 'delete',
|
|
51
|
+
cacheKey,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (cacheKeys.length > 0) {
|
|
55
|
+
this.scheduleFlush();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Force an immediate flush of pending updates.
|
|
60
|
+
* Use this when you need to ensure updates are persisted (e.g., before reading).
|
|
61
|
+
*/
|
|
62
|
+
async flush() {
|
|
63
|
+
// If already flushing, wait for that to complete
|
|
64
|
+
if (this.flushPromise) {
|
|
65
|
+
await this.flushPromise;
|
|
66
|
+
// After waiting, check if there are still pending updates
|
|
67
|
+
if (this.pendingUpdates.length > 0) {
|
|
68
|
+
return this.flush();
|
|
69
|
+
}
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (this.pendingUpdates.length === 0) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
this.flushPromise = this.doFlush();
|
|
76
|
+
try {
|
|
77
|
+
await this.flushPromise;
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
this.flushPromise = null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get the number of pending updates.
|
|
85
|
+
*/
|
|
86
|
+
get pendingCount() {
|
|
87
|
+
return this.pendingUpdates.length;
|
|
88
|
+
}
|
|
89
|
+
scheduleFlush() {
|
|
90
|
+
// If a timer is already scheduled, let it handle the flush
|
|
91
|
+
if (this.flushTimer) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const timeSinceLastFlush = Date.now() - this.lastFlushTime;
|
|
95
|
+
const delay = Math.max(0, this.flushIntervalMs - timeSinceLastFlush);
|
|
96
|
+
this.flushTimer = setTimeout(() => {
|
|
97
|
+
this.flushTimer = null;
|
|
98
|
+
this.flush().catch((error) => {
|
|
99
|
+
this.log.error('Error during scheduled flush:', error);
|
|
100
|
+
});
|
|
101
|
+
}, delay);
|
|
102
|
+
}
|
|
103
|
+
async doFlush() {
|
|
104
|
+
if (this.isFlushing || this.pendingUpdates.length === 0) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
this.isFlushing = true;
|
|
108
|
+
// Take all pending updates
|
|
109
|
+
const updates = this.pendingUpdates;
|
|
110
|
+
this.pendingUpdates = [];
|
|
111
|
+
try {
|
|
112
|
+
// Read current state
|
|
113
|
+
const tagsMapping = await this.readTagsMapping();
|
|
114
|
+
// Apply all updates
|
|
115
|
+
this.applyUpdates(tagsMapping, updates);
|
|
116
|
+
// Write back
|
|
117
|
+
await this.writeTagsMapping(tagsMapping);
|
|
118
|
+
this.lastFlushTime = Date.now();
|
|
119
|
+
this.log.debug(`Flushed ${updates.length} tag updates`);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
// On failure, put updates back for retry
|
|
123
|
+
this.pendingUpdates = [...updates, ...this.pendingUpdates];
|
|
124
|
+
this.log.error('Error flushing tags, will retry:', error);
|
|
125
|
+
// Schedule a retry with backoff
|
|
126
|
+
if (!this.flushTimer) {
|
|
127
|
+
this.flushTimer = setTimeout(() => {
|
|
128
|
+
this.flushTimer = null;
|
|
129
|
+
this.flush().catch((e) => {
|
|
130
|
+
this.log.error('Retry flush failed:', e);
|
|
131
|
+
});
|
|
132
|
+
}, this.flushIntervalMs * 2);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
this.isFlushing = false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
applyUpdates(tagsMapping, updates) {
|
|
140
|
+
// Collect all keys to delete for efficient removal
|
|
141
|
+
const keysToDelete = new Set();
|
|
142
|
+
for (const update of updates) {
|
|
143
|
+
if (update.type === 'delete') {
|
|
144
|
+
keysToDelete.add(update.cacheKey);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Remove deleted keys from all tags
|
|
148
|
+
if (keysToDelete.size > 0) {
|
|
149
|
+
for (const tag of Object.keys(tagsMapping)) {
|
|
150
|
+
tagsMapping[tag] = tagsMapping[tag].filter((key) => !keysToDelete.has(key));
|
|
151
|
+
if (tagsMapping[tag].length === 0) {
|
|
152
|
+
delete tagsMapping[tag];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Add new tag mappings
|
|
157
|
+
for (const update of updates) {
|
|
158
|
+
if (update.type === 'add' && update.tags) {
|
|
159
|
+
for (const tag of update.tags) {
|
|
160
|
+
if (!tagsMapping[tag]) {
|
|
161
|
+
tagsMapping[tag] = [];
|
|
162
|
+
}
|
|
163
|
+
if (!tagsMapping[tag].includes(update.cacheKey)) {
|
|
164
|
+
tagsMapping[tag].push(update.cacheKey);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Cancel any pending flush timer.
|
|
172
|
+
* Call this when shutting down.
|
|
173
|
+
*/
|
|
174
|
+
destroy() {
|
|
175
|
+
if (this.flushTimer) {
|
|
176
|
+
clearTimeout(this.flushTimer);
|
|
177
|
+
this.flushTimer = null;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=tags-buffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tags-buffer.js","sourceRoot":"","sources":["../../src/utils/tags-buffer.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pantheon-systems/nextjs-cache-handler",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Custom cache handler for Next.js with support for Google Cloud Storage and file-based caching",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"prepublishOnly": "npm run build",
|
|
20
|
+
"clean": "rm -rf dist",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"test:watch": "vitest",
|
|
23
|
+
"test:coverage": "vitest run --coverage"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"next.js",
|
|
27
|
+
"cache",
|
|
28
|
+
"cache-handler",
|
|
29
|
+
"gcs",
|
|
30
|
+
"google-cloud-storage",
|
|
31
|
+
"pantheon"
|
|
32
|
+
],
|
|
33
|
+
"author": "Pantheon Systems",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"next": ">=14.0.0"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@google-cloud/storage": "^7.0.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^20",
|
|
43
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
44
|
+
"typescript": "^5.0.0",
|
|
45
|
+
"vitest": "^4.0.18"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18.0.0"
|
|
49
|
+
},
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "https://github.com/pantheon-systems/nextjs-cache-handler"
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://github.com/pantheon-systems/nextjs-cache-handler#readme",
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/pantheon-systems/nextjs-cache-handler/issues"
|
|
57
|
+
}
|
|
58
|
+
}
|