@keq-request/cache 5.0.0-alpha.21 → 5.0.0-alpha.23
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/CHANGELOG.md +26 -0
- package/dist/cache-entry/cache-entry.d.ts.map +1 -1
- package/dist/cache.d.ts +13 -4
- package/dist/cache.d.ts.map +1 -1
- package/dist/constants/index.d.ts +5 -0
- package/dist/constants/index.d.ts.map +1 -0
- package/dist/constants/max-expired-at.d.ts +2 -0
- package/dist/constants/max-expired-at.d.ts.map +1 -0
- package/dist/exceptions/cache-exception.d.ts +5 -0
- package/dist/exceptions/cache-exception.d.ts.map +1 -0
- package/dist/exceptions/index.d.ts +2 -0
- package/dist/exceptions/index.d.ts.map +1 -0
- package/dist/index.d.ts +4 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +295 -224
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +295 -224
- package/dist/index.mjs.map +1 -1
- package/dist/request-cache-handler/index.d.ts +3 -0
- package/dist/request-cache-handler/index.d.ts.map +1 -0
- package/dist/request-cache-handler/request-cache-handler.d.ts +22 -0
- package/dist/request-cache-handler/request-cache-handler.d.ts.map +1 -0
- package/dist/request-cache-handler/types/index.d.ts +2 -0
- package/dist/request-cache-handler/types/index.d.ts.map +1 -0
- package/dist/{types/keq-cache-option.d.ts → request-cache-handler/types/request-cache-options.d.ts} +6 -4
- package/dist/request-cache-handler/types/request-cache-options.d.ts.map +1 -0
- package/dist/storage/index.d.ts +4 -4
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/indexed-db-storage/base-indexed-db-storage.d.ts +2 -4
- package/dist/storage/indexed-db-storage/base-indexed-db-storage.d.ts.map +1 -1
- package/dist/storage/indexed-db-storage/index.d.ts +3 -0
- package/dist/storage/indexed-db-storage/index.d.ts.map +1 -0
- package/dist/storage/indexed-db-storage/indexed-db-storage.d.ts.map +1 -1
- package/dist/storage/indexed-db-storage/types/index.d.ts +7 -0
- package/dist/storage/indexed-db-storage/types/index.d.ts.map +1 -0
- package/dist/storage/indexed-db-storage/types/indexed-db-storage-options.d.ts +1 -1
- package/dist/storage/indexed-db-storage/types/indexed-db-storage-options.d.ts.map +1 -1
- package/dist/storage/internal-storage/internal-storage.d.ts +1 -1
- package/dist/storage/internal-storage/internal-storage.d.ts.map +1 -1
- package/dist/storage/memory-storage/base-memory-storage.d.ts +5 -4
- package/dist/storage/memory-storage/base-memory-storage.d.ts.map +1 -1
- package/dist/storage/memory-storage/index.d.ts +3 -0
- package/dist/storage/memory-storage/index.d.ts.map +1 -0
- package/dist/storage/memory-storage/memory-storage.d.ts +1 -0
- package/dist/storage/memory-storage/memory-storage.d.ts.map +1 -1
- package/dist/storage/memory-storage/types/index.d.ts +3 -0
- package/dist/storage/memory-storage/types/index.d.ts.map +1 -0
- package/dist/storage/memory-storage/types/memory-storage-options.d.ts +1 -1
- package/dist/storage/memory-storage/types/memory-storage-options.d.ts.map +1 -1
- package/dist/storage/memory-storage/utils/humanize-size.d.ts +6 -0
- package/dist/storage/memory-storage/utils/humanize-size.d.ts.map +1 -0
- package/dist/storage/memory-storage/utils/index.d.ts +3 -0
- package/dist/storage/memory-storage/utils/index.d.ts.map +1 -0
- package/dist/storage/memory-storage/utils/serialize-response-body.d.ts +6 -0
- package/dist/storage/memory-storage/utils/serialize-response-body.d.ts.map +1 -0
- package/dist/storage/multi-tier-storage/index.d.ts +1 -0
- package/dist/storage/multi-tier-storage/index.d.ts.map +1 -1
- package/dist/storage/multi-tier-storage/types/index.d.ts +2 -0
- package/dist/storage/multi-tier-storage/types/index.d.ts.map +1 -0
- package/dist/storage/tier-storage/index.d.ts +2 -2
- package/dist/storage/tier-storage/index.d.ts.map +1 -1
- package/dist/storage/tier-storage/types/index.d.ts +2 -0
- package/dist/storage/tier-storage/types/index.d.ts.map +1 -0
- package/dist/strategies/cache-first.d.ts.map +1 -1
- package/dist/strategies/index.d.ts +5 -0
- package/dist/strategies/index.d.ts.map +1 -0
- package/dist/strategies/network-first.d.ts.map +1 -1
- package/dist/strategies/network-only.d.ts.map +1 -1
- package/dist/strategies/stale-while-revalidate.d.ts.map +1 -1
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/keq-cache-key.d.ts +2 -1
- package/dist/types/keq-cache-key.d.ts.map +1 -1
- package/dist/types/keq-cache-pattern.d.ts +3 -0
- package/dist/types/keq-cache-pattern.d.ts.map +1 -0
- package/dist/types/keq-cache-rule.d.ts +4 -4
- package/dist/types/keq-cache-rule.d.ts.map +1 -1
- package/dist/types/keq-cache-strategy.d.ts +2 -2
- package/dist/types/keq-cache-strategy.d.ts.map +1 -1
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +5 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/package.json +6 -11
- package/dist/strategies/utils/cache-context.d.ts +0 -5
- package/dist/strategies/utils/cache-context.d.ts.map +0 -1
- package/dist/strategies/utils/index.d.ts +0 -2
- package/dist/strategies/utils/index.d.ts.map +0 -1
- package/dist/types/keq-cache-option.d.ts.map +0 -1
- package/dist/types/keq-cache-parameters.d.ts +0 -12
- package/dist/types/keq-cache-parameters.d.ts.map +0 -1
- package/dist/types/strategies-options.d.ts +0 -14
- package/dist/types/strategies-options.d.ts.map +0 -1
- package/dist/utils/debug.d.ts +0 -2
- package/dist/utils/debug.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -32,10 +32,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
32
32
|
// src/index.ts
|
|
33
33
|
var index_exports = {};
|
|
34
34
|
__export(index_exports, {
|
|
35
|
-
CacheStorage: () => KeqCacheStorage,
|
|
36
35
|
Eviction: () => Eviction,
|
|
37
36
|
IndexedDBStorage: () => IndexedDBStorage,
|
|
37
|
+
KeqCacheStorage: () => KeqCacheStorage,
|
|
38
38
|
MemoryStorage: () => MemoryStorage,
|
|
39
|
+
MultiTierStorage: () => MultiTierStorage,
|
|
39
40
|
Size: () => Size,
|
|
40
41
|
Strategy: () => Strategy,
|
|
41
42
|
TierStorage: () => TierStorage,
|
|
@@ -44,45 +45,21 @@ __export(index_exports, {
|
|
|
44
45
|
module.exports = __toCommonJS(index_exports);
|
|
45
46
|
|
|
46
47
|
// src/cache.ts
|
|
48
|
+
var R2 = __toESM(require("ramda"));
|
|
49
|
+
|
|
50
|
+
// src/request-cache-handler/request-cache-handler.ts
|
|
47
51
|
var R = __toESM(require("ramda"));
|
|
52
|
+
|
|
53
|
+
// src/exceptions/cache-exception.ts
|
|
48
54
|
var import_keq = require("keq");
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
let cOpt = ctx.options.cache;
|
|
58
|
-
const rule = rules.find((rule2) => {
|
|
59
|
-
if (rule2.pattern === void 0 || rule2.pattern === true) return true;
|
|
60
|
-
if (typeof rule2.pattern === "function") return rule2.pattern(ctx);
|
|
61
|
-
return rule2.pattern.test(ctx.request.__url__.href);
|
|
62
|
-
});
|
|
63
|
-
if (rule) cOpt = R.mergeRight(rule, cOpt || {});
|
|
64
|
-
if (!cOpt || R.isEmpty(cOpt)) {
|
|
65
|
-
await next();
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
let key = ctx.locationId;
|
|
69
|
-
if (cOpt.key) {
|
|
70
|
-
if (typeof cOpt.key === "function") key = cOpt.key(ctx);
|
|
71
|
-
else key = cOpt.key;
|
|
72
|
-
} else if (opts == null ? void 0 : opts.keyFactory) {
|
|
73
|
-
key = opts.keyFactory(ctx);
|
|
74
|
-
}
|
|
75
|
-
if (!key) throw new import_keq.Exception("Cache key is required");
|
|
76
|
-
const strategy = cOpt.strategy;
|
|
77
|
-
const opt = {
|
|
78
|
-
key,
|
|
79
|
-
storage,
|
|
80
|
-
ttl: cOpt.ttl,
|
|
81
|
-
exclude: cOpt.exclude
|
|
82
|
-
};
|
|
83
|
-
await strategy(opt)(ctx, next);
|
|
84
|
-
};
|
|
85
|
-
}
|
|
55
|
+
var CacheException = class extends import_keq.Exception {
|
|
56
|
+
constructor(message) {
|
|
57
|
+
super("[@keq-request/cache] ".concat(message));
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// src/cache-entry/cache-entry.ts
|
|
62
|
+
var import_keq2 = require("keq");
|
|
86
63
|
|
|
87
64
|
// src/utils/get-response-bytes.ts
|
|
88
65
|
async function getResponseBytes(response) {
|
|
@@ -94,6 +71,124 @@ async function getResponseBytes(response) {
|
|
|
94
71
|
return arrayBuffer.byteLength;
|
|
95
72
|
}
|
|
96
73
|
|
|
74
|
+
// src/constants/max-expired-at.ts
|
|
75
|
+
var MAX_EXPIRED_AT = /* @__PURE__ */ new Date(864e13);
|
|
76
|
+
|
|
77
|
+
// src/constants/eviction.enum.ts
|
|
78
|
+
var Eviction = /* @__PURE__ */ ((Eviction2) => {
|
|
79
|
+
Eviction2["LRU"] = "lru";
|
|
80
|
+
Eviction2["LFU"] = "lfu";
|
|
81
|
+
Eviction2["RANDOM"] = "random";
|
|
82
|
+
Eviction2["TTL"] = "ttl";
|
|
83
|
+
return Eviction2;
|
|
84
|
+
})(Eviction || {});
|
|
85
|
+
|
|
86
|
+
// src/constants/size.enum.ts
|
|
87
|
+
var Size = /* @__PURE__ */ ((Size2) => {
|
|
88
|
+
Size2[Size2["B"] = 1] = "B";
|
|
89
|
+
Size2[Size2["KB"] = 1024] = "KB";
|
|
90
|
+
Size2[Size2["MB"] = 1048576] = "MB";
|
|
91
|
+
Size2[Size2["GB"] = 1073741824] = "GB";
|
|
92
|
+
return Size2;
|
|
93
|
+
})(Size || {});
|
|
94
|
+
|
|
95
|
+
// src/strategies/cache-first.ts
|
|
96
|
+
var cacheFirst = async function cacheFirst2(handler, context, next) {
|
|
97
|
+
const [cacheKey, cacheValue] = await handler.getCache(context);
|
|
98
|
+
if (cacheValue) {
|
|
99
|
+
context.emitter.emit("cache:hit", { key: cacheKey, response: cacheValue.response, context });
|
|
100
|
+
context.res = cacheValue.response;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
context.emitter.emit("cache:miss", { key: cacheKey, context });
|
|
104
|
+
await next();
|
|
105
|
+
const [, entry] = await handler.setCache(context);
|
|
106
|
+
if (entry) {
|
|
107
|
+
context.emitter.emit("cache:update", {
|
|
108
|
+
key: entry.key,
|
|
109
|
+
oldResponse: void 0,
|
|
110
|
+
newResponse: entry.response,
|
|
111
|
+
context
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// src/strategies/network-first.ts
|
|
117
|
+
var networkFirst = async function networkFirst2(handler, context, next) {
|
|
118
|
+
try {
|
|
119
|
+
await next();
|
|
120
|
+
const [, cache2] = await handler.getCache(context);
|
|
121
|
+
const [, entry] = await handler.setCache(context);
|
|
122
|
+
if (entry) {
|
|
123
|
+
context.emitter.emit("cache:update", {
|
|
124
|
+
key: entry.key,
|
|
125
|
+
oldResponse: cache2 == null ? void 0 : cache2.response,
|
|
126
|
+
newResponse: entry.response,
|
|
127
|
+
context
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
} catch (err) {
|
|
131
|
+
const [key, cache2] = await handler.getCache(context);
|
|
132
|
+
if (!cache2) {
|
|
133
|
+
context.emitter.emit("cache:miss", { key, context });
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
context.emitter.emit("cache:hit", { key, response: cache2.response, context });
|
|
137
|
+
context.res = cache2.response;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// src/strategies/network-only.ts
|
|
142
|
+
var networkOnly = async function(handler, context, next) {
|
|
143
|
+
await next();
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// src/strategies/stale-while-revalidate.ts
|
|
147
|
+
var staleWhileRevalidate = async function(handler, context, next) {
|
|
148
|
+
const [key, cache2] = await handler.getCache(context);
|
|
149
|
+
if (cache2) {
|
|
150
|
+
context.emitter.emit("cache:hit", { key, response: cache2.response, context });
|
|
151
|
+
const orchestrator = context.orchestration.fork();
|
|
152
|
+
context.res = cache2.response;
|
|
153
|
+
setTimeout(async () => {
|
|
154
|
+
try {
|
|
155
|
+
await orchestrator.execute();
|
|
156
|
+
const context2 = orchestrator.context;
|
|
157
|
+
const [, entry] = await handler.setCache(context2);
|
|
158
|
+
if (entry) {
|
|
159
|
+
context2.emitter.emit("cache:update", {
|
|
160
|
+
key,
|
|
161
|
+
oldResponse: cache2.response,
|
|
162
|
+
newResponse: entry.response,
|
|
163
|
+
context: context2
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
} catch (err) {
|
|
167
|
+
}
|
|
168
|
+
}, 1);
|
|
169
|
+
} else {
|
|
170
|
+
context.emitter.emit("cache:miss", { key, context });
|
|
171
|
+
await next();
|
|
172
|
+
const [, entry] = await handler.setCache(context);
|
|
173
|
+
if (entry) {
|
|
174
|
+
context.emitter.emit("cache:update", {
|
|
175
|
+
key,
|
|
176
|
+
oldResponse: void 0,
|
|
177
|
+
newResponse: entry.response,
|
|
178
|
+
context
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// src/constants/strategy.enum.ts
|
|
185
|
+
var Strategy = {
|
|
186
|
+
STALE_WHILE_REVALIDATE: staleWhileRevalidate,
|
|
187
|
+
NETWORK_FIRST: networkFirst,
|
|
188
|
+
NETWORK_ONLY: networkOnly,
|
|
189
|
+
CACHE_FIRST: cacheFirst
|
|
190
|
+
};
|
|
191
|
+
|
|
97
192
|
// src/cache-entry/cache-entry.ts
|
|
98
193
|
var CacheEntry = class _CacheEntry {
|
|
99
194
|
constructor(options) {
|
|
@@ -107,13 +202,13 @@ var CacheEntry = class _CacheEntry {
|
|
|
107
202
|
__publicField(this, "expiredAt");
|
|
108
203
|
var _a;
|
|
109
204
|
this.key = options.key;
|
|
110
|
-
this.response = options.response;
|
|
205
|
+
this.response = (0, import_keq2.createProxyResponse)(options.response);
|
|
111
206
|
this.size = options.size;
|
|
112
|
-
this.expiredAt = (_a = options.expiredAt) != null ? _a :
|
|
207
|
+
this.expiredAt = (_a = options.expiredAt) != null ? _a : MAX_EXPIRED_AT;
|
|
113
208
|
}
|
|
114
209
|
static async build(options) {
|
|
115
210
|
var _a;
|
|
116
|
-
const expiredAt = "expiredAt" in options ? options.expiredAt : "ttl" in options && typeof options.ttl === "number" && options.ttl > 0 ? new Date(Date.now() + options.ttl * 1e3) :
|
|
211
|
+
const expiredAt = "expiredAt" in options ? options.expiredAt : "ttl" in options && typeof options.ttl === "number" && options.ttl > 0 ? new Date(Date.now() + options.ttl * 1e3) : MAX_EXPIRED_AT;
|
|
117
212
|
const response = options.response.clone();
|
|
118
213
|
return new _CacheEntry({
|
|
119
214
|
key: options.key,
|
|
@@ -139,164 +234,106 @@ var CacheEntry = class _CacheEntry {
|
|
|
139
234
|
}
|
|
140
235
|
};
|
|
141
236
|
|
|
142
|
-
// src/
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
237
|
+
// src/request-cache-handler/request-cache-handler.ts
|
|
238
|
+
var RequestCacheHandler = class {
|
|
239
|
+
constructor(storage, options) {
|
|
240
|
+
this.storage = storage;
|
|
241
|
+
this.options = options;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Get cache key for request
|
|
245
|
+
*/
|
|
246
|
+
getRequestCacheKey(context) {
|
|
247
|
+
const options = this.options;
|
|
248
|
+
if (typeof options.key === "string") return options.key;
|
|
249
|
+
else if (typeof options.key === "function") return options.key(context);
|
|
250
|
+
else if (R.isNil(options.key) && context.locationId) return context.locationId;
|
|
251
|
+
else throw new CacheException("Cannot resolve cache key");
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Get cache from storage
|
|
255
|
+
*/
|
|
256
|
+
async getCache(context) {
|
|
257
|
+
const key = this.getRequestCacheKey(context);
|
|
258
|
+
return [key, await this.storage.get(key)];
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Store response that in context to storage
|
|
262
|
+
*/
|
|
263
|
+
async setCache(context) {
|
|
264
|
+
const options = this.options;
|
|
265
|
+
const key = this.getRequestCacheKey(context);
|
|
266
|
+
if (!context.response) return [key, void 0];
|
|
267
|
+
if (options.exclude && await options.exclude(context.response)) return [key, void 0];
|
|
268
|
+
const entry = await CacheEntry.build({
|
|
269
|
+
key,
|
|
270
|
+
response: context.response,
|
|
271
|
+
ttl: options.ttl
|
|
272
|
+
});
|
|
273
|
+
void this.storage.set(entry);
|
|
274
|
+
return [key, entry];
|
|
275
|
+
}
|
|
276
|
+
};
|
|
156
277
|
|
|
157
|
-
// src/
|
|
158
|
-
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (
|
|
163
|
-
|
|
164
|
-
context.res = cache2.response;
|
|
278
|
+
// src/cache.ts
|
|
279
|
+
function cache(options) {
|
|
280
|
+
const storage = options.storage;
|
|
281
|
+
const rules = (options == null ? void 0 : options.rules) || [];
|
|
282
|
+
return async function cache2(ctx, next) {
|
|
283
|
+
if (ctx.options.cache === false) {
|
|
284
|
+
await next();
|
|
165
285
|
return;
|
|
166
286
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
context
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
// src/strategies/network-first.ts
|
|
182
|
-
var networkFirst = function(opts) {
|
|
183
|
-
const { key, storage } = opts;
|
|
184
|
-
return async function(context, next) {
|
|
185
|
-
try {
|
|
287
|
+
let requestCacheOptions = ctx.options.cache;
|
|
288
|
+
const rule = rules.find((rule2) => {
|
|
289
|
+
if (rule2.pattern === void 0 || rule2.pattern === true) return true;
|
|
290
|
+
if (typeof rule2.pattern === "function") return rule2.pattern(ctx);
|
|
291
|
+
return rule2.pattern.test(ctx.request.__url__.href);
|
|
292
|
+
});
|
|
293
|
+
if (rule) requestCacheOptions = R2.mergeRight(rule, requestCacheOptions || {});
|
|
294
|
+
if (!requestCacheOptions || R2.isEmpty(requestCacheOptions)) {
|
|
186
295
|
await next();
|
|
187
|
-
|
|
188
|
-
const entry = await cacheContext(opts, context);
|
|
189
|
-
if (entry) {
|
|
190
|
-
context.emitter.emit("cache:update", {
|
|
191
|
-
key,
|
|
192
|
-
oldResponse: cache2 == null ? void 0 : cache2.response,
|
|
193
|
-
newResponse: entry.response,
|
|
194
|
-
context
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
} catch (err) {
|
|
198
|
-
const cache2 = await storage.get(key);
|
|
199
|
-
if (!cache2) {
|
|
200
|
-
context.emitter.emit("cache:miss", { key, context });
|
|
201
|
-
throw err;
|
|
202
|
-
}
|
|
203
|
-
context.emitter.emit("cache:hit", { key, response: cache2.response, context });
|
|
204
|
-
context.res = cache2.response;
|
|
296
|
+
return;
|
|
205
297
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
// src/strategies/network-only.ts
|
|
210
|
-
var networkOnly = function(opts) {
|
|
211
|
-
return async function(ctx, next) {
|
|
212
|
-
await next();
|
|
213
|
-
};
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
// src/strategies/stale-while-revalidate.ts
|
|
217
|
-
var staleWhileRevalidate = function(opts) {
|
|
218
|
-
const { key, storage } = opts;
|
|
219
|
-
return async function(context, next) {
|
|
220
|
-
const cache2 = await storage.get(key);
|
|
221
|
-
if (cache2) {
|
|
222
|
-
context.emitter.emit("cache:hit", { key, response: cache2.response, context });
|
|
223
|
-
const orchestrator = context.orchestration.fork();
|
|
224
|
-
context.res = cache2.response;
|
|
225
|
-
setTimeout(async () => {
|
|
226
|
-
try {
|
|
227
|
-
await orchestrator.execute();
|
|
228
|
-
const context2 = orchestrator.context;
|
|
229
|
-
const entry = await cacheContext(opts, context2);
|
|
230
|
-
if (entry) {
|
|
231
|
-
context2.emitter.emit("cache:update", {
|
|
232
|
-
key,
|
|
233
|
-
oldResponse: cache2.response,
|
|
234
|
-
newResponse: entry.response,
|
|
235
|
-
context: context2
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
} catch (err) {
|
|
239
|
-
}
|
|
240
|
-
}, 1);
|
|
241
|
-
} else {
|
|
242
|
-
context.emitter.emit("cache:miss", { key, context });
|
|
298
|
+
if (!requestCacheOptions.key) requestCacheOptions.key = options.keyFactory;
|
|
299
|
+
if (!ctx.locationId && !requestCacheOptions.key) {
|
|
300
|
+
console.warn("[@keq/cache] Warning: Cannot resolve Cache Key. Cache is skipped.");
|
|
243
301
|
await next();
|
|
244
|
-
|
|
245
|
-
if (entry) {
|
|
246
|
-
context.emitter.emit("cache:update", {
|
|
247
|
-
key,
|
|
248
|
-
oldResponse: void 0,
|
|
249
|
-
newResponse: entry.response,
|
|
250
|
-
context
|
|
251
|
-
});
|
|
252
|
-
}
|
|
302
|
+
return;
|
|
253
303
|
}
|
|
304
|
+
const handler = new RequestCacheHandler(storage, requestCacheOptions);
|
|
305
|
+
const strategy = requestCacheOptions.strategy;
|
|
306
|
+
await strategy(handler, ctx, next);
|
|
254
307
|
};
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// src/constants/strategy.enum.ts
|
|
258
|
-
var Strategy = {
|
|
259
|
-
STALE_WHILE_REVALIDATE: staleWhileRevalidate,
|
|
260
|
-
NETWORK_FIRST: networkFirst,
|
|
261
|
-
NETWORK_ONLY: networkOnly,
|
|
262
|
-
CACHE_FIRST: cacheFirst
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
// src/constants/eviction.enum.ts
|
|
266
|
-
var Eviction = /* @__PURE__ */ ((Eviction2) => {
|
|
267
|
-
Eviction2["LRU"] = "lru";
|
|
268
|
-
Eviction2["LFU"] = "lfu";
|
|
269
|
-
Eviction2["RANDOM"] = "random";
|
|
270
|
-
Eviction2["TTL"] = "ttl";
|
|
271
|
-
return Eviction2;
|
|
272
|
-
})(Eviction || {});
|
|
273
|
-
|
|
274
|
-
// src/constants/size.enum.ts
|
|
275
|
-
var Size = /* @__PURE__ */ ((Size2) => {
|
|
276
|
-
Size2[Size2["B"] = 1] = "B";
|
|
277
|
-
Size2[Size2["KB"] = 1024] = "KB";
|
|
278
|
-
Size2[Size2["MB"] = 1048576] = "MB";
|
|
279
|
-
Size2[Size2["GB"] = 1073741824] = "GB";
|
|
280
|
-
return Size2;
|
|
281
|
-
})(Size || {});
|
|
308
|
+
}
|
|
282
309
|
|
|
283
310
|
// src/storage/memory-storage/ttl-memory-storage.ts
|
|
284
311
|
var import_dayjs2 = __toESM(require("dayjs"));
|
|
285
|
-
var
|
|
312
|
+
var R4 = __toESM(require("ramda"));
|
|
286
313
|
|
|
287
314
|
// src/storage/memory-storage/base-memory-storage.ts
|
|
288
315
|
var import_dayjs = __toESM(require("dayjs"));
|
|
289
|
-
var
|
|
290
|
-
|
|
291
|
-
// src/utils/debug.ts
|
|
292
|
-
function debug(...args) {
|
|
293
|
-
console.debug("[@keq-cache] [DEBUG] ", ...args);
|
|
294
|
-
}
|
|
316
|
+
var R3 = __toESM(require("ramda"));
|
|
295
317
|
|
|
296
318
|
// src/storage/keq-cache-storage.ts
|
|
297
319
|
var KeqCacheStorage = class {
|
|
298
320
|
};
|
|
299
321
|
|
|
322
|
+
// src/utils/logger.ts
|
|
323
|
+
var Logger = class {
|
|
324
|
+
static debug(...args) {
|
|
325
|
+
console.debug("[@keq-cache] [DEBUG] ", ...args);
|
|
326
|
+
}
|
|
327
|
+
static error(...args) {
|
|
328
|
+
console.error("[@keq-cache] [ERROR] ", ...args);
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
// src/utils/random.ts
|
|
333
|
+
function random(min, max) {
|
|
334
|
+
return Math.floor(Math.random() * (max - min)) + min;
|
|
335
|
+
}
|
|
336
|
+
|
|
300
337
|
// src/storage/internal-storage/internal-storage.ts
|
|
301
338
|
var InternalStorage = class extends KeqCacheStorage {
|
|
302
339
|
constructor(options) {
|
|
@@ -311,7 +348,7 @@ var InternalStorage = class extends KeqCacheStorage {
|
|
|
311
348
|
__publicField(this, "__onCacheEvict__");
|
|
312
349
|
__publicField(this, "__onCacheExpired__");
|
|
313
350
|
if ((options == null ? void 0 : options.size) && (typeof (options == null ? void 0 : options.size) !== "number" || options.size <= 0)) {
|
|
314
|
-
throw
|
|
351
|
+
throw new CacheException("Invalid size: ".concat(String(options == null ? void 0 : options.size)));
|
|
315
352
|
}
|
|
316
353
|
this.__size__ = (_a = options == null ? void 0 : options.size) != null ? _a : Infinity;
|
|
317
354
|
this.__debug__ = !!(options == null ? void 0 : options.debug);
|
|
@@ -324,12 +361,38 @@ var InternalStorage = class extends KeqCacheStorage {
|
|
|
324
361
|
debug(fn) {
|
|
325
362
|
if (this.__debug__) {
|
|
326
363
|
fn((...args) => {
|
|
327
|
-
debug("[Storage(".concat(this.__id__, ")]"), ...args);
|
|
364
|
+
Logger.debug("[Storage(".concat(this.__id__, ")]"), ...args);
|
|
328
365
|
});
|
|
329
366
|
}
|
|
330
367
|
}
|
|
331
368
|
};
|
|
332
369
|
|
|
370
|
+
// src/storage/memory-storage/utils/humanize-size.ts
|
|
371
|
+
function humanizeSize(size) {
|
|
372
|
+
if (size < 1024) return "".concat(size, " B");
|
|
373
|
+
if (size < 1024 * 1024) return "".concat((size / 1024).toFixed(2), " KB");
|
|
374
|
+
if (size < 1024 * 1024 * 1024) return "".concat((size / (1024 * 1024)).toFixed(2), " MB");
|
|
375
|
+
return "".concat((size / (1024 * 1024 * 1024)).toFixed(2), " GB");
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// src/storage/memory-storage/utils/serialize-response-body.ts
|
|
379
|
+
async function serializeResponseBody(response) {
|
|
380
|
+
var _a;
|
|
381
|
+
const contentType = (_a = response.headers.get("content-type")) != null ? _a : "";
|
|
382
|
+
try {
|
|
383
|
+
if (contentType.includes("application/json")) {
|
|
384
|
+
const json = await response.json();
|
|
385
|
+
return JSON.stringify(json);
|
|
386
|
+
}
|
|
387
|
+
if (contentType.includes("text/") || contentType.includes("application/xml") || contentType.includes("application/javascript")) {
|
|
388
|
+
return await response.text();
|
|
389
|
+
}
|
|
390
|
+
return "[Binary or unsupported content]";
|
|
391
|
+
} catch {
|
|
392
|
+
return "[Unable to serialize]";
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
333
396
|
// src/storage/memory-storage/base-memory-storage.ts
|
|
334
397
|
var BaseMemoryStorage = class extends InternalStorage {
|
|
335
398
|
constructor() {
|
|
@@ -340,7 +403,7 @@ var BaseMemoryStorage = class extends InternalStorage {
|
|
|
340
403
|
__publicField(this, "lastEvictExpiredTime", (0, import_dayjs.default)());
|
|
341
404
|
}
|
|
342
405
|
get size() {
|
|
343
|
-
const used =
|
|
406
|
+
const used = R3.sum(R3.pluck("size", [...this.storage.values()]));
|
|
344
407
|
const free = this.__size__ > used ? this.__size__ - used : 0;
|
|
345
408
|
return {
|
|
346
409
|
used,
|
|
@@ -383,23 +446,6 @@ var BaseMemoryStorage = class extends InternalStorage {
|
|
|
383
446
|
remove(key) {
|
|
384
447
|
this.__remove__([key]);
|
|
385
448
|
}
|
|
386
|
-
/**
|
|
387
|
-
* Print all cache entries
|
|
388
|
-
*/
|
|
389
|
-
print() {
|
|
390
|
-
const entries = Array.from(this.storage.entries()).map(([key, entry]) => {
|
|
391
|
-
var _a;
|
|
392
|
-
return {
|
|
393
|
-
key,
|
|
394
|
-
size: entry.size,
|
|
395
|
-
expiredAt: entry.expiredAt ? (0, import_dayjs.default)(entry.expiredAt).format("YYYY-MM-DD HH:mm:ss") : "N/A",
|
|
396
|
-
visitCount: (_a = this.visitCountRecords.get(key)) != null ? _a : 0,
|
|
397
|
-
lastVisit: this.visitTimeRecords.get(key) ? (0, import_dayjs.default)(this.visitTimeRecords.get(key)).format("YYYY-MM-DD HH:mm:ss") : "N/A"
|
|
398
|
-
};
|
|
399
|
-
});
|
|
400
|
-
console.table(entries);
|
|
401
|
-
console.log("Total: ".concat(entries.length, " entries, Used: ").concat(this.size.used, ", Free: ").concat(this.size.free));
|
|
402
|
-
}
|
|
403
449
|
/**
|
|
404
450
|
* @zh 清除过期的缓存
|
|
405
451
|
*/
|
|
@@ -427,6 +473,33 @@ var BaseMemoryStorage = class extends InternalStorage {
|
|
|
427
473
|
const size = this.size;
|
|
428
474
|
return size.free >= expectSize;
|
|
429
475
|
}
|
|
476
|
+
/**
|
|
477
|
+
* @en Print all cached data using console.table for debugging
|
|
478
|
+
* @zh 使用 console.table 打印所有缓存数据,用于调试
|
|
479
|
+
*/
|
|
480
|
+
async print() {
|
|
481
|
+
if (this.storage.size === 0) {
|
|
482
|
+
console.log("MemoryStorage is empty");
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
const entries = await Promise.all(
|
|
486
|
+
[...this.storage.entries()].map(async ([key, entry]) => {
|
|
487
|
+
var _a, _b, _c;
|
|
488
|
+
const body = await serializeResponseBody(entry.response.clone());
|
|
489
|
+
return {
|
|
490
|
+
key,
|
|
491
|
+
size: humanizeSize(entry.size),
|
|
492
|
+
"Expired Time": entry.expiredAt.getTime() >= MAX_EXPIRED_AT.getTime() ? "-" : entry.expiredAt.toISOString(),
|
|
493
|
+
"Visit Count": (_a = this.visitCountRecords.get(key)) != null ? _a : 0,
|
|
494
|
+
"Last Visit Time": (_c = (_b = this.visitTimeRecords.get(key)) == null ? void 0 : _b.toISOString()) != null ? _c : "-",
|
|
495
|
+
"Response Status": entry.response.status,
|
|
496
|
+
"Response URL": entry.response.url,
|
|
497
|
+
"Response Body": body
|
|
498
|
+
};
|
|
499
|
+
})
|
|
500
|
+
);
|
|
501
|
+
console.table(entries);
|
|
502
|
+
}
|
|
430
503
|
};
|
|
431
504
|
|
|
432
505
|
// src/storage/memory-storage/ttl-memory-storage.ts
|
|
@@ -464,7 +537,7 @@ var TTLMemoryStorage = class extends BaseMemoryStorage {
|
|
|
464
537
|
const bExpiredAt = (0, import_dayjs2.default)(b.expiredAt);
|
|
465
538
|
return aExpiredAt.isBefore(bExpiredAt) ? 1 : -1;
|
|
466
539
|
});
|
|
467
|
-
if (
|
|
540
|
+
if (R4.sum(R4.pluck("size", entries)) < deficitSize) {
|
|
468
541
|
this.debug((log) => log("Storage Size Not Enough: ", this.size.free, " < ", deficitSize));
|
|
469
542
|
return false;
|
|
470
543
|
}
|
|
@@ -480,11 +553,6 @@ var TTLMemoryStorage = class extends BaseMemoryStorage {
|
|
|
480
553
|
}
|
|
481
554
|
};
|
|
482
555
|
|
|
483
|
-
// src/utils/random.ts
|
|
484
|
-
function random(min, max) {
|
|
485
|
-
return Math.floor(Math.random() * (max - min)) + min;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
556
|
// src/storage/memory-storage/random-memory-storage.ts
|
|
489
557
|
var RandomMemoryStorage = class extends BaseMemoryStorage {
|
|
490
558
|
constructor(options) {
|
|
@@ -655,15 +723,18 @@ var MemoryStorage = class extends KeqCacheStorage {
|
|
|
655
723
|
remove(key) {
|
|
656
724
|
return this.storage.remove(key);
|
|
657
725
|
}
|
|
726
|
+
async print() {
|
|
727
|
+
return this.storage.print();
|
|
728
|
+
}
|
|
658
729
|
};
|
|
659
730
|
|
|
660
731
|
// src/storage/indexed-db-storage/random-indexed-db-storage.ts
|
|
661
|
-
var
|
|
732
|
+
var R6 = __toESM(require("ramda"));
|
|
662
733
|
|
|
663
734
|
// src/storage/indexed-db-storage/base-indexed-db-storage.ts
|
|
664
|
-
var
|
|
665
|
-
var import_idb = require("idb");
|
|
735
|
+
var R5 = __toESM(require("ramda"));
|
|
666
736
|
var import_dayjs4 = __toESM(require("dayjs"));
|
|
737
|
+
var import_idb = require("idb");
|
|
667
738
|
|
|
668
739
|
// src/storage/indexed-db-storage/constants/default-table-name.ts
|
|
669
740
|
var DEFAULT_TABLE_NAME = "keq_cache_indexed_db_storage";
|
|
@@ -674,9 +745,9 @@ var BaseIndexedDBStorage = class extends InternalStorage {
|
|
|
674
745
|
super(options);
|
|
675
746
|
__publicField(this, "tableName", DEFAULT_TABLE_NAME);
|
|
676
747
|
__publicField(this, "db");
|
|
677
|
-
__publicField(this, "lastEvictExpiredTime", (0, import_dayjs4.default)());
|
|
748
|
+
__publicField(this, "lastEvictExpiredTime", (0, import_dayjs4.default)(0));
|
|
678
749
|
if ((options == null ? void 0 : options.tableName) === DEFAULT_TABLE_NAME) {
|
|
679
|
-
throw new
|
|
750
|
+
throw new CacheException('IndexedDBStorage name cannot be "'.concat(DEFAULT_TABLE_NAME, '"'));
|
|
680
751
|
}
|
|
681
752
|
this.tableName = (options == null ? void 0 : options.tableName) || DEFAULT_TABLE_NAME;
|
|
682
753
|
}
|
|
@@ -700,13 +771,13 @@ var BaseIndexedDBStorage = class extends InternalStorage {
|
|
|
700
771
|
}
|
|
701
772
|
},
|
|
702
773
|
blocked() {
|
|
703
|
-
|
|
774
|
+
Logger.error("[@keq-request/cache] IndexedDB Table ".concat(tableName, " is blocked"));
|
|
704
775
|
},
|
|
705
776
|
blocking() {
|
|
706
|
-
|
|
777
|
+
Logger.error("[@keq-request/cache] IndexedDB Table ".concat(tableName, " is blocking"));
|
|
707
778
|
},
|
|
708
779
|
terminated() {
|
|
709
|
-
|
|
780
|
+
Logger.error("[@keq-request/cache] IndexedDB Table ".concat(tableName, " is terminated"));
|
|
710
781
|
}
|
|
711
782
|
});
|
|
712
783
|
this.db = db;
|
|
@@ -715,7 +786,7 @@ var BaseIndexedDBStorage = class extends InternalStorage {
|
|
|
715
786
|
async getSize() {
|
|
716
787
|
const db = await this.openDB();
|
|
717
788
|
const items = await db.getAll("metadata");
|
|
718
|
-
const used =
|
|
789
|
+
const used = R5.sum(items.map((entry) => entry.size));
|
|
719
790
|
const free = this.__size__ - used;
|
|
720
791
|
return { used, free };
|
|
721
792
|
}
|
|
@@ -791,7 +862,7 @@ var BaseIndexedDBStorage = class extends InternalStorage {
|
|
|
791
862
|
}
|
|
792
863
|
async __remove__(tx, keys) {
|
|
793
864
|
await Promise.all(
|
|
794
|
-
|
|
865
|
+
R5.unnest(
|
|
795
866
|
keys.map((key) => [
|
|
796
867
|
tx.objectStore("metadata").delete(key),
|
|
797
868
|
tx.objectStore("response").delete(key),
|
|
@@ -817,15 +888,15 @@ var BaseIndexedDBStorage = class extends InternalStorage {
|
|
|
817
888
|
var _a;
|
|
818
889
|
const now = (0, import_dayjs4.default)();
|
|
819
890
|
if (now.diff(this.lastEvictExpiredTime, "second") < 1) return;
|
|
891
|
+
this.lastEvictExpiredTime = now;
|
|
820
892
|
try {
|
|
821
|
-
const now2 = (0, import_dayjs4.default)();
|
|
822
893
|
const db = await this.openDB();
|
|
823
894
|
const tx = db.transaction(["metadata", "response", "visits"], "readwrite");
|
|
824
895
|
const metadataStore = tx.objectStore("metadata");
|
|
825
|
-
let cursor = await metadataStore.index("expiredAt").openCursor(IDBKeyRange.upperBound(
|
|
896
|
+
let cursor = await metadataStore.index("expiredAt").openCursor(IDBKeyRange.upperBound(now.toDate()));
|
|
826
897
|
const expiredKeys = [];
|
|
827
898
|
while (cursor) {
|
|
828
|
-
if ((0, import_dayjs4.default)(cursor.value.expiredAt).isBefore(
|
|
899
|
+
if ((0, import_dayjs4.default)(cursor.value.expiredAt).isBefore(now)) {
|
|
829
900
|
expiredKeys.push(cursor.value.key);
|
|
830
901
|
cursor = await cursor.continue();
|
|
831
902
|
} else {
|
|
@@ -872,7 +943,7 @@ var RandomIndexedDBStorage = class extends BaseIndexedDBStorage {
|
|
|
872
943
|
const tx = db.transaction(["metadata", "response", "visits"], "readwrite");
|
|
873
944
|
const metadataStore = tx.objectStore("metadata");
|
|
874
945
|
const metadatas = await metadataStore.getAll();
|
|
875
|
-
const totalSize =
|
|
946
|
+
const totalSize = R6.sum(metadatas.map((m) => m.size));
|
|
876
947
|
if (totalSize < deficitSize) {
|
|
877
948
|
this.debug((log) => log("Storage Size Not Enough, deficit size: ".concat(deficitSize - totalSize)));
|
|
878
949
|
tx.abort();
|
|
@@ -1075,7 +1146,7 @@ var IndexedDBStorage = class extends KeqCacheStorage {
|
|
|
1075
1146
|
} else if (eviction === "ttl" /* TTL */) {
|
|
1076
1147
|
this.storage = new TTLIndexedDBStorage(options);
|
|
1077
1148
|
} else {
|
|
1078
|
-
throw
|
|
1149
|
+
throw new CacheException("Not Supported Eviction: ".concat(String(options == null ? void 0 : options.eviction)));
|
|
1079
1150
|
}
|
|
1080
1151
|
}
|
|
1081
1152
|
set(entry) {
|
|
@@ -1125,7 +1196,7 @@ var MultiTierStorage = class extends KeqCacheStorage {
|
|
|
1125
1196
|
* @zh 并发写入所有层的缓存
|
|
1126
1197
|
*/
|
|
1127
1198
|
async set(entry) {
|
|
1128
|
-
const promises = this.storages.map((storage) => storage.set(entry));
|
|
1199
|
+
const promises = this.storages.map(async (storage) => storage.set(entry));
|
|
1129
1200
|
await Promise.all(promises);
|
|
1130
1201
|
}
|
|
1131
1202
|
/**
|
|
@@ -1133,7 +1204,7 @@ var MultiTierStorage = class extends KeqCacheStorage {
|
|
|
1133
1204
|
* @zh 从所有层删除缓存条目
|
|
1134
1205
|
*/
|
|
1135
1206
|
async remove(key) {
|
|
1136
|
-
const promises = this.storages.map((storage) => storage.remove(key));
|
|
1207
|
+
const promises = this.storages.map(async (storage) => storage.remove(key));
|
|
1137
1208
|
await Promise.all(promises);
|
|
1138
1209
|
}
|
|
1139
1210
|
/**
|
|
@@ -1145,7 +1216,7 @@ var MultiTierStorage = class extends KeqCacheStorage {
|
|
|
1145
1216
|
if (lowerTierStorages.length === 0) {
|
|
1146
1217
|
return;
|
|
1147
1218
|
}
|
|
1148
|
-
const promises = lowerTierStorages.map((storage) => storage.set(entry.clone()));
|
|
1219
|
+
const promises = lowerTierStorages.map(async (storage) => storage.set(entry.clone()));
|
|
1149
1220
|
try {
|
|
1150
1221
|
await Promise.all(promises);
|
|
1151
1222
|
} catch (error) {
|