@keq-request/cache 5.0.0-alpha.34 → 5.0.0-alpha.35
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 +11 -0
- package/dist/index.d.mts +354 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.d.ts +352 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1211 -1276
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1183 -1251
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -9
- package/tsdown.config.ts +12 -0
- package/dist/cache-entry/cache-entry.d.ts +0 -17
- package/dist/cache-entry/cache-entry.d.ts.map +0 -1
- package/dist/cache-entry/index.d.ts +0 -4
- package/dist/cache-entry/index.d.ts.map +0 -1
- package/dist/cache-entry/types/cache-entry-build-options.d.ts +0 -8
- package/dist/cache-entry/types/cache-entry-build-options.d.ts.map +0 -1
- package/dist/cache-entry/types/cache-entry-options.d.ts +0 -7
- package/dist/cache-entry/types/cache-entry-options.d.ts.map +0 -1
- package/dist/cache.d.ts +0 -44
- package/dist/cache.d.ts.map +0 -1
- package/dist/constants/eviction.enum.d.ts +0 -7
- package/dist/constants/eviction.enum.d.ts.map +0 -1
- package/dist/constants/index.d.ts +0 -5
- package/dist/constants/index.d.ts.map +0 -1
- package/dist/constants/max-expired-at.d.ts +0 -2
- package/dist/constants/max-expired-at.d.ts.map +0 -1
- package/dist/constants/size.enum.d.ts +0 -7
- package/dist/constants/size.enum.d.ts.map +0 -1
- package/dist/constants/strategy.enum.d.ts +0 -7
- package/dist/constants/strategy.enum.d.ts.map +0 -1
- package/dist/exceptions/cache-exception.d.ts +0 -5
- package/dist/exceptions/cache-exception.d.ts.map +0 -1
- package/dist/exceptions/index.d.ts +0 -2
- package/dist/exceptions/index.d.ts.map +0 -1
- package/dist/request-cache-handler/index.d.ts +0 -2
- package/dist/request-cache-handler/index.d.ts.map +0 -1
- package/dist/request-cache-handler/request-cache-handler.d.ts +0 -24
- package/dist/request-cache-handler/request-cache-handler.d.ts.map +0 -1
- package/dist/storage/index.d.ts +0 -6
- package/dist/storage/index.d.ts.map +0 -1
- package/dist/storage/indexed-db-storage/base-indexed-db-storage.d.ts +0 -22
- package/dist/storage/indexed-db-storage/base-indexed-db-storage.d.ts.map +0 -1
- package/dist/storage/indexed-db-storage/constants/default-table-name.d.ts +0 -2
- package/dist/storage/indexed-db-storage/constants/default-table-name.d.ts.map +0 -1
- package/dist/storage/indexed-db-storage/index.d.ts +0 -3
- package/dist/storage/indexed-db-storage/index.d.ts.map +0 -1
- package/dist/storage/indexed-db-storage/indexed-db-storage.d.ts +0 -12
- package/dist/storage/indexed-db-storage/indexed-db-storage.d.ts.map +0 -1
- package/dist/storage/indexed-db-storage/lfu-indexed-db-storage.d.ts +0 -11
- package/dist/storage/indexed-db-storage/lfu-indexed-db-storage.d.ts.map +0 -1
- package/dist/storage/indexed-db-storage/lru-indexed-db-storage.d.ts +0 -11
- package/dist/storage/indexed-db-storage/lru-indexed-db-storage.d.ts.map +0 -1
- package/dist/storage/indexed-db-storage/random-indexed-db-storage.d.ts +0 -11
- package/dist/storage/indexed-db-storage/random-indexed-db-storage.d.ts.map +0 -1
- package/dist/storage/indexed-db-storage/ttl-indexed-db-storage.d.ts +0 -11
- package/dist/storage/indexed-db-storage/ttl-indexed-db-storage.d.ts.map +0 -1
- package/dist/storage/indexed-db-storage/types/index.d.ts +0 -7
- package/dist/storage/indexed-db-storage/types/index.d.ts.map +0 -1
- package/dist/storage/indexed-db-storage/types/indexed-db-entry-metadata.d.ts +0 -12
- package/dist/storage/indexed-db-storage/types/indexed-db-entry-metadata.d.ts.map +0 -1
- package/dist/storage/indexed-db-storage/types/indexed-db-entry-response.d.ts +0 -8
- package/dist/storage/indexed-db-storage/types/indexed-db-entry-response.d.ts.map +0 -1
- package/dist/storage/indexed-db-storage/types/indexed-db-entry-visits.d.ts +0 -14
- package/dist/storage/indexed-db-storage/types/indexed-db-entry-visits.d.ts.map +0 -1
- package/dist/storage/indexed-db-storage/types/indexed-db-schema.d.ts +0 -29
- package/dist/storage/indexed-db-storage/types/indexed-db-schema.d.ts.map +0 -1
- package/dist/storage/indexed-db-storage/types/indexed-db-storage-options.d.ts +0 -14
- package/dist/storage/indexed-db-storage/types/indexed-db-storage-options.d.ts.map +0 -1
- package/dist/storage/indexed-db-storage/types/indexed-db-storage-size.d.ts +0 -13
- package/dist/storage/indexed-db-storage/types/indexed-db-storage-size.d.ts.map +0 -1
- package/dist/storage/internal-storage/internal-storage.d.ts +0 -16
- package/dist/storage/internal-storage/internal-storage.d.ts.map +0 -1
- package/dist/storage/internal-storage/types/events.d.ts +0 -16
- package/dist/storage/internal-storage/types/events.d.ts.map +0 -1
- package/dist/storage/internal-storage/types/storage-options.d.ts +0 -20
- package/dist/storage/internal-storage/types/storage-options.d.ts.map +0 -1
- package/dist/storage/keq-cache-storage.d.ts +0 -20
- package/dist/storage/keq-cache-storage.d.ts.map +0 -1
- package/dist/storage/memory-storage/base-memory-storage.d.ts +0 -31
- package/dist/storage/memory-storage/base-memory-storage.d.ts.map +0 -1
- package/dist/storage/memory-storage/index.d.ts +0 -3
- package/dist/storage/memory-storage/index.d.ts.map +0 -1
- package/dist/storage/memory-storage/lfu-memory-storage.d.ts +0 -11
- package/dist/storage/memory-storage/lfu-memory-storage.d.ts.map +0 -1
- package/dist/storage/memory-storage/lru-memory-storage.d.ts +0 -11
- package/dist/storage/memory-storage/lru-memory-storage.d.ts.map +0 -1
- package/dist/storage/memory-storage/memory-storage.d.ts +0 -13
- package/dist/storage/memory-storage/memory-storage.d.ts.map +0 -1
- package/dist/storage/memory-storage/random-memory-storage.d.ts +0 -11
- package/dist/storage/memory-storage/random-memory-storage.d.ts.map +0 -1
- package/dist/storage/memory-storage/ttl-memory-storage.d.ts +0 -11
- package/dist/storage/memory-storage/ttl-memory-storage.d.ts.map +0 -1
- package/dist/storage/memory-storage/types/index.d.ts +0 -3
- package/dist/storage/memory-storage/types/index.d.ts.map +0 -1
- package/dist/storage/memory-storage/types/memory-storage-options.d.ts +0 -9
- package/dist/storage/memory-storage/types/memory-storage-options.d.ts.map +0 -1
- package/dist/storage/memory-storage/types/memory-storage-size.d.ts +0 -13
- package/dist/storage/memory-storage/types/memory-storage-size.d.ts.map +0 -1
- package/dist/storage/memory-storage/utils/humanize-size.d.ts +0 -6
- package/dist/storage/memory-storage/utils/humanize-size.d.ts.map +0 -1
- package/dist/storage/memory-storage/utils/index.d.ts +0 -3
- package/dist/storage/memory-storage/utils/index.d.ts.map +0 -1
- package/dist/storage/memory-storage/utils/serialize-response-body.d.ts +0 -6
- package/dist/storage/memory-storage/utils/serialize-response-body.d.ts.map +0 -1
- package/dist/storage/multi-tier-storage/index.d.ts +0 -3
- package/dist/storage/multi-tier-storage/index.d.ts.map +0 -1
- package/dist/storage/multi-tier-storage/multi-tier-storage.d.ts +0 -36
- package/dist/storage/multi-tier-storage/multi-tier-storage.d.ts.map +0 -1
- package/dist/storage/multi-tier-storage/types/index.d.ts +0 -2
- package/dist/storage/multi-tier-storage/types/index.d.ts.map +0 -1
- package/dist/storage/multi-tier-storage/types/multi-tier-storage-options.d.ts +0 -5
- package/dist/storage/multi-tier-storage/types/multi-tier-storage-options.d.ts.map +0 -1
- package/dist/storage/tier-storage/index.d.ts +0 -3
- package/dist/storage/tier-storage/index.d.ts.map +0 -1
- package/dist/storage/tier-storage/tier-storage.d.ts +0 -15
- package/dist/storage/tier-storage/tier-storage.d.ts.map +0 -1
- package/dist/storage/tier-storage/types/index.d.ts +0 -2
- package/dist/storage/tier-storage/types/index.d.ts.map +0 -1
- package/dist/storage/tier-storage/types/tier-storage-options.d.ts +0 -21
- package/dist/storage/tier-storage/types/tier-storage-options.d.ts.map +0 -1
- package/dist/strategies/cache-first.d.ts +0 -3
- package/dist/strategies/cache-first.d.ts.map +0 -1
- package/dist/strategies/index.d.ts +0 -5
- package/dist/strategies/index.d.ts.map +0 -1
- package/dist/strategies/network-first.d.ts +0 -3
- package/dist/strategies/network-first.d.ts.map +0 -1
- package/dist/strategies/network-only.d.ts +0 -3
- package/dist/strategies/network-only.d.ts.map +0 -1
- package/dist/strategies/stale-while-revalidate.d.ts +0 -3
- package/dist/strategies/stale-while-revalidate.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -6
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/keq-cache-key.d.ts +0 -4
- package/dist/types/keq-cache-key.d.ts.map +0 -1
- package/dist/types/keq-cache-pattern.d.ts +0 -3
- package/dist/types/keq-cache-pattern.d.ts.map +0 -1
- package/dist/types/keq-cache-rule.d.ts +0 -6
- package/dist/types/keq-cache-rule.d.ts.map +0 -1
- package/dist/types/keq-cache-strategy.d.ts +0 -6
- package/dist/types/keq-cache-strategy.d.ts.map +0 -1
- package/dist/types/request-cache-options.d.ts +0 -45
- package/dist/types/request-cache-options.d.ts.map +0 -1
- package/dist/utils/get-response-bytes.d.ts +0 -2
- package/dist/utils/get-response-bytes.d.ts.map +0 -1
- package/dist/utils/index.d.ts +0 -4
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/logger.d.ts +0 -5
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/random.d.ts +0 -2
- package/dist/utils/random.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,1336 +1,1271 @@
|
|
|
1
|
-
"
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
2
3
|
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
-
var __export = (target, all) => {
|
|
10
|
-
for (var name in all)
|
|
11
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
-
};
|
|
13
9
|
var __copyProps = (to, from, except, desc) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
20
18
|
};
|
|
21
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
MultiTierStorage: () => MultiTierStorage,
|
|
40
|
-
Size: () => Size,
|
|
41
|
-
Strategy: () => Strategy,
|
|
42
|
-
TierStorage: () => TierStorage,
|
|
43
|
-
cache: () => cache
|
|
44
|
-
});
|
|
45
|
-
module.exports = __toCommonJS(index_exports);
|
|
46
|
-
|
|
47
|
-
// src/cache.ts
|
|
48
|
-
var R2 = __toESM(require("ramda"));
|
|
49
|
-
var fastq = __toESM(require("fastq"));
|
|
50
|
-
|
|
51
|
-
// src/request-cache-handler/request-cache-handler.ts
|
|
52
|
-
var R = __toESM(require("ramda"));
|
|
53
|
-
|
|
54
|
-
// src/exceptions/cache-exception.ts
|
|
55
|
-
var import_keq = require("keq");
|
|
56
|
-
var CacheException = class extends import_keq.Exception {
|
|
57
|
-
constructor(message) {
|
|
58
|
-
super("[@keq-request/cache] ".concat(message));
|
|
59
|
-
}
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
+
value: mod,
|
|
21
|
+
enumerable: true
|
|
22
|
+
}) : target, mod));
|
|
23
|
+
//#endregion
|
|
24
|
+
let ramda = require("ramda");
|
|
25
|
+
ramda = __toESM(ramda);
|
|
26
|
+
let fastq = require("fastq");
|
|
27
|
+
fastq = __toESM(fastq);
|
|
28
|
+
let keq = require("keq");
|
|
29
|
+
let dayjs = require("dayjs");
|
|
30
|
+
dayjs = __toESM(dayjs);
|
|
31
|
+
let idb = require("idb");
|
|
32
|
+
//#region src/exceptions/cache-exception.ts
|
|
33
|
+
var CacheException = class extends keq.Exception {
|
|
34
|
+
constructor(message) {
|
|
35
|
+
super(`[@keq-request/cache] ${message}`);
|
|
36
|
+
}
|
|
60
37
|
};
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
var import_keq2 = require("keq");
|
|
64
|
-
|
|
65
|
-
// src/utils/get-response-bytes.ts
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/utils/get-response-bytes.ts
|
|
66
40
|
async function getResponseBytes(response) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
const arrayBuffer = await response.clone().arrayBuffer();
|
|
72
|
-
return arrayBuffer.byteLength;
|
|
41
|
+
const contentLength = response.headers.get("content-length");
|
|
42
|
+
if (contentLength) return parseInt(contentLength);
|
|
43
|
+
return (await response.clone().arrayBuffer()).byteLength;
|
|
73
44
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region src/constants/max-expired-at.ts
|
|
47
|
+
const MAX_EXPIRED_AT = /* @__PURE__ */ new Date(864e13);
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/constants/eviction.enum.ts
|
|
50
|
+
let Eviction = /* @__PURE__ */ function(Eviction) {
|
|
51
|
+
Eviction["LRU"] = "lru";
|
|
52
|
+
Eviction["LFU"] = "lfu";
|
|
53
|
+
Eviction["RANDOM"] = "random";
|
|
54
|
+
Eviction["TTL"] = "ttl";
|
|
55
|
+
return Eviction;
|
|
56
|
+
}({});
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/constants/size.enum.ts
|
|
59
|
+
let Size = /* @__PURE__ */ function(Size) {
|
|
60
|
+
Size[Size["B"] = 1] = "B";
|
|
61
|
+
Size[Size["KB"] = 1024] = "KB";
|
|
62
|
+
Size[Size["MB"] = 1048576] = "MB";
|
|
63
|
+
Size[Size["GB"] = 1073741824] = "GB";
|
|
64
|
+
return Size;
|
|
65
|
+
}({});
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/utils/logger.ts
|
|
97
68
|
var Logger = class {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
69
|
+
static debug(...args) {
|
|
70
|
+
console.debug("[@keq-request/cache] [DEBUG] ", ...args);
|
|
71
|
+
}
|
|
72
|
+
static error(...args) {
|
|
73
|
+
console.error("[@keq-request/cache] [ERROR] ", ...args);
|
|
74
|
+
}
|
|
104
75
|
};
|
|
105
|
-
|
|
106
|
-
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/utils/random.ts
|
|
107
78
|
function random(min, max) {
|
|
108
|
-
|
|
79
|
+
return Math.floor(Math.random() * (max - min)) + min;
|
|
109
80
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/strategies/cache-first.ts
|
|
83
|
+
const cacheFirst = async function cacheFirst(handler, context, next) {
|
|
84
|
+
const [cacheKey, cacheValue] = await handler.getCache();
|
|
85
|
+
if (handler.options.debug) Logger.debug([
|
|
86
|
+
"",
|
|
87
|
+
`Request: ${context.request.method.toUpperCase()} ${context.request.__url__.href}`,
|
|
88
|
+
"Strategy: Cache First",
|
|
89
|
+
`Cache Key: ${cacheKey}`,
|
|
90
|
+
`Cache Status: ${cacheValue ? "HIT" : "MISS"}`
|
|
91
|
+
].join("\n"));
|
|
92
|
+
if (cacheValue) {
|
|
93
|
+
context.emitter.emit("cache:hit", {
|
|
94
|
+
key: cacheKey,
|
|
95
|
+
response: cacheValue.response,
|
|
96
|
+
context
|
|
97
|
+
});
|
|
98
|
+
context.res = cacheValue.response;
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
context.emitter.emit("cache:miss", {
|
|
102
|
+
key: cacheKey,
|
|
103
|
+
context
|
|
104
|
+
});
|
|
105
|
+
await next();
|
|
106
|
+
const [, entry] = await handler.setCache(context);
|
|
107
|
+
if (handler.options.debug) Logger.debug([
|
|
108
|
+
"",
|
|
109
|
+
`Request: ${context.request.method.toUpperCase()} ${context.request.__url__.href}`,
|
|
110
|
+
"Strategy: Cache First",
|
|
111
|
+
`Cache Key: ${cacheKey}`,
|
|
112
|
+
`ACTIONS: ${entry ? "UPDATED" : "EXCLUDED"}`
|
|
113
|
+
].join("\n"));
|
|
114
|
+
if (entry) context.emitter.emit("cache:update", {
|
|
115
|
+
key: entry.key,
|
|
116
|
+
oldResponse: void 0,
|
|
117
|
+
newResponse: entry.response,
|
|
118
|
+
context
|
|
119
|
+
});
|
|
148
120
|
};
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/strategies/network-first.ts
|
|
123
|
+
const networkFirst = async function networkFirst(handler, context, next) {
|
|
124
|
+
try {
|
|
125
|
+
await next();
|
|
126
|
+
const [cacheKey, cache] = await handler.getCache();
|
|
127
|
+
const [, entry] = await handler.setCache(context);
|
|
128
|
+
if (handler.options.debug) Logger.debug([
|
|
129
|
+
"",
|
|
130
|
+
`Request: ${context.request.method.toUpperCase()} ${context.request.__url__.href}`,
|
|
131
|
+
"Strategy: Network First",
|
|
132
|
+
`Cache Key: ${cacheKey}`,
|
|
133
|
+
`ACTIONS: ${entry ? "UPDATED" : "EXCLUDED"}`
|
|
134
|
+
].join("\n"));
|
|
135
|
+
if (entry) context.emitter.emit("cache:update", {
|
|
136
|
+
key: entry.key,
|
|
137
|
+
oldResponse: cache?.response,
|
|
138
|
+
newResponse: entry.response,
|
|
139
|
+
context
|
|
140
|
+
});
|
|
141
|
+
} catch (err) {
|
|
142
|
+
const [cacheKey, cache] = await handler.getCache();
|
|
143
|
+
if (handler.options.debug) Logger.debug([
|
|
144
|
+
"",
|
|
145
|
+
`Request: ${context.request.method.toUpperCase()} ${context.request.__url__.href}`,
|
|
146
|
+
"Strategy: Network First",
|
|
147
|
+
`Cache Key: ${cacheKey}`,
|
|
148
|
+
`Cache Status: ${cache ? "HIT" : "MISS"}`
|
|
149
|
+
].join("\n"));
|
|
150
|
+
if (!cache) {
|
|
151
|
+
context.emitter.emit("cache:miss", {
|
|
152
|
+
key: cacheKey,
|
|
153
|
+
context
|
|
154
|
+
});
|
|
155
|
+
throw err;
|
|
156
|
+
}
|
|
157
|
+
context.emitter.emit("cache:hit", {
|
|
158
|
+
key: cacheKey,
|
|
159
|
+
response: cache.response,
|
|
160
|
+
context
|
|
161
|
+
});
|
|
162
|
+
context.res = cache.response;
|
|
163
|
+
}
|
|
191
164
|
};
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
165
|
+
//#endregion
|
|
166
|
+
//#region src/strategies/network-only.ts
|
|
167
|
+
const networkOnly = async function(handler, context, next) {
|
|
168
|
+
await next();
|
|
196
169
|
};
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
key: cacheKey2,
|
|
258
|
-
oldResponse: void 0,
|
|
259
|
-
newResponse: entry.response,
|
|
260
|
-
context
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
}
|
|
170
|
+
//#endregion
|
|
171
|
+
//#region src/strategies/stale-while-revalidate.ts
|
|
172
|
+
const staleWhileRevalidate = async function(handler, context, next) {
|
|
173
|
+
const [cacheKey, cache] = await handler.getCache();
|
|
174
|
+
if (handler.options.debug) Logger.debug([
|
|
175
|
+
"",
|
|
176
|
+
`Request: ${context.request.method.toUpperCase()} ${context.request.__url__.href}`,
|
|
177
|
+
"Strategy: Stale While Revalidate",
|
|
178
|
+
`Cache Key: ${cacheKey}`,
|
|
179
|
+
`Cache Status: ${cache ? "HIT" : "MISS"}`
|
|
180
|
+
].join("\n"));
|
|
181
|
+
if (cache) context.emitter.emit("cache:hit", {
|
|
182
|
+
key: cacheKey,
|
|
183
|
+
response: cache.response,
|
|
184
|
+
context
|
|
185
|
+
});
|
|
186
|
+
else context.emitter.emit("cache:miss", {
|
|
187
|
+
key: cacheKey,
|
|
188
|
+
context
|
|
189
|
+
});
|
|
190
|
+
if (cache) {
|
|
191
|
+
const orchestrator = context.orchestration.fork();
|
|
192
|
+
context.res = cache.response;
|
|
193
|
+
setTimeout(async () => {
|
|
194
|
+
try {
|
|
195
|
+
await orchestrator.execute();
|
|
196
|
+
const context = orchestrator.context;
|
|
197
|
+
const [cacheKey, entry] = await handler.setCache(context);
|
|
198
|
+
if (handler.options.debug) Logger.debug([
|
|
199
|
+
"",
|
|
200
|
+
`Request: ${context.request.method.toUpperCase()} ${context.request.__url__.href}`,
|
|
201
|
+
"Strategy: Stale While Revalidate",
|
|
202
|
+
`Cache Key: ${cacheKey}`,
|
|
203
|
+
`ACTIONS: ${entry ? "UPDATED" : "EXCLUDED"}`
|
|
204
|
+
].join("\n"));
|
|
205
|
+
if (entry) context.emitter.emit("cache:update", {
|
|
206
|
+
key: cacheKey,
|
|
207
|
+
oldResponse: cache.response,
|
|
208
|
+
newResponse: entry.response,
|
|
209
|
+
context
|
|
210
|
+
});
|
|
211
|
+
} catch (err) {}
|
|
212
|
+
}, 1);
|
|
213
|
+
} else {
|
|
214
|
+
await next();
|
|
215
|
+
const [cacheKey, entry] = await handler.setCache(context);
|
|
216
|
+
if (handler.options.debug) Logger.debug([
|
|
217
|
+
"",
|
|
218
|
+
`Request: ${context.request.method.toUpperCase()} ${context.request.__url__.href}`,
|
|
219
|
+
"Strategy: Stale While Revalidate",
|
|
220
|
+
`Cache Key: ${cacheKey}`,
|
|
221
|
+
`ACTIONS: ${entry ? "UPDATED" : "EXCLUDED"}`
|
|
222
|
+
].join("\n"));
|
|
223
|
+
if (entry) context.emitter.emit("cache:update", {
|
|
224
|
+
key: cacheKey,
|
|
225
|
+
oldResponse: void 0,
|
|
226
|
+
newResponse: entry.response,
|
|
227
|
+
context
|
|
228
|
+
});
|
|
229
|
+
}
|
|
264
230
|
};
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region src/constants/strategy.enum.ts
|
|
233
|
+
const Strategy = {
|
|
234
|
+
STALE_WHILE_REVALIDATE: staleWhileRevalidate,
|
|
235
|
+
NETWORK_FIRST: networkFirst,
|
|
236
|
+
NETWORK_ONLY: networkOnly,
|
|
237
|
+
CACHE_FIRST: cacheFirst
|
|
272
238
|
};
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region \0@oxc-project+runtime@0.127.0/helpers/typeof.js
|
|
241
|
+
function _typeof(o) {
|
|
242
|
+
"@babel/helpers - typeof";
|
|
243
|
+
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
244
|
+
return typeof o;
|
|
245
|
+
} : function(o) {
|
|
246
|
+
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
|
247
|
+
}, _typeof(o);
|
|
248
|
+
}
|
|
249
|
+
//#endregion
|
|
250
|
+
//#region \0@oxc-project+runtime@0.127.0/helpers/toPrimitive.js
|
|
251
|
+
function toPrimitive(t, r) {
|
|
252
|
+
if ("object" != _typeof(t) || !t) return t;
|
|
253
|
+
var e = t[Symbol.toPrimitive];
|
|
254
|
+
if (void 0 !== e) {
|
|
255
|
+
var i = e.call(t, r || "default");
|
|
256
|
+
if ("object" != _typeof(i)) return i;
|
|
257
|
+
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
258
|
+
}
|
|
259
|
+
return ("string" === r ? String : Number)(t);
|
|
260
|
+
}
|
|
261
|
+
//#endregion
|
|
262
|
+
//#region \0@oxc-project+runtime@0.127.0/helpers/toPropertyKey.js
|
|
263
|
+
function toPropertyKey(t) {
|
|
264
|
+
var i = toPrimitive(t, "string");
|
|
265
|
+
return "symbol" == _typeof(i) ? i : i + "";
|
|
266
|
+
}
|
|
267
|
+
//#endregion
|
|
268
|
+
//#region \0@oxc-project+runtime@0.127.0/helpers/defineProperty.js
|
|
269
|
+
function _defineProperty(e, r, t) {
|
|
270
|
+
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
271
|
+
value: t,
|
|
272
|
+
enumerable: !0,
|
|
273
|
+
configurable: !0,
|
|
274
|
+
writable: !0
|
|
275
|
+
}) : e[r] = t, e;
|
|
276
|
+
}
|
|
277
|
+
//#endregion
|
|
278
|
+
//#region src/cache-entry/cache-entry.ts
|
|
279
|
+
var CacheEntry = class CacheEntry {
|
|
280
|
+
constructor(options) {
|
|
281
|
+
_defineProperty(this, "key", void 0);
|
|
282
|
+
_defineProperty(this, "response", void 0);
|
|
283
|
+
_defineProperty(
|
|
284
|
+
this,
|
|
285
|
+
/**
|
|
286
|
+
* @en bytes
|
|
287
|
+
* @zh 字节数
|
|
288
|
+
*/
|
|
289
|
+
"size",
|
|
290
|
+
void 0
|
|
291
|
+
);
|
|
292
|
+
_defineProperty(this, "expiredAt", void 0);
|
|
293
|
+
this.key = options.key;
|
|
294
|
+
this.response = (0, keq.createProxyResponse)(options.response);
|
|
295
|
+
this.size = options.size;
|
|
296
|
+
this.expiredAt = options.expiredAt ?? MAX_EXPIRED_AT;
|
|
297
|
+
}
|
|
298
|
+
static async build(options) {
|
|
299
|
+
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;
|
|
300
|
+
const response = options.response.clone();
|
|
301
|
+
return new CacheEntry({
|
|
302
|
+
key: options.key,
|
|
303
|
+
response,
|
|
304
|
+
size: options.size ?? await getResponseBytes(response),
|
|
305
|
+
expiredAt
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
clone() {
|
|
309
|
+
return new CacheEntry({
|
|
310
|
+
key: this.key,
|
|
311
|
+
response: this.response.clone(),
|
|
312
|
+
size: this.size,
|
|
313
|
+
expiredAt: this.expiredAt
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
assignResponseHeaders(headers) {
|
|
317
|
+
this.response = new Response(this.response.body, {
|
|
318
|
+
status: this.response.status,
|
|
319
|
+
statusText: this.response.statusText,
|
|
320
|
+
headers
|
|
321
|
+
});
|
|
322
|
+
}
|
|
317
323
|
};
|
|
318
|
-
|
|
319
|
-
|
|
324
|
+
//#endregion
|
|
325
|
+
//#region src/request-cache-handler/request-cache-handler.ts
|
|
320
326
|
var RequestCacheHandler = class {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
327
|
+
constructor(cacheKey, storage, options) {
|
|
328
|
+
this.cacheKey = cacheKey;
|
|
329
|
+
this.storage = storage;
|
|
330
|
+
this.options = options;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Resolve cache key for request context
|
|
334
|
+
*/
|
|
335
|
+
static resolveRequestCacheKey(context, options) {
|
|
336
|
+
if (typeof options.key === "string") return options.key;
|
|
337
|
+
else if (typeof options.key === "function") return options.key(context);
|
|
338
|
+
else if (ramda.isNil(options.key) && context.locationId) return context.locationId;
|
|
339
|
+
else throw new CacheException("Cannot resolve cache key");
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Get cache from storage
|
|
343
|
+
*/
|
|
344
|
+
async getCache() {
|
|
345
|
+
const key = this.cacheKey;
|
|
346
|
+
if (this.options.serverTiming) {
|
|
347
|
+
const startAt = /* @__PURE__ */ new Date();
|
|
348
|
+
const entry = await this.storage.get(key);
|
|
349
|
+
if (entry) {
|
|
350
|
+
const dur = (/* @__PURE__ */ new Date()).getTime() - startAt.getTime();
|
|
351
|
+
const HeadersWithServerTiming = new Headers(entry.response.headers);
|
|
352
|
+
HeadersWithServerTiming.set("Server-Timing", `keq-cache; dur=${dur}; desc="HIT"`);
|
|
353
|
+
entry.assignResponseHeaders(HeadersWithServerTiming);
|
|
354
|
+
}
|
|
355
|
+
return [key, entry];
|
|
356
|
+
}
|
|
357
|
+
return [key, await this.storage.get(key)];
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Store response that in context to storage
|
|
361
|
+
*/
|
|
362
|
+
async setCache(context) {
|
|
363
|
+
const options = this.options;
|
|
364
|
+
const key = this.cacheKey;
|
|
365
|
+
if (!context.response) return [key, void 0];
|
|
366
|
+
if (options.exclude && await options.exclude(context.response)) return [key, void 0];
|
|
367
|
+
const entry = await CacheEntry.build({
|
|
368
|
+
key,
|
|
369
|
+
response: context.response,
|
|
370
|
+
ttl: options.ttl
|
|
371
|
+
});
|
|
372
|
+
this.storage.set(entry);
|
|
373
|
+
return [key, entry];
|
|
374
|
+
}
|
|
369
375
|
};
|
|
370
|
-
|
|
371
|
-
|
|
376
|
+
//#endregion
|
|
377
|
+
//#region src/cache.ts
|
|
372
378
|
function cache(options) {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
const queue = ctx.global.core.cache[cacheKey];
|
|
414
|
-
await queue.push({
|
|
415
|
-
next: async () => {
|
|
416
|
-
await strategy(handler, ctx, next);
|
|
417
|
-
}
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
};
|
|
379
|
+
const storage = options.storage;
|
|
380
|
+
const rules = options?.rules || [];
|
|
381
|
+
return async function cache(ctx, next) {
|
|
382
|
+
if (ctx.options.cache === false) {
|
|
383
|
+
await next();
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
let requestCacheOptions = ctx.options.cache;
|
|
387
|
+
const rule = rules.find((rule) => {
|
|
388
|
+
if (rule.pattern === void 0 || rule.pattern === true) return true;
|
|
389
|
+
if (typeof rule.pattern === "function") return rule.pattern(ctx);
|
|
390
|
+
return rule.pattern.test(ctx.request.__url__.href);
|
|
391
|
+
});
|
|
392
|
+
if (rule) requestCacheOptions = ramda.mergeRight(rule, requestCacheOptions || {});
|
|
393
|
+
if (!requestCacheOptions || ramda.isEmpty(requestCacheOptions)) {
|
|
394
|
+
await next();
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
if (!requestCacheOptions.key) requestCacheOptions.key = options.keyFactory;
|
|
398
|
+
if (!ctx.locationId && !requestCacheOptions.key) {
|
|
399
|
+
console.warn("[@keq/cache] Warning: Cannot resolve Cache Key. Cache is skipped.");
|
|
400
|
+
await next();
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
if (requestCacheOptions.serverTiming === void 0 && options.serverTiming !== void 0) requestCacheOptions.serverTiming = options.serverTiming;
|
|
404
|
+
const cacheKey = RequestCacheHandler.resolveRequestCacheKey(ctx, requestCacheOptions);
|
|
405
|
+
const handler = new RequestCacheHandler(cacheKey, storage, requestCacheOptions);
|
|
406
|
+
const strategy = requestCacheOptions.strategy;
|
|
407
|
+
if (requestCacheOptions.concurrent) await strategy(handler, ctx, next);
|
|
408
|
+
else {
|
|
409
|
+
if (!ctx.global.core) ctx.global.core = {};
|
|
410
|
+
if (!ctx.global.core.cache) ctx.global.core.cache = {};
|
|
411
|
+
if (!ctx.global.core.cache[cacheKey]) ctx.global.core.cache[cacheKey] = fastq.promise(async ({ next }) => {
|
|
412
|
+
await next();
|
|
413
|
+
}, 1);
|
|
414
|
+
await ctx.global.core.cache[cacheKey].push({ next: async () => {
|
|
415
|
+
await strategy(handler, ctx, next);
|
|
416
|
+
} });
|
|
417
|
+
}
|
|
418
|
+
};
|
|
421
419
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
var
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
// src/storage/memory-storage/base-memory-storage.ts
|
|
428
|
-
var import_dayjs = __toESM(require("dayjs"));
|
|
429
|
-
var R3 = __toESM(require("ramda"));
|
|
430
|
-
|
|
431
|
-
// src/storage/keq-cache-storage.ts
|
|
432
|
-
var KeqCacheStorage = class {
|
|
433
|
-
};
|
|
434
|
-
|
|
435
|
-
// src/storage/internal-storage/internal-storage.ts
|
|
420
|
+
//#endregion
|
|
421
|
+
//#region src/storage/keq-cache-storage.ts
|
|
422
|
+
var KeqCacheStorage = class {};
|
|
423
|
+
//#endregion
|
|
424
|
+
//#region src/storage/internal-storage/internal-storage.ts
|
|
436
425
|
var InternalStorage = class extends KeqCacheStorage {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
fn((...args) => {
|
|
462
|
-
Logger.debug("[Storage(".concat(this.__id__, ")]"), ...args);
|
|
463
|
-
});
|
|
464
|
-
}
|
|
465
|
-
}
|
|
426
|
+
constructor(options) {
|
|
427
|
+
super();
|
|
428
|
+
_defineProperty(this, "__id__", Math.random().toString(36).slice(2));
|
|
429
|
+
_defineProperty(this, "__size__", void 0);
|
|
430
|
+
_defineProperty(this, "__debug__", void 0);
|
|
431
|
+
_defineProperty(this, "__onCacheGet__", void 0);
|
|
432
|
+
_defineProperty(this, "__onCacheSet__", void 0);
|
|
433
|
+
_defineProperty(this, "__onCacheRemove__", void 0);
|
|
434
|
+
_defineProperty(this, "__onCacheEvict__", void 0);
|
|
435
|
+
_defineProperty(this, "__onCacheExpired__", void 0);
|
|
436
|
+
if (options?.size && (typeof options?.size !== "number" || options.size <= 0)) throw new CacheException(`Invalid size: ${String(options?.size)}`);
|
|
437
|
+
this.__size__ = options?.size ?? Infinity;
|
|
438
|
+
this.__debug__ = !!options?.debug;
|
|
439
|
+
this.__onCacheGet__ = options?.onCacheGet;
|
|
440
|
+
this.__onCacheSet__ = options?.onCacheSet;
|
|
441
|
+
this.__onCacheRemove__ = options?.onCacheRemove;
|
|
442
|
+
this.__onCacheEvict__ = options?.onCacheEvict;
|
|
443
|
+
this.debug((log) => log("Storage Created: ", this));
|
|
444
|
+
}
|
|
445
|
+
debug(fn) {
|
|
446
|
+
if (this.__debug__) fn((...args) => {
|
|
447
|
+
Logger.debug(`[Storage(${this.__id__})]`, ...args);
|
|
448
|
+
});
|
|
449
|
+
}
|
|
466
450
|
};
|
|
467
|
-
|
|
468
|
-
|
|
451
|
+
//#endregion
|
|
452
|
+
//#region src/storage/memory-storage/utils/humanize-size.ts
|
|
453
|
+
/**
|
|
454
|
+
* @en Humanize size in bytes to KB, MB, GB
|
|
455
|
+
* @zh 将字节数转换为 KB、MB、GB 等易读格式
|
|
456
|
+
*/
|
|
469
457
|
function humanizeSize(size) {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
458
|
+
if (size < 1024) return `${size} B`;
|
|
459
|
+
if (size < 1024 * 1024) return `${(size / 1024).toFixed(2)} KB`;
|
|
460
|
+
if (size < 1024 * 1024 * 1024) return `${(size / (1024 * 1024)).toFixed(2)} MB`;
|
|
461
|
+
return `${(size / (1024 * 1024 * 1024)).toFixed(2)} GB`;
|
|
474
462
|
}
|
|
475
|
-
|
|
476
|
-
|
|
463
|
+
//#endregion
|
|
464
|
+
//#region src/storage/memory-storage/utils/serialize-response-body.ts
|
|
465
|
+
/**
|
|
466
|
+
* @en Serialize the response body based on content-type
|
|
467
|
+
* @zh 根据 content-type 序列化响应体
|
|
468
|
+
*/
|
|
477
469
|
async function serializeResponseBody(response) {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
} catch {
|
|
490
|
-
return "[Unable to serialize]";
|
|
491
|
-
}
|
|
470
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
471
|
+
try {
|
|
472
|
+
if (contentType.includes("application/json")) {
|
|
473
|
+
const json = await response.json();
|
|
474
|
+
return JSON.stringify(json);
|
|
475
|
+
}
|
|
476
|
+
if (contentType.includes("text/") || contentType.includes("application/xml") || contentType.includes("application/javascript")) return await response.text();
|
|
477
|
+
return "[Binary or unsupported content]";
|
|
478
|
+
} catch {
|
|
479
|
+
return "[Unable to serialize]";
|
|
480
|
+
}
|
|
492
481
|
}
|
|
493
|
-
|
|
494
|
-
|
|
482
|
+
//#endregion
|
|
483
|
+
//#region src/storage/memory-storage/base-memory-storage.ts
|
|
495
484
|
var BaseMemoryStorage = class extends InternalStorage {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
size: humanizeSize(entry.size),
|
|
590
|
-
"Expired Time": entry.expiredAt.getTime() >= MAX_EXPIRED_AT.getTime() ? "-" : entry.expiredAt.toISOString(),
|
|
591
|
-
"Visit Count": (_a = this.visitCountRecords.get(key)) != null ? _a : 0,
|
|
592
|
-
"Last Visit Time": (_c = (_b = this.visitTimeRecords.get(key)) == null ? void 0 : _b.toISOString()) != null ? _c : "-",
|
|
593
|
-
"Response Status": entry.response.status,
|
|
594
|
-
"Response URL": entry.response.url,
|
|
595
|
-
"Response Body": body
|
|
596
|
-
};
|
|
597
|
-
})
|
|
598
|
-
);
|
|
599
|
-
console.table(entries);
|
|
600
|
-
}
|
|
485
|
+
constructor(..._args) {
|
|
486
|
+
super(..._args);
|
|
487
|
+
_defineProperty(this, "storage", /* @__PURE__ */ new Map());
|
|
488
|
+
_defineProperty(this, "visitTimeRecords", /* @__PURE__ */ new Map());
|
|
489
|
+
_defineProperty(this, "visitCountRecords", /* @__PURE__ */ new Map());
|
|
490
|
+
_defineProperty(this, "lastEvictExpiredTime", (0, dayjs.default)());
|
|
491
|
+
}
|
|
492
|
+
get size() {
|
|
493
|
+
const used = ramda.sum(ramda.pluck("size", [...this.storage.values()]));
|
|
494
|
+
return {
|
|
495
|
+
used,
|
|
496
|
+
free: this.__size__ > used ? this.__size__ - used : 0
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
get(key) {
|
|
500
|
+
this.evictExpired();
|
|
501
|
+
const entry = this.storage.get(key);
|
|
502
|
+
this.visitCountRecords.set(key, (this.visitCountRecords.get(key) ?? 0) + 1);
|
|
503
|
+
this.visitTimeRecords.set(key, /* @__PURE__ */ new Date());
|
|
504
|
+
if (!entry) this.debug((log) => log(`Entry(${key}) Not Found`));
|
|
505
|
+
else this.debug((log) => log(`Entry(${key}) Found: `, entry));
|
|
506
|
+
return entry?.clone();
|
|
507
|
+
}
|
|
508
|
+
set(value) {
|
|
509
|
+
if (!this.evict(value.size)) {
|
|
510
|
+
this.debug((log) => log("Storage Size Not Enough: ", this.size.free, " < ", value.size));
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
this.storage.set(value.key, value);
|
|
514
|
+
this.visitTimeRecords.set(value.key, /* @__PURE__ */ new Date());
|
|
515
|
+
this.visitCountRecords.set(value.key, this.visitCountRecords.get(value.key) ?? 0);
|
|
516
|
+
this.debug((log) => log("Entry Added: ", value));
|
|
517
|
+
this.debug((log) => log("Storage Size: ", this.size));
|
|
518
|
+
}
|
|
519
|
+
__remove__(keys) {
|
|
520
|
+
for (const key of keys) {
|
|
521
|
+
const entry = this.storage.get(key);
|
|
522
|
+
if (!entry) return;
|
|
523
|
+
this.storage.delete(key);
|
|
524
|
+
this.visitCountRecords.delete(key);
|
|
525
|
+
this.visitTimeRecords.delete(key);
|
|
526
|
+
this.debug((log) => log("Entry Removed: ", entry));
|
|
527
|
+
this.debug((log) => log("Storage Size: ", this.size));
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
remove(key) {
|
|
531
|
+
this.__remove__([key]);
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* @zh 清除过期的缓存
|
|
535
|
+
*/
|
|
536
|
+
evictExpired() {
|
|
537
|
+
const now = (0, dayjs.default)();
|
|
538
|
+
if (now.diff(this.lastEvictExpiredTime, "second") < 1) return;
|
|
539
|
+
const keys = [];
|
|
540
|
+
for (const [key, entry] of this.storage.entries()) if (entry.expiredAt && now.isAfter(entry.expiredAt)) keys.push(key);
|
|
541
|
+
this.__remove__(keys);
|
|
542
|
+
this.__onCacheExpired__?.({ keys });
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* @en Evict the storage to make sure the size is enough
|
|
546
|
+
* @zh 清除缓存以确保有足够的空间
|
|
547
|
+
*
|
|
548
|
+
* @return {boolean} - is evicted successfully
|
|
549
|
+
*/
|
|
550
|
+
evict(expectSize) {
|
|
551
|
+
this.evictExpired();
|
|
552
|
+
return this.size.free >= expectSize;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* @en Print all cached data using console.table for debugging
|
|
556
|
+
* @zh 使用 console.table 打印所有缓存数据,用于调试
|
|
557
|
+
*/
|
|
558
|
+
async print() {
|
|
559
|
+
if (this.storage.size === 0) {
|
|
560
|
+
console.log("MemoryStorage is empty");
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
const entries = await Promise.all([...this.storage.entries()].map(async ([key, entry]) => {
|
|
564
|
+
const body = await serializeResponseBody(entry.response.clone());
|
|
565
|
+
return {
|
|
566
|
+
key,
|
|
567
|
+
size: humanizeSize(entry.size),
|
|
568
|
+
"Expired Time": entry.expiredAt.getTime() >= MAX_EXPIRED_AT.getTime() ? "-" : entry.expiredAt.toISOString(),
|
|
569
|
+
"Visit Count": this.visitCountRecords.get(key) ?? 0,
|
|
570
|
+
"Last Visit Time": this.visitTimeRecords.get(key)?.toISOString() ?? "-",
|
|
571
|
+
"Response Status": entry.response.status,
|
|
572
|
+
"Response URL": entry.response.url,
|
|
573
|
+
"Response Body": body
|
|
574
|
+
};
|
|
575
|
+
}));
|
|
576
|
+
console.table(entries);
|
|
577
|
+
}
|
|
601
578
|
};
|
|
602
|
-
|
|
603
|
-
|
|
579
|
+
//#endregion
|
|
580
|
+
//#region src/storage/memory-storage/ttl-memory-storage.ts
|
|
604
581
|
var TTLMemoryStorage = class extends BaseMemoryStorage {
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
this.__remove__(keys);
|
|
649
|
-
(_a = this.__onCacheEvict__) == null ? void 0 : _a.call(this, { keys });
|
|
650
|
-
return true;
|
|
651
|
-
}
|
|
582
|
+
constructor(options) {
|
|
583
|
+
super(options);
|
|
584
|
+
}
|
|
585
|
+
get(key) {
|
|
586
|
+
const entry = super.get(key);
|
|
587
|
+
this.__onCacheGet__?.({ key });
|
|
588
|
+
return entry;
|
|
589
|
+
}
|
|
590
|
+
set(value) {
|
|
591
|
+
super.set(value);
|
|
592
|
+
this.__onCacheSet__?.({ key: value.key });
|
|
593
|
+
}
|
|
594
|
+
remove(key) {
|
|
595
|
+
super.remove(key);
|
|
596
|
+
this.__onCacheRemove__?.({ key });
|
|
597
|
+
}
|
|
598
|
+
evict(expectSize) {
|
|
599
|
+
if (expectSize > this.__size__) {
|
|
600
|
+
this.debug((log) => log("Storage Size Not Enough: ", this.__size__, " < ", expectSize));
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
this.evictExpired();
|
|
604
|
+
let deficitSize = expectSize - this.size.free;
|
|
605
|
+
if (deficitSize <= 0) return true;
|
|
606
|
+
const entries = [...this.storage.values()].sort((a, b) => {
|
|
607
|
+
const aExpiredAt = (0, dayjs.default)(a.expiredAt);
|
|
608
|
+
const bExpiredAt = (0, dayjs.default)(b.expiredAt);
|
|
609
|
+
return aExpiredAt.isBefore(bExpiredAt) ? 1 : -1;
|
|
610
|
+
});
|
|
611
|
+
if (ramda.sum(ramda.pluck("size", entries)) < deficitSize) {
|
|
612
|
+
this.debug((log) => log("Storage Size Not Enough: ", this.size.free, " < ", deficitSize));
|
|
613
|
+
return false;
|
|
614
|
+
}
|
|
615
|
+
const keys = [];
|
|
616
|
+
while (deficitSize > 0 && entries.length) {
|
|
617
|
+
const entry = entries.pop();
|
|
618
|
+
deficitSize -= entry.size;
|
|
619
|
+
keys.push(entry.key);
|
|
620
|
+
}
|
|
621
|
+
this.__remove__(keys);
|
|
622
|
+
this.__onCacheEvict__?.({ keys });
|
|
623
|
+
return true;
|
|
624
|
+
}
|
|
652
625
|
};
|
|
653
|
-
|
|
654
|
-
|
|
626
|
+
//#endregion
|
|
627
|
+
//#region src/storage/memory-storage/random-memory-storage.ts
|
|
655
628
|
var RandomMemoryStorage = class extends BaseMemoryStorage {
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
this.__remove__(keys);
|
|
694
|
-
(_a = this.__onCacheEvict__) == null ? void 0 : _a.call(this, { keys });
|
|
695
|
-
return true;
|
|
696
|
-
}
|
|
629
|
+
constructor(options) {
|
|
630
|
+
super(options);
|
|
631
|
+
}
|
|
632
|
+
get(key) {
|
|
633
|
+
const entry = super.get(key);
|
|
634
|
+
this.__onCacheGet__?.({ key });
|
|
635
|
+
return entry;
|
|
636
|
+
}
|
|
637
|
+
set(value) {
|
|
638
|
+
super.set(value);
|
|
639
|
+
this.__onCacheSet__?.({ key: value.key });
|
|
640
|
+
}
|
|
641
|
+
remove(key) {
|
|
642
|
+
super.remove(key);
|
|
643
|
+
this.__onCacheRemove__?.({ key });
|
|
644
|
+
}
|
|
645
|
+
evict(expectSize) {
|
|
646
|
+
if (expectSize > this.__size__) {
|
|
647
|
+
this.debug((log) => log("Storage Size Not Enough: ", this.__size__, " < ", expectSize));
|
|
648
|
+
return false;
|
|
649
|
+
}
|
|
650
|
+
this.evictExpired();
|
|
651
|
+
let deficitSize = expectSize - this.size.free;
|
|
652
|
+
if (deficitSize <= 0) return true;
|
|
653
|
+
const entries = [...this.storage.values()];
|
|
654
|
+
const keys = [];
|
|
655
|
+
while (deficitSize > 0 && entries.length) {
|
|
656
|
+
const index = random(0, entries.length - 1);
|
|
657
|
+
const entry = entries[index];
|
|
658
|
+
deficitSize -= entry.size;
|
|
659
|
+
entries.splice(index, 1);
|
|
660
|
+
keys.push(entry.key);
|
|
661
|
+
}
|
|
662
|
+
this.__remove__(keys);
|
|
663
|
+
this.__onCacheEvict__?.({ keys });
|
|
664
|
+
return true;
|
|
665
|
+
}
|
|
697
666
|
};
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
var import_dayjs3 = __toESM(require("dayjs"));
|
|
667
|
+
//#endregion
|
|
668
|
+
//#region src/storage/memory-storage/lru-memory-storage.ts
|
|
701
669
|
var LRUMemoryStorage = class extends BaseMemoryStorage {
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
this.__remove__(keys);
|
|
745
|
-
(_a = this.__onCacheEvict__) == null ? void 0 : _a.call(this, { keys });
|
|
746
|
-
return true;
|
|
747
|
-
}
|
|
670
|
+
constructor(options) {
|
|
671
|
+
super(options);
|
|
672
|
+
}
|
|
673
|
+
get(key) {
|
|
674
|
+
const entry = super.get(key);
|
|
675
|
+
this.__onCacheGet__?.({ key });
|
|
676
|
+
return entry;
|
|
677
|
+
}
|
|
678
|
+
set(value) {
|
|
679
|
+
super.set(value);
|
|
680
|
+
this.__onCacheSet__?.({ key: value.key });
|
|
681
|
+
}
|
|
682
|
+
remove(key) {
|
|
683
|
+
super.remove(key);
|
|
684
|
+
this.__onCacheRemove__?.({ key });
|
|
685
|
+
}
|
|
686
|
+
evict(expectSize) {
|
|
687
|
+
if (expectSize > this.__size__) {
|
|
688
|
+
this.debug((log) => log("Storage Size Not Enough: ", this.__size__, " < ", expectSize));
|
|
689
|
+
return false;
|
|
690
|
+
}
|
|
691
|
+
this.evictExpired();
|
|
692
|
+
let deficitSize = expectSize - this.size.free;
|
|
693
|
+
if (deficitSize <= 0) return true;
|
|
694
|
+
const entries = [...this.storage.values()].sort((a, b) => {
|
|
695
|
+
const aVisitAt = this.visitTimeRecords.get(a.key);
|
|
696
|
+
const bVisitAt = this.visitTimeRecords.get(b.key);
|
|
697
|
+
if (aVisitAt === bVisitAt) return 0;
|
|
698
|
+
if (!aVisitAt) return 1;
|
|
699
|
+
if (!bVisitAt) return -1;
|
|
700
|
+
return (0, dayjs.default)(aVisitAt).isBefore((0, dayjs.default)(bVisitAt)) ? 1 : -1;
|
|
701
|
+
});
|
|
702
|
+
const keys = [];
|
|
703
|
+
while (deficitSize > 0 && entries.length) {
|
|
704
|
+
const entry = entries.pop();
|
|
705
|
+
deficitSize -= entry.size;
|
|
706
|
+
keys.push(entry.key);
|
|
707
|
+
}
|
|
708
|
+
this.__remove__(keys);
|
|
709
|
+
this.__onCacheEvict__?.({ keys });
|
|
710
|
+
return true;
|
|
711
|
+
}
|
|
748
712
|
};
|
|
749
|
-
|
|
750
|
-
|
|
713
|
+
//#endregion
|
|
714
|
+
//#region src/storage/memory-storage/lfu-memory-storage.ts
|
|
751
715
|
var LFUMemoryStorage = class extends BaseMemoryStorage {
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
}
|
|
791
|
-
this.__remove__(keys);
|
|
792
|
-
(_a = this.__onCacheEvict__) == null ? void 0 : _a.call(this, { keys });
|
|
793
|
-
return true;
|
|
794
|
-
}
|
|
716
|
+
constructor(options) {
|
|
717
|
+
super(options);
|
|
718
|
+
}
|
|
719
|
+
get(key) {
|
|
720
|
+
const entry = super.get(key);
|
|
721
|
+
this.__onCacheGet__?.({ key });
|
|
722
|
+
return entry;
|
|
723
|
+
}
|
|
724
|
+
set(value) {
|
|
725
|
+
super.set(value);
|
|
726
|
+
this.__onCacheSet__?.({ key: value.key });
|
|
727
|
+
}
|
|
728
|
+
remove(key) {
|
|
729
|
+
super.remove(key);
|
|
730
|
+
this.__onCacheRemove__?.({ key });
|
|
731
|
+
}
|
|
732
|
+
evict(expectSize) {
|
|
733
|
+
if (expectSize > this.__size__) {
|
|
734
|
+
this.debug((log) => log("Storage Size Not Enough: ", this.__size__, " < ", expectSize));
|
|
735
|
+
return false;
|
|
736
|
+
}
|
|
737
|
+
this.evictExpired();
|
|
738
|
+
let deficitSize = expectSize - this.size.free;
|
|
739
|
+
if (deficitSize <= 0) return true;
|
|
740
|
+
const entries = [...this.storage.values()].sort((a, b) => {
|
|
741
|
+
const aVisitCount = this.visitCountRecords.get(a.key) || 0;
|
|
742
|
+
return (this.visitCountRecords.get(b.key) || 0) - aVisitCount;
|
|
743
|
+
});
|
|
744
|
+
const keys = [];
|
|
745
|
+
while (deficitSize > 0 && entries.length) {
|
|
746
|
+
const entry = entries.pop();
|
|
747
|
+
deficitSize -= entry.size;
|
|
748
|
+
keys.push(entry.key);
|
|
749
|
+
}
|
|
750
|
+
this.__remove__(keys);
|
|
751
|
+
this.__onCacheEvict__?.({ keys });
|
|
752
|
+
return true;
|
|
753
|
+
}
|
|
795
754
|
};
|
|
796
|
-
|
|
797
|
-
|
|
755
|
+
//#endregion
|
|
756
|
+
//#region src/storage/memory-storage/memory-storage.ts
|
|
798
757
|
var MemoryStorage = class extends KeqCacheStorage {
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
remove(key) {
|
|
822
|
-
return this.storage.remove(key);
|
|
823
|
-
}
|
|
824
|
-
async print() {
|
|
825
|
-
return this.storage.print();
|
|
826
|
-
}
|
|
758
|
+
constructor(options) {
|
|
759
|
+
super();
|
|
760
|
+
_defineProperty(this, "storage", void 0);
|
|
761
|
+
const eviction = options?.eviction || "lru";
|
|
762
|
+
if (eviction === "ttl") this.storage = new TTLMemoryStorage(options);
|
|
763
|
+
else if (eviction === "random") this.storage = new RandomMemoryStorage(options);
|
|
764
|
+
else if (eviction === "lru") this.storage = new LRUMemoryStorage(options);
|
|
765
|
+
else if (eviction === "lfu") this.storage = new LFUMemoryStorage(options);
|
|
766
|
+
else throw new TypeError(`Invalid eviction: ${String(eviction)}`);
|
|
767
|
+
}
|
|
768
|
+
set(entry) {
|
|
769
|
+
return this.storage.set(entry);
|
|
770
|
+
}
|
|
771
|
+
get(key) {
|
|
772
|
+
return this.storage.get(key);
|
|
773
|
+
}
|
|
774
|
+
remove(key) {
|
|
775
|
+
return this.storage.remove(key);
|
|
776
|
+
}
|
|
777
|
+
async print() {
|
|
778
|
+
return this.storage.print();
|
|
779
|
+
}
|
|
827
780
|
};
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
var R5 = __toESM(require("ramda"));
|
|
834
|
-
var import_dayjs4 = __toESM(require("dayjs"));
|
|
835
|
-
var import_idb = require("idb");
|
|
836
|
-
|
|
837
|
-
// src/storage/indexed-db-storage/constants/default-table-name.ts
|
|
838
|
-
var DEFAULT_TABLE_NAME = "keq_cache_indexed_db_storage";
|
|
839
|
-
|
|
840
|
-
// src/storage/indexed-db-storage/base-indexed-db-storage.ts
|
|
781
|
+
//#endregion
|
|
782
|
+
//#region src/storage/indexed-db-storage/constants/default-table-name.ts
|
|
783
|
+
const DEFAULT_TABLE_NAME = "keq_cache_indexed_db_storage";
|
|
784
|
+
//#endregion
|
|
785
|
+
//#region src/storage/indexed-db-storage/base-indexed-db-storage.ts
|
|
841
786
|
var BaseIndexedDBStorage = class extends InternalStorage {
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
}
|
|
1004
|
-
await this.__remove__(tx, expiredKeys);
|
|
1005
|
-
await tx.done;
|
|
1006
|
-
(_a = this.__onCacheExpired__) == null ? void 0 : _a.call(this, { keys: expiredKeys });
|
|
1007
|
-
} catch (error) {
|
|
1008
|
-
return;
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
787
|
+
constructor(options) {
|
|
788
|
+
super(options);
|
|
789
|
+
_defineProperty(this, "tableName", DEFAULT_TABLE_NAME);
|
|
790
|
+
_defineProperty(this, "db", void 0);
|
|
791
|
+
_defineProperty(this, "lastEvictExpiredTime", (0, dayjs.default)(0));
|
|
792
|
+
if (options?.tableName === "keq_cache_indexed_db_storage") throw new CacheException(`IndexedDBStorage name cannot be "${DEFAULT_TABLE_NAME}"`);
|
|
793
|
+
this.tableName = options?.tableName || "keq_cache_indexed_db_storage";
|
|
794
|
+
}
|
|
795
|
+
async openDB() {
|
|
796
|
+
if (this.db) return this.db;
|
|
797
|
+
const tableName = this.tableName;
|
|
798
|
+
const db = await (0, idb.openDB)(tableName, 2, {
|
|
799
|
+
upgrade(db) {
|
|
800
|
+
if (!db.objectStoreNames.contains("metadata")) db.createObjectStore("metadata", { keyPath: "key" }).createIndex("expiredAt", "expiredAt");
|
|
801
|
+
if (!db.objectStoreNames.contains("response")) db.createObjectStore("response", { keyPath: "key" }).createIndex("responseStatus", "responseStatus");
|
|
802
|
+
if (!db.objectStoreNames.contains("visits")) {
|
|
803
|
+
const visitsStore = db.createObjectStore("visits", { keyPath: "key" });
|
|
804
|
+
visitsStore.createIndex("visitCount", "visitCount");
|
|
805
|
+
visitsStore.createIndex("lastVisitedAt", "lastVisitedAt");
|
|
806
|
+
}
|
|
807
|
+
},
|
|
808
|
+
blocked() {
|
|
809
|
+
Logger.error(`[@keq-request/cache] IndexedDB Table ${tableName} is blocked`);
|
|
810
|
+
},
|
|
811
|
+
blocking() {
|
|
812
|
+
Logger.error(`[@keq-request/cache] IndexedDB Table ${tableName} is blocking`);
|
|
813
|
+
},
|
|
814
|
+
terminated() {
|
|
815
|
+
Logger.error(`[@keq-request/cache] IndexedDB Table ${tableName} is terminated`);
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
this.db = db;
|
|
819
|
+
return db;
|
|
820
|
+
}
|
|
821
|
+
async getSize() {
|
|
822
|
+
const items = await (await this.openDB()).getAll("metadata");
|
|
823
|
+
const used = ramda.sum(items.map((entry) => entry.size));
|
|
824
|
+
return {
|
|
825
|
+
used,
|
|
826
|
+
free: this.__size__ - used
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
async get(key) {
|
|
830
|
+
await this.evictExpired();
|
|
831
|
+
try {
|
|
832
|
+
const db = await this.openDB();
|
|
833
|
+
const dbMetadata = await db.get("metadata", key);
|
|
834
|
+
const dbResponse = await db.get("response", key);
|
|
835
|
+
const dbVisits = await db.get("visits", key);
|
|
836
|
+
if (!dbMetadata || !dbResponse) return;
|
|
837
|
+
await db.put("visits", {
|
|
838
|
+
key: dbMetadata.key,
|
|
839
|
+
visitCount: dbVisits ? dbVisits.visitCount + 1 : 1,
|
|
840
|
+
lastVisitedAt: /* @__PURE__ */ new Date()
|
|
841
|
+
});
|
|
842
|
+
const response = new Response(dbResponse.responseBody, {
|
|
843
|
+
status: dbResponse.responseStatus,
|
|
844
|
+
headers: new Headers(dbResponse.responseHeaders),
|
|
845
|
+
statusText: dbResponse.responseStatusText
|
|
846
|
+
});
|
|
847
|
+
return await CacheEntry.build({
|
|
848
|
+
key: dbMetadata.key,
|
|
849
|
+
expiredAt: dbMetadata.expiredAt,
|
|
850
|
+
response,
|
|
851
|
+
size: dbMetadata.size
|
|
852
|
+
});
|
|
853
|
+
} catch (error) {
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
async set(entry) {
|
|
858
|
+
try {
|
|
859
|
+
if (!await this.evict(entry.size)) {
|
|
860
|
+
const size = await this.getSize();
|
|
861
|
+
this.debug((log) => log(`Storage Size Not Enough: ${size.free} < ${entry.size}`));
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
const dbMetadata = {
|
|
865
|
+
key: entry.key,
|
|
866
|
+
size: entry.size,
|
|
867
|
+
expiredAt: entry.expiredAt,
|
|
868
|
+
visitedAt: /* @__PURE__ */ new Date(),
|
|
869
|
+
visitCount: 0
|
|
870
|
+
};
|
|
871
|
+
const response = entry.response.clone();
|
|
872
|
+
const dbResponse = {
|
|
873
|
+
key: entry.key,
|
|
874
|
+
responseBody: await response.arrayBuffer(),
|
|
875
|
+
responseHeaders: [...response.headers.entries()],
|
|
876
|
+
responseStatus: response.status,
|
|
877
|
+
responseStatusText: response.statusText
|
|
878
|
+
};
|
|
879
|
+
const tx = (await this.openDB()).transaction([
|
|
880
|
+
"metadata",
|
|
881
|
+
"response",
|
|
882
|
+
"visits"
|
|
883
|
+
], "readwrite");
|
|
884
|
+
const metadataStore = tx.objectStore("metadata");
|
|
885
|
+
const responseStore = tx.objectStore("response");
|
|
886
|
+
const visitsStore = tx.objectStore("visits");
|
|
887
|
+
const dbVisits = await visitsStore.get(entry.key) || {
|
|
888
|
+
key: entry.key,
|
|
889
|
+
visitCount: 0,
|
|
890
|
+
lastVisitedAt: /* @__PURE__ */ new Date()
|
|
891
|
+
};
|
|
892
|
+
await Promise.all([
|
|
893
|
+
metadataStore.put(dbMetadata),
|
|
894
|
+
responseStore.put(dbResponse),
|
|
895
|
+
visitsStore.put(dbVisits)
|
|
896
|
+
]);
|
|
897
|
+
await tx.done;
|
|
898
|
+
} catch (error) {
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
async __remove__(tx, keys) {
|
|
903
|
+
await Promise.all(ramda.unnest(keys.map((key) => [
|
|
904
|
+
tx.objectStore("metadata").delete(key),
|
|
905
|
+
tx.objectStore("response").delete(key),
|
|
906
|
+
tx.objectStore("visits").delete(key)
|
|
907
|
+
])));
|
|
908
|
+
}
|
|
909
|
+
async remove(key) {
|
|
910
|
+
try {
|
|
911
|
+
const tx = (await this.openDB()).transaction([
|
|
912
|
+
"metadata",
|
|
913
|
+
"response",
|
|
914
|
+
"visits"
|
|
915
|
+
], "readwrite");
|
|
916
|
+
await this.__remove__(tx, [key]);
|
|
917
|
+
await tx.done;
|
|
918
|
+
} catch (error) {
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* @zh 清除过期的缓存
|
|
924
|
+
*/
|
|
925
|
+
async evictExpired() {
|
|
926
|
+
const now = (0, dayjs.default)();
|
|
927
|
+
if (now.diff(this.lastEvictExpiredTime, "second") < 1) return;
|
|
928
|
+
this.lastEvictExpiredTime = now;
|
|
929
|
+
try {
|
|
930
|
+
const tx = (await this.openDB()).transaction([
|
|
931
|
+
"metadata",
|
|
932
|
+
"response",
|
|
933
|
+
"visits"
|
|
934
|
+
], "readwrite");
|
|
935
|
+
let cursor = await tx.objectStore("metadata").index("expiredAt").openCursor(IDBKeyRange.upperBound(now.toDate()));
|
|
936
|
+
const expiredKeys = [];
|
|
937
|
+
while (cursor) if ((0, dayjs.default)(cursor.value.expiredAt).isBefore(now)) {
|
|
938
|
+
expiredKeys.push(cursor.value.key);
|
|
939
|
+
cursor = await cursor.continue();
|
|
940
|
+
} else break;
|
|
941
|
+
await this.__remove__(tx, expiredKeys);
|
|
942
|
+
await tx.done;
|
|
943
|
+
this.__onCacheExpired__?.({ keys: expiredKeys });
|
|
944
|
+
} catch (error) {
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
1011
948
|
};
|
|
1012
|
-
|
|
1013
|
-
|
|
949
|
+
//#endregion
|
|
950
|
+
//#region src/storage/indexed-db-storage/random-indexed-db-storage.ts
|
|
1014
951
|
var RandomIndexedDBStorage = class extends BaseIndexedDBStorage {
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
(_a = this.__onCacheEvict__) == null ? void 0 : _a.call(this, { keys });
|
|
1061
|
-
return true;
|
|
1062
|
-
}
|
|
952
|
+
constructor(options) {
|
|
953
|
+
super(options);
|
|
954
|
+
}
|
|
955
|
+
async get(key) {
|
|
956
|
+
const entry = await super.get(key);
|
|
957
|
+
this.__onCacheGet__?.({ key });
|
|
958
|
+
return entry;
|
|
959
|
+
}
|
|
960
|
+
async set(value) {
|
|
961
|
+
await super.set(value);
|
|
962
|
+
this.__onCacheSet__?.({ key: value.key });
|
|
963
|
+
}
|
|
964
|
+
async remove(key) {
|
|
965
|
+
await super.remove(key);
|
|
966
|
+
this.__onCacheRemove__?.({ key });
|
|
967
|
+
}
|
|
968
|
+
async evict(expectSize) {
|
|
969
|
+
await this.evictExpired();
|
|
970
|
+
let deficitSize = expectSize - (await this.getSize()).free;
|
|
971
|
+
if (deficitSize <= 0) return true;
|
|
972
|
+
const tx = (await this.openDB()).transaction([
|
|
973
|
+
"metadata",
|
|
974
|
+
"response",
|
|
975
|
+
"visits"
|
|
976
|
+
], "readwrite");
|
|
977
|
+
const metadatas = await tx.objectStore("metadata").getAll();
|
|
978
|
+
const totalSize = ramda.sum(metadatas.map((m) => m.size));
|
|
979
|
+
if (totalSize < deficitSize) {
|
|
980
|
+
this.debug((log) => log(`Storage Size Not Enough, deficit size: ${deficitSize - totalSize}`));
|
|
981
|
+
tx.abort();
|
|
982
|
+
return false;
|
|
983
|
+
}
|
|
984
|
+
const keys = [];
|
|
985
|
+
while (deficitSize > 0 && metadatas.length) {
|
|
986
|
+
const index = random(0, metadatas.length - 1);
|
|
987
|
+
const metadata = metadatas[index];
|
|
988
|
+
deficitSize -= metadata.size;
|
|
989
|
+
keys.push(metadata.key);
|
|
990
|
+
metadatas.splice(index, 1);
|
|
991
|
+
}
|
|
992
|
+
await this.__remove__(tx, keys);
|
|
993
|
+
await tx.done;
|
|
994
|
+
this.__onCacheEvict__?.({ keys });
|
|
995
|
+
return true;
|
|
996
|
+
}
|
|
1063
997
|
};
|
|
1064
|
-
|
|
1065
|
-
|
|
998
|
+
//#endregion
|
|
999
|
+
//#region src/storage/indexed-db-storage/lfu-indexed-db-storage.ts
|
|
1066
1000
|
var LFUIndexedDBStorage = class extends BaseIndexedDBStorage {
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
(_a = this.__onCacheEvict__) == null ? void 0 : _a.call(this, { keys });
|
|
1117
|
-
return true;
|
|
1118
|
-
}
|
|
1001
|
+
constructor(options) {
|
|
1002
|
+
super(options);
|
|
1003
|
+
}
|
|
1004
|
+
async get(key) {
|
|
1005
|
+
const entry = await super.get(key);
|
|
1006
|
+
this.__onCacheGet__?.({ key });
|
|
1007
|
+
return entry;
|
|
1008
|
+
}
|
|
1009
|
+
async set(value) {
|
|
1010
|
+
await super.set(value);
|
|
1011
|
+
this.__onCacheSet__?.({ key: value.key });
|
|
1012
|
+
}
|
|
1013
|
+
async remove(key) {
|
|
1014
|
+
await super.remove(key);
|
|
1015
|
+
this.__onCacheRemove__?.({ key });
|
|
1016
|
+
}
|
|
1017
|
+
async evict(expectSize) {
|
|
1018
|
+
await this.evictExpired();
|
|
1019
|
+
let deficitSize = expectSize - (await this.getSize()).free;
|
|
1020
|
+
if (deficitSize <= 0) return true;
|
|
1021
|
+
const tx = (await this.openDB()).transaction([
|
|
1022
|
+
"metadata",
|
|
1023
|
+
"response",
|
|
1024
|
+
"visits"
|
|
1025
|
+
], "readwrite");
|
|
1026
|
+
const metadataStore = tx.objectStore("metadata");
|
|
1027
|
+
let cursor = await tx.objectStore("visits").index("visitCount").openCursor();
|
|
1028
|
+
const keys = [];
|
|
1029
|
+
while (deficitSize > 0 && cursor) {
|
|
1030
|
+
const metadata = await metadataStore.get(cursor.value.key);
|
|
1031
|
+
if (!metadata) {
|
|
1032
|
+
await cursor.delete();
|
|
1033
|
+
cursor = await cursor.continue();
|
|
1034
|
+
continue;
|
|
1035
|
+
}
|
|
1036
|
+
deficitSize -= metadata.size;
|
|
1037
|
+
keys.push(cursor.value.key);
|
|
1038
|
+
cursor = await cursor.continue();
|
|
1039
|
+
}
|
|
1040
|
+
if (deficitSize > 0) {
|
|
1041
|
+
this.debug((log) => log(`Storage Size Not Enough, deficit size: ${deficitSize}`));
|
|
1042
|
+
tx.abort();
|
|
1043
|
+
return false;
|
|
1044
|
+
}
|
|
1045
|
+
await this.__remove__(tx, keys);
|
|
1046
|
+
await tx.done;
|
|
1047
|
+
this.__onCacheEvict__?.({ keys });
|
|
1048
|
+
return true;
|
|
1049
|
+
}
|
|
1119
1050
|
};
|
|
1120
|
-
|
|
1121
|
-
|
|
1051
|
+
//#endregion
|
|
1052
|
+
//#region src/storage/indexed-db-storage/lru-indexed-db-storage.ts
|
|
1122
1053
|
var LRUIndexedDBStorage = class extends BaseIndexedDBStorage {
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
return true;
|
|
1174
|
-
}
|
|
1054
|
+
constructor(options) {
|
|
1055
|
+
super(options);
|
|
1056
|
+
}
|
|
1057
|
+
async get(key) {
|
|
1058
|
+
const entry = await super.get(key);
|
|
1059
|
+
this.__onCacheGet__?.({ key });
|
|
1060
|
+
return entry;
|
|
1061
|
+
}
|
|
1062
|
+
async set(value) {
|
|
1063
|
+
await super.set(value);
|
|
1064
|
+
this.__onCacheSet__?.({ key: value.key });
|
|
1065
|
+
}
|
|
1066
|
+
async remove(key) {
|
|
1067
|
+
await super.remove(key);
|
|
1068
|
+
this.__onCacheRemove__?.({ key });
|
|
1069
|
+
}
|
|
1070
|
+
async evict(expectSize) {
|
|
1071
|
+
await this.evictExpired();
|
|
1072
|
+
let deficitSize = expectSize - (await this.getSize()).free;
|
|
1073
|
+
if (deficitSize <= 0) return true;
|
|
1074
|
+
const tx = (await this.openDB()).transaction([
|
|
1075
|
+
"metadata",
|
|
1076
|
+
"response",
|
|
1077
|
+
"visits"
|
|
1078
|
+
], "readwrite");
|
|
1079
|
+
const metadataStore = tx.objectStore("metadata");
|
|
1080
|
+
const visitsStore = tx.objectStore("visits");
|
|
1081
|
+
const keys = [];
|
|
1082
|
+
let cursor = await visitsStore.index("lastVisitedAt").openCursor();
|
|
1083
|
+
while (deficitSize > 0 && cursor) {
|
|
1084
|
+
const metadata = await metadataStore.get(cursor.value.key);
|
|
1085
|
+
if (!metadata) {
|
|
1086
|
+
await cursor.delete();
|
|
1087
|
+
cursor = await cursor.continue();
|
|
1088
|
+
continue;
|
|
1089
|
+
}
|
|
1090
|
+
deficitSize -= metadata.size;
|
|
1091
|
+
keys.push(cursor.value.key);
|
|
1092
|
+
cursor = await cursor.continue();
|
|
1093
|
+
}
|
|
1094
|
+
if (deficitSize > 0) {
|
|
1095
|
+
this.debug((log) => log(`Storage Size Not Enough, deficit size: ${deficitSize}`));
|
|
1096
|
+
tx.abort();
|
|
1097
|
+
return false;
|
|
1098
|
+
}
|
|
1099
|
+
await this.__remove__(tx, keys);
|
|
1100
|
+
await tx.done;
|
|
1101
|
+
this.__onCacheEvict__?.({ keys });
|
|
1102
|
+
return true;
|
|
1103
|
+
}
|
|
1175
1104
|
};
|
|
1176
|
-
|
|
1177
|
-
|
|
1105
|
+
//#endregion
|
|
1106
|
+
//#region src/storage/indexed-db-storage/ttl-indexed-db-storage.ts
|
|
1178
1107
|
var TTLIndexedDBStorage = class extends BaseIndexedDBStorage {
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
return true;
|
|
1229
|
-
}
|
|
1108
|
+
constructor(options) {
|
|
1109
|
+
super(options);
|
|
1110
|
+
}
|
|
1111
|
+
async get(key) {
|
|
1112
|
+
const entry = await super.get(key);
|
|
1113
|
+
this.__onCacheGet__?.({ key });
|
|
1114
|
+
return entry;
|
|
1115
|
+
}
|
|
1116
|
+
async set(value) {
|
|
1117
|
+
await super.set(value);
|
|
1118
|
+
this.__onCacheSet__?.({ key: value.key });
|
|
1119
|
+
}
|
|
1120
|
+
async remove(key) {
|
|
1121
|
+
await super.remove(key);
|
|
1122
|
+
this.__onCacheRemove__?.({ key });
|
|
1123
|
+
}
|
|
1124
|
+
async evict(expectSize) {
|
|
1125
|
+
await this.evictExpired();
|
|
1126
|
+
let deficitSize = expectSize - (await this.getSize()).free;
|
|
1127
|
+
if (deficitSize <= 0) return true;
|
|
1128
|
+
const tx = (await this.openDB()).transaction([
|
|
1129
|
+
"metadata",
|
|
1130
|
+
"response",
|
|
1131
|
+
"visits"
|
|
1132
|
+
], "readwrite");
|
|
1133
|
+
const metadataStore = tx.objectStore("metadata");
|
|
1134
|
+
const keys = [];
|
|
1135
|
+
let cursor = await metadataStore.index("expiredAt").openCursor();
|
|
1136
|
+
while (deficitSize > 0 && cursor) {
|
|
1137
|
+
const metadata = await metadataStore.get(cursor.value.key);
|
|
1138
|
+
if (!metadata) {
|
|
1139
|
+
await cursor.delete();
|
|
1140
|
+
cursor = await cursor.continue();
|
|
1141
|
+
continue;
|
|
1142
|
+
}
|
|
1143
|
+
deficitSize -= metadata.size;
|
|
1144
|
+
keys.push(cursor.value.key);
|
|
1145
|
+
cursor = await cursor.continue();
|
|
1146
|
+
}
|
|
1147
|
+
if (deficitSize > 0) {
|
|
1148
|
+
this.debug((log) => log(`Storage Size Not Enough, deficit size: ${deficitSize}`));
|
|
1149
|
+
tx.abort();
|
|
1150
|
+
return false;
|
|
1151
|
+
}
|
|
1152
|
+
await this.__remove__(tx, keys);
|
|
1153
|
+
await tx.done;
|
|
1154
|
+
this.__onCacheEvict__?.({ keys });
|
|
1155
|
+
return true;
|
|
1156
|
+
}
|
|
1230
1157
|
};
|
|
1231
|
-
|
|
1232
|
-
|
|
1158
|
+
//#endregion
|
|
1159
|
+
//#region src/storage/indexed-db-storage/indexed-db-storage.ts
|
|
1233
1160
|
var IndexedDBStorage = class extends KeqCacheStorage {
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
get(key) {
|
|
1254
|
-
return this.storage.get(key);
|
|
1255
|
-
}
|
|
1256
|
-
remove(key) {
|
|
1257
|
-
return this.storage.remove(key);
|
|
1258
|
-
}
|
|
1161
|
+
constructor(options) {
|
|
1162
|
+
super();
|
|
1163
|
+
_defineProperty(this, "storage", void 0);
|
|
1164
|
+
const eviction = options?.eviction || "lru";
|
|
1165
|
+
if (eviction === "random") this.storage = new RandomIndexedDBStorage(options);
|
|
1166
|
+
else if (eviction === "lfu") this.storage = new LFUIndexedDBStorage(options);
|
|
1167
|
+
else if (eviction === "lru") this.storage = new LRUIndexedDBStorage(options);
|
|
1168
|
+
else if (eviction === "ttl") this.storage = new TTLIndexedDBStorage(options);
|
|
1169
|
+
else throw new CacheException(`Not Supported Eviction: ${String(options?.eviction)}`);
|
|
1170
|
+
}
|
|
1171
|
+
set(entry) {
|
|
1172
|
+
return this.storage.set(entry);
|
|
1173
|
+
}
|
|
1174
|
+
get(key) {
|
|
1175
|
+
return this.storage.get(key);
|
|
1176
|
+
}
|
|
1177
|
+
remove(key) {
|
|
1178
|
+
return this.storage.remove(key);
|
|
1179
|
+
}
|
|
1259
1180
|
};
|
|
1260
|
-
|
|
1261
|
-
|
|
1181
|
+
//#endregion
|
|
1182
|
+
//#region src/storage/multi-tier-storage/multi-tier-storage.ts
|
|
1183
|
+
/**
|
|
1184
|
+
* @en Multi-tier cache storage that manages multiple KeqCacheStorage instances in tiers
|
|
1185
|
+
* @zh 多层缓存存储,管理多个分层的 KeqCacheStorage 实例
|
|
1186
|
+
*/
|
|
1262
1187
|
var MultiTierStorage = class extends KeqCacheStorage {
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
}
|
|
1317
|
-
const promises = lowerTierStorages.map(async (storage) => storage.set(entry.clone()));
|
|
1318
|
-
try {
|
|
1319
|
-
await Promise.all(promises);
|
|
1320
|
-
} catch (error) {
|
|
1321
|
-
console.warn("Failed to sync cache entry to lower tiers:", error);
|
|
1322
|
-
}
|
|
1323
|
-
}
|
|
1188
|
+
/**
|
|
1189
|
+
* @param storages Array of storage instances ordered by performance (fastest first)
|
|
1190
|
+
* @zh 按性价比排序的存储实例数组,排在前面的成本低,排在后面的成本高
|
|
1191
|
+
*/
|
|
1192
|
+
constructor(options) {
|
|
1193
|
+
super();
|
|
1194
|
+
_defineProperty(this, "storages", void 0);
|
|
1195
|
+
if (!options.tiers || options.tiers.length === 0) throw new Error("At least one storage instance is required");
|
|
1196
|
+
this.storages = [...options.tiers];
|
|
1197
|
+
}
|
|
1198
|
+
/**
|
|
1199
|
+
* @en Get cache entry, searching from lowest to highest tier
|
|
1200
|
+
* @zh 获取缓存条目,从最底层到高层依次搜索
|
|
1201
|
+
*/
|
|
1202
|
+
async get(key) {
|
|
1203
|
+
for (let i = 0; i < this.storages.length; i++) {
|
|
1204
|
+
const entry = await this.storages[i].get(key);
|
|
1205
|
+
if (entry) {
|
|
1206
|
+
if (i > 0) await this.syncToLowerTiers(entry, i);
|
|
1207
|
+
return entry;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
/**
|
|
1212
|
+
* @en Set cache entry to all tiers concurrently
|
|
1213
|
+
* @zh 并发写入所有层的缓存
|
|
1214
|
+
*/
|
|
1215
|
+
async set(entry) {
|
|
1216
|
+
const promises = this.storages.map(async (storage) => storage.set(entry));
|
|
1217
|
+
await Promise.all(promises);
|
|
1218
|
+
}
|
|
1219
|
+
/**
|
|
1220
|
+
* @en Remove cache entry from all tiers
|
|
1221
|
+
* @zh 从所有层删除缓存条目
|
|
1222
|
+
*/
|
|
1223
|
+
async remove(key) {
|
|
1224
|
+
const promises = this.storages.map(async (storage) => storage.remove(key));
|
|
1225
|
+
await Promise.all(promises);
|
|
1226
|
+
}
|
|
1227
|
+
/**
|
|
1228
|
+
* @en Sync cache entry to all lower tiers (tiers with index < currentTierIndex)
|
|
1229
|
+
* @zh 将缓存条目同步到所有低层存储(索引小于当前层的存储)
|
|
1230
|
+
*/
|
|
1231
|
+
async syncToLowerTiers(entry, currentTierIndex) {
|
|
1232
|
+
const lowerTierStorages = this.storages.slice(0, currentTierIndex);
|
|
1233
|
+
if (lowerTierStorages.length === 0) return;
|
|
1234
|
+
const promises = lowerTierStorages.map(async (storage) => storage.set(entry.clone()));
|
|
1235
|
+
try {
|
|
1236
|
+
await Promise.all(promises);
|
|
1237
|
+
} catch (error) {
|
|
1238
|
+
console.warn("Failed to sync cache entry to lower tiers:", error);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1324
1241
|
};
|
|
1325
|
-
|
|
1326
|
-
|
|
1242
|
+
//#endregion
|
|
1243
|
+
//#region src/storage/tier-storage/tier-storage.ts
|
|
1244
|
+
/**
|
|
1245
|
+
* @en Two-tier cache storage that combines MemoryStorage (L1) and IndexedDBStorage (L2)
|
|
1246
|
+
* @zh 二级缓存存储,结合了MemoryStorage(一级)和IndexedDBStorage(二级)
|
|
1247
|
+
*
|
|
1248
|
+
* This is a convenience wrapper around MultiTierStorage that provides:
|
|
1249
|
+
* - Fast in-memory cache (L1)
|
|
1250
|
+
* - Persistent IndexedDB cache (L2)
|
|
1251
|
+
* - Simplified configuration options
|
|
1252
|
+
*/
|
|
1327
1253
|
var TierStorage = class extends MultiTierStorage {
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
});
|
|
1334
|
-
}
|
|
1254
|
+
constructor(options) {
|
|
1255
|
+
const memoryStorage = options?.memory instanceof MemoryStorage ? options.memory : new MemoryStorage(options?.memory);
|
|
1256
|
+
const indexedDBStorage = options?.indexedDB instanceof IndexedDBStorage ? options.indexedDB : new IndexedDBStorage(options?.indexedDB);
|
|
1257
|
+
super({ tiers: [memoryStorage, indexedDBStorage] });
|
|
1258
|
+
}
|
|
1335
1259
|
};
|
|
1260
|
+
//#endregion
|
|
1261
|
+
exports.Eviction = Eviction;
|
|
1262
|
+
exports.IndexedDBStorage = IndexedDBStorage;
|
|
1263
|
+
exports.KeqCacheStorage = KeqCacheStorage;
|
|
1264
|
+
exports.MemoryStorage = MemoryStorage;
|
|
1265
|
+
exports.MultiTierStorage = MultiTierStorage;
|
|
1266
|
+
exports.Size = Size;
|
|
1267
|
+
exports.Strategy = Strategy;
|
|
1268
|
+
exports.TierStorage = TierStorage;
|
|
1269
|
+
exports.cache = cache;
|
|
1270
|
+
|
|
1336
1271
|
//# sourceMappingURL=index.js.map
|