@dee-wan/cache 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +177 -2
- package/dist/chunk-A4WV6RY4.js +311 -0
- package/dist/chunk-A4WV6RY4.js.map +1 -0
- package/dist/chunk-AENVFT2S.js +6 -0
- package/dist/chunk-AENVFT2S.js.map +1 -0
- package/dist/chunk-D2EESWMC.js +19 -0
- package/dist/chunk-D2EESWMC.js.map +1 -0
- package/dist/chunk-E6OZZ5UX.js +133 -0
- package/dist/chunk-E6OZZ5UX.js.map +1 -0
- package/dist/chunk-HGAUU4EU.js +388 -0
- package/dist/chunk-HGAUU4EU.js.map +1 -0
- package/dist/chunk-JPK2AF7X.js +18 -0
- package/dist/chunk-JPK2AF7X.js.map +1 -0
- package/dist/chunk-LHOK33GI.js +12 -0
- package/dist/chunk-LHOK33GI.js.map +1 -0
- package/dist/chunk-MOJBHU3S.js +431 -0
- package/dist/chunk-MOJBHU3S.js.map +1 -0
- package/dist/chunk-OOPPXK7Q.js +133 -0
- package/dist/chunk-OOPPXK7Q.js.map +1 -0
- package/dist/chunk-ZCMZJKGN.js +78 -0
- package/dist/chunk-ZCMZJKGN.js.map +1 -0
- package/dist/chunk-ZREX7LLC.js +545 -0
- package/dist/chunk-ZREX7LLC.js.map +1 -0
- package/dist/client.d.ts +50 -0
- package/dist/client.js +224 -0
- package/dist/client.js.map +1 -0
- package/dist/cloudflare/index.d.ts +15 -2
- package/dist/cloudflare/index.js +413 -45
- package/dist/cloudflare/index.js.map +1 -1
- package/dist/d1/config.d.ts +41 -0
- package/dist/d1/config.js +102 -0
- package/dist/d1/config.js.map +1 -0
- package/dist/d1/index.d.ts +64 -0
- package/dist/d1/index.js +196 -0
- package/dist/d1/index.js.map +1 -0
- package/dist/d1/response-lease.d.ts +9 -0
- package/dist/d1/response-lease.js +42 -0
- package/dist/d1/response-lease.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -616
- package/dist/index.js.map +1 -1
- package/dist/profile--LBtbQI_.d.ts +30 -0
- package/dist/response-lease-DeeM-ofO.d.ts +19 -0
- package/dist/response-lease.d.ts +7 -0
- package/dist/response-lease.js +9 -0
- package/dist/response-lease.js.map +1 -0
- package/dist/response-warmup-BWQvnT1G.d.ts +38 -0
- package/dist/scoped-read.d.ts +12 -0
- package/dist/scoped-read.js +30 -0
- package/dist/scoped-read.js.map +1 -0
- package/dist/{types-DwtU0KpX.d.ts → types-D-Gd11to.d.ts} +13 -1
- package/docs/cache-contract.md +49 -1
- package/package.json +31 -2
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// src/d1/request-freshness.ts
|
|
2
|
+
var validFreshnessHeader = (name) => /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name);
|
|
3
|
+
var hasFreshnessCookie = (request, name) => (request.headers.get("cookie") ?? "").split(";").some((part) => part.split("=", 1)[0]?.trim() === name);
|
|
4
|
+
var hasFreshnessGeneration = (request, name) => {
|
|
5
|
+
const matches = (request.headers.get("cookie") ?? "").split(";").map((part) => part.trim()).filter((part) => part.split("=", 1)[0]?.trim() === name);
|
|
6
|
+
const value = matches[0]?.slice(matches[0].indexOf("=") + 1).trim() ?? "";
|
|
7
|
+
return matches.length === 1 && /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
|
|
8
|
+
};
|
|
9
|
+
var hasCacheBypass = (request) => (request.headers.get("cache-control") ?? "").split(",").some((part) => /^\s*(?:no-cache|no-store)(?:\s*=|\s*$)/i.test(part));
|
|
10
|
+
function regionalD1MetadataTtl(request, policy) {
|
|
11
|
+
if (request.method !== "GET" || hasFreshnessCookie(request, policy.freshnessCookie)) return 0;
|
|
12
|
+
if (policy.freshnessHeader !== void 0 && (!validFreshnessHeader(policy.freshnessHeader) || request.headers.has(policy.freshnessHeader))) return 0;
|
|
13
|
+
if (!policy.ignoreRequestCacheControl && hasCacheBypass(request)) return 0;
|
|
14
|
+
return 5e3;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { hasCacheBypass, hasFreshnessCookie, hasFreshnessGeneration, regionalD1MetadataTtl, validFreshnessHeader };
|
|
18
|
+
//# sourceMappingURL=chunk-D2EESWMC.js.map
|
|
19
|
+
//# sourceMappingURL=chunk-D2EESWMC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/d1/request-freshness.ts"],"names":[],"mappings":";AAGO,IAAM,oBAAA,GAAuB,CAAC,IAAA,KAA0B,+BAAA,CAAgC,KAAK,IAAI;AACjG,IAAM,kBAAA,GAAqB,CAAC,OAAA,EAAkB,IAAA,KAAA,CAA2B,OAAA,CAAQ,QAAQ,GAAA,CAAI,QAAQ,CAAA,IAAK,EAAA,EAAI,KAAA,CAAM,GAAG,EAAE,IAAA,CAAK,CAAC,IAAA,KAAS,IAAA,CAAK,KAAA,CAAM,GAAA,EAAK,CAAC,CAAA,CAAE,CAAC,CAAA,EAAG,IAAA,EAAK,KAAM,IAAI;AAC9K,IAAM,sBAAA,GAAyB,CAAC,OAAA,EAAkB,IAAA,KAA0B;AACjF,EAAA,MAAM,OAAA,GAAA,CAAW,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA,IAAK,EAAA,EAAI,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,IAAA,EAAM,CAAA,CAAE,MAAA,CAAO,CAAC,IAAA,KAAS,IAAA,CAAK,KAAA,CAAM,GAAA,EAAK,CAAC,CAAA,CAAE,CAAC,CAAA,EAAG,IAAA,OAAW,IAAI,CAAA;AACnJ,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,CAAC,CAAA,EAAG,MAAM,OAAA,CAAQ,CAAC,CAAA,CAAE,OAAA,CAAQ,GAAG,CAAA,GAAI,CAAC,CAAA,CAAE,MAAK,IAAK,EAAA;AACvE,EAAA,OAAO,OAAA,CAAQ,MAAA,KAAW,CAAA,IAAK,wEAAA,CAAyE,KAAK,KAAK,CAAA;AACpH;AACO,IAAM,iBAAiB,CAAC,OAAA,KAAA,CAA+B,QAAQ,OAAA,CAAQ,GAAA,CAAI,eAAe,CAAA,IAAK,EAAA,EAAI,KAAA,CAAM,GAAG,EAAE,IAAA,CAAK,CAAC,SAAS,yCAAA,CAA0C,IAAA,CAAK,IAAI,CAAC;AAEjL,SAAS,qBAAA,CAAsB,SAAkB,MAAA,EAAmC;AACzF,EAAA,IAAI,OAAA,CAAQ,WAAW,KAAA,IAAS,kBAAA,CAAmB,SAAS,MAAA,CAAO,eAAe,GAAG,OAAO,CAAA;AAC5F,EAAA,IAAI,MAAA,CAAO,eAAA,KAAoB,MAAA,KAAc,CAAC,qBAAqB,MAAA,CAAO,eAAe,CAAA,IAAK,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,MAAA,CAAO,eAAe,IAAI,OAAO,CAAA;AACnJ,EAAA,IAAI,CAAC,MAAA,CAAO,yBAAA,IAA6B,cAAA,CAAe,OAAO,GAAG,OAAO,CAAA;AACzE,EAAA,OAAO,GAAA;AACT","file":"chunk-D2EESWMC.js","sourcesContent":["import type { D1CacheProfile } from './profile';\n\ntype FreshnessPolicy = Pick<NonNullable<D1CacheProfile['readResponseLease']>, 'freshnessCookie' | 'freshnessHeader' | 'ignoreRequestCacheControl'>;\nexport const validFreshnessHeader = (name: string): boolean => /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name);\nexport const hasFreshnessCookie = (request: Request, name: string): boolean => (request.headers.get('cookie') ?? '').split(';').some((part) => part.split('=', 1)[0]?.trim() === name);\nexport const hasFreshnessGeneration = (request: Request, name: string): boolean => {\n const matches = (request.headers.get('cookie') ?? '').split(';').map((part) => part.trim()).filter((part) => part.split('=', 1)[0]?.trim() === name);\n const value = matches[0]?.slice(matches[0].indexOf('=') + 1).trim() ?? '';\n return matches.length === 1 && /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);\n};\nexport const hasCacheBypass = (request: Request): boolean => (request.headers.get('cache-control') ?? '').split(',').some((part) => /^\\s*(?:no-cache|no-store)(?:\\s*=|\\s*$)/i.test(part));\n\nexport function regionalD1MetadataTtl(request: Request, policy: FreshnessPolicy): 0 | 5000 {\n if (request.method !== 'GET' || hasFreshnessCookie(request, policy.freshnessCookie)) return 0;\n if (policy.freshnessHeader !== undefined && (!validFreshnessHeader(policy.freshnessHeader) || request.headers.has(policy.freshnessHeader))) return 0;\n if (!policy.ignoreRequestCacheControl && hasCacheBypass(request)) return 0;\n return 5000;\n}\n"]}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { encode, decode, stableStringify, sha256Hex } from './chunk-ZCMZJKGN.js';
|
|
2
|
+
|
|
3
|
+
// src/core/bounded-value.ts
|
|
4
|
+
function boundedValue(value, maxBytes, identity) {
|
|
5
|
+
let remaining = 1e4;
|
|
6
|
+
let bytes = maxBytes;
|
|
7
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8
|
+
const count = (text) => {
|
|
9
|
+
if (text.length > bytes) return false;
|
|
10
|
+
bytes -= new TextEncoder().encode(text).byteLength;
|
|
11
|
+
return bytes >= 0;
|
|
12
|
+
};
|
|
13
|
+
const check = (part, depth, objectValue) => {
|
|
14
|
+
if (--remaining < 0 || depth > 24) return false;
|
|
15
|
+
if (part === void 0) return identity || !objectValue;
|
|
16
|
+
if (part === null || typeof part === "boolean") return true;
|
|
17
|
+
if (typeof part === "string") return count(part);
|
|
18
|
+
if (typeof part === "number") return !Object.is(part, -0);
|
|
19
|
+
if (typeof part === "bigint") return count(part.toString());
|
|
20
|
+
if (typeof part !== "object" || seen.has(part)) return false;
|
|
21
|
+
if (part instanceof Date) return Number.isFinite(part.getTime());
|
|
22
|
+
if (part instanceof Uint8Array) {
|
|
23
|
+
bytes -= part.byteLength * 2;
|
|
24
|
+
return bytes >= 0;
|
|
25
|
+
}
|
|
26
|
+
const prototype = Object.getPrototypeOf(part);
|
|
27
|
+
if (!Array.isArray(part) && prototype !== Object.prototype) return false;
|
|
28
|
+
if (Object.getOwnPropertySymbols(part).length > 0) return false;
|
|
29
|
+
if (Array.isArray(part) && part.length > remaining) return false;
|
|
30
|
+
const properties = Object.getOwnPropertyDescriptors(part);
|
|
31
|
+
if (Object.entries(properties).some(([key, descriptor]) => !(Array.isArray(part) && key === "length") && (!descriptor.enumerable || !("value" in descriptor)))) return false;
|
|
32
|
+
if (Array.isArray(part) && Object.keys(properties).some((key) => key !== "length" && !/^(0|[1-9]\d*)$/.test(key))) return false;
|
|
33
|
+
seen.add(part);
|
|
34
|
+
const valid = Array.isArray(part) ? Array.from({ length: part.length }, (_, index) => Object.hasOwn(part, index) && check(part[index], depth + 1, false)).every(Boolean) : Object.entries(properties).every(([key, descriptor]) => count(key) && check(descriptor.value, depth + 1, true));
|
|
35
|
+
seen.delete(part);
|
|
36
|
+
return valid;
|
|
37
|
+
};
|
|
38
|
+
try {
|
|
39
|
+
return check(value, 0, false);
|
|
40
|
+
} catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/d1/regional.ts
|
|
46
|
+
var MAX_IDENTITY_BYTES = 32768;
|
|
47
|
+
var MAX_VALUE_BYTES = 15e5;
|
|
48
|
+
var MAX_RESPONSE_LEASE_BYTES = 8e6;
|
|
49
|
+
function sameEncodedValue(left, right) {
|
|
50
|
+
let remaining = 1e5;
|
|
51
|
+
const same = (a, b, depth) => {
|
|
52
|
+
if (--remaining < 0 || depth > 64) return false;
|
|
53
|
+
if (a === b) return true;
|
|
54
|
+
if (!a || !b || typeof a !== "object" || typeof b !== "object") return false;
|
|
55
|
+
if (Array.isArray(a) || Array.isArray(b)) return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((value, index) => same(value, b[index], depth + 1));
|
|
56
|
+
const keys = Object.keys(a);
|
|
57
|
+
return keys.length === Object.keys(b).length && keys.every((key) => Object.hasOwn(b, key) && same(Reflect.get(a, key), Reflect.get(b, key), depth + 1));
|
|
58
|
+
};
|
|
59
|
+
return same(left, right, 0);
|
|
60
|
+
}
|
|
61
|
+
function createRegionalCache(maxMs, maxValueBytes = MAX_VALUE_BYTES, options = {}) {
|
|
62
|
+
const cache = options.cache ?? (() => caches.default);
|
|
63
|
+
const now = options.now ?? (() => Date.now());
|
|
64
|
+
async function regionalKey2(ttl, identity) {
|
|
65
|
+
if (!Number.isFinite(ttl) || !ttl || ttl <= 0 || ttl > maxMs || !boundedValue(identity, MAX_IDENTITY_BYTES, true)) return null;
|
|
66
|
+
try {
|
|
67
|
+
const text = stableStringify(identity);
|
|
68
|
+
if (new TextEncoder().encode(text).byteLength > MAX_IDENTITY_BYTES) return null;
|
|
69
|
+
return `https://dee-wan-cache.invalid/regional-v1/${await sha256Hex(text)}`;
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function regionalRead2(key, ttl = maxMs, decimal) {
|
|
75
|
+
if (!key) return null;
|
|
76
|
+
try {
|
|
77
|
+
const response = await cache().match(key);
|
|
78
|
+
if (!response || response.status !== 200 || response.headers.has("set-cookie")) return null;
|
|
79
|
+
const reader = response.body?.getReader();
|
|
80
|
+
if (!reader) return null;
|
|
81
|
+
const chunks = [];
|
|
82
|
+
let size = 0;
|
|
83
|
+
let timer;
|
|
84
|
+
try {
|
|
85
|
+
const timeout = new Promise((_, reject) => {
|
|
86
|
+
timer = setTimeout(() => reject(new Error("cache body timeout")), 1e3);
|
|
87
|
+
});
|
|
88
|
+
for (; ; ) {
|
|
89
|
+
const part = await Promise.race([reader.read(), timeout]);
|
|
90
|
+
if (part.done) break;
|
|
91
|
+
size += part.value.byteLength;
|
|
92
|
+
if (size > maxValueBytes) return null;
|
|
93
|
+
chunks.push(part.value);
|
|
94
|
+
}
|
|
95
|
+
} finally {
|
|
96
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
97
|
+
void reader.cancel().catch(() => void 0);
|
|
98
|
+
}
|
|
99
|
+
const bytes = new Uint8Array(size);
|
|
100
|
+
let offset = 0;
|
|
101
|
+
for (const chunk of chunks) {
|
|
102
|
+
bytes.set(chunk, offset);
|
|
103
|
+
offset += chunk.byteLength;
|
|
104
|
+
}
|
|
105
|
+
const text = new TextDecoder("utf-8", { fatal: true, ignoreBOM: false }).decode(bytes);
|
|
106
|
+
const envelope = JSON.parse(text);
|
|
107
|
+
const currentTime = now();
|
|
108
|
+
if (!Number.isFinite(ttl) || ttl <= 0 || ttl > maxMs || !envelope || typeof envelope !== "object" || !("started" in envelope) || typeof envelope.started !== "number" || !Number.isSafeInteger(envelope.started) || envelope.started > currentTime || !("expires" in envelope) || typeof envelope.expires !== "number" || !Number.isSafeInteger(envelope.expires) || envelope.expires <= currentTime || envelope.expires > envelope.started + ttl || envelope.expires > currentTime + ttl || !("value" in envelope)) return null;
|
|
109
|
+
const value = decode(envelope.value, decimal);
|
|
110
|
+
return value !== null && value !== void 0 && boundedValue(value, maxValueBytes, false) && sameEncodedValue(encode(value), envelope.value) ? { value, expires: envelope.expires } : null;
|
|
111
|
+
} catch {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async function regionalWrite2(key, ttl, started, value) {
|
|
116
|
+
if (!key || !ttl || !Number.isFinite(ttl) || ttl <= 0 || ttl > maxMs || !Number.isSafeInteger(started) || !Number.isSafeInteger(Math.floor(started + ttl)) || value === null || value === void 0 || !boundedValue(value, maxValueBytes, false)) return;
|
|
117
|
+
try {
|
|
118
|
+
const expires = Math.floor(started + ttl);
|
|
119
|
+
if (expires <= now()) return;
|
|
120
|
+
const text = JSON.stringify({ started: Math.floor(started), expires, value: encode(value) });
|
|
121
|
+
if (new TextEncoder().encode(text).byteLength > maxValueBytes) return;
|
|
122
|
+
await cache().put(key, new Response(text, { headers: { "Cache-Control": `public, max-age=${maxMs / 1e3}` } }));
|
|
123
|
+
} catch {
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return { regionalKey: regionalKey2, regionalRead: regionalRead2, regionalWrite: regionalWrite2 };
|
|
127
|
+
}
|
|
128
|
+
var { regionalKey, regionalRead, regionalWrite } = createRegionalCache(5e3);
|
|
129
|
+
var { regionalKey: responseLeaseKey } = createRegionalCache(3e5);
|
|
130
|
+
|
|
131
|
+
export { MAX_RESPONSE_LEASE_BYTES, MAX_VALUE_BYTES, boundedValue, createRegionalCache, regionalKey, regionalRead, regionalWrite, responseLeaseKey };
|
|
132
|
+
//# sourceMappingURL=chunk-E6OZZ5UX.js.map
|
|
133
|
+
//# sourceMappingURL=chunk-E6OZZ5UX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/bounded-value.ts","../src/d1/regional.ts"],"names":["regionalKey","regionalRead","regionalWrite"],"mappings":"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","file":"chunk-E6OZZ5UX.js","sourcesContent":["export function boundedValue(value: unknown, maxBytes: number, identity: boolean): boolean {\n let remaining = 10_000;\n let bytes = maxBytes;\n const seen = new Set<object>();\n const count = (text: string): boolean => {\n if (text.length > bytes) return false;\n bytes -= new TextEncoder().encode(text).byteLength;\n return bytes >= 0;\n };\n const check = (part: unknown, depth: number, objectValue: boolean): boolean => {\n if (--remaining < 0 || depth > 24) return false;\n if (part === undefined) return identity || !objectValue;\n if (part === null || typeof part === 'boolean') return true;\n if (typeof part === 'string') return count(part);\n if (typeof part === 'number') return !Object.is(part, -0);\n if (typeof part === 'bigint') return count(part.toString());\n if (typeof part !== 'object' || seen.has(part)) return false;\n if (part instanceof Date) return Number.isFinite(part.getTime());\n if (part instanceof Uint8Array) { bytes -= part.byteLength * 2; return bytes >= 0; }\n const prototype: unknown = Object.getPrototypeOf(part);\n if (!Array.isArray(part) && prototype !== Object.prototype) return false;\n if (Object.getOwnPropertySymbols(part).length > 0) return false;\n if (Array.isArray(part) && part.length > remaining) return false;\n const properties = Object.getOwnPropertyDescriptors(part);\n if (Object.entries(properties).some(([key, descriptor]) => !(Array.isArray(part) && key === 'length') && (!descriptor.enumerable || !('value' in descriptor)))) return false;\n if (Array.isArray(part) && Object.keys(properties).some((key) => key !== 'length' && !/^(0|[1-9]\\d*)$/.test(key))) return false;\n seen.add(part);\n const valid = Array.isArray(part)\n ? Array.from({ length: part.length }, (_, index) => Object.hasOwn(part, index) && check(part[index], depth + 1, false)).every(Boolean)\n : Object.entries(properties).every(([key, descriptor]) => count(key) && check(descriptor.value, depth + 1, true));\n seen.delete(part);\n return valid;\n };\n try { return check(value, 0, false); } catch { return false; }\n}\n\n","import { decode, encode, sha256Hex, stableStringify } from '../core/codec';\nimport { boundedValue } from '../core/bounded-value';\nimport type { DecimalConstructor } from '../core/types';\n\nconst MAX_IDENTITY_BYTES = 32_768;\nexport const MAX_VALUE_BYTES = 1_500_000;\nexport const MAX_RESPONSE_LEASE_BYTES = 8_000_000;\n\nfunction sameEncodedValue(left: unknown, right: unknown): boolean {\n let remaining = 100_000;\n const same = (a: unknown, b: unknown, depth: number): boolean => {\n if (--remaining < 0 || depth > 64) return false;\n if (a === b) return true;\n if (!a || !b || typeof a !== 'object' || typeof b !== 'object') return false;\n if (Array.isArray(a) || Array.isArray(b)) return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((value, index) => same(value, b[index], depth + 1));\n const keys = Object.keys(a);\n return keys.length === Object.keys(b).length && keys.every((key) => Object.hasOwn(b, key) && same(Reflect.get(a, key), Reflect.get(b, key), depth + 1));\n };\n return same(left, right, 0);\n}\n\nexport function createRegionalCache(maxMs: number, maxValueBytes = MAX_VALUE_BYTES, options: { cache?: () => Pick<Cache, 'match' | 'put'>; now?: () => number } = {}) {\n const cache = options.cache ?? (() => caches.default);\n const now = options.now ?? (() => Date.now());\n async function regionalKey(ttl: number | undefined, identity: unknown): Promise<string | null> {\n if (!Number.isFinite(ttl) || !ttl || ttl <= 0 || ttl > maxMs || !boundedValue(identity, MAX_IDENTITY_BYTES, true)) return null;\n try {\n const text = stableStringify(identity);\n if (new TextEncoder().encode(text).byteLength > MAX_IDENTITY_BYTES) return null;\n return `https://dee-wan-cache.invalid/regional-v1/${await sha256Hex(text)}`;\n } catch { return null; }\n }\n\n async function regionalRead(key: string | null, ttl = maxMs, decimal?: DecimalConstructor): Promise<{ value: unknown; expires: number } | null> {\n if (!key) return null;\n try {\n const response = await cache().match(key);\n if (!response || response.status !== 200 || response.headers.has('set-cookie')) return null;\n const reader = response.body?.getReader();\n if (!reader) return null;\n const chunks: Uint8Array[] = [];\n let size = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const timeout = new Promise<never>((_, reject) => { timer = setTimeout(() => reject(new Error('cache body timeout')), 1000); });\n for (;;) {\n const part = await Promise.race([reader.read(), timeout]);\n if (part.done) break;\n size += part.value.byteLength;\n if (size > maxValueBytes) return null;\n chunks.push(part.value);\n }\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n void reader.cancel().catch(() => undefined);\n }\n const bytes = new Uint8Array(size);\n let offset = 0;\n for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.byteLength; }\n const text = new TextDecoder('utf-8', { fatal:true, ignoreBOM:false }).decode(bytes);\n const envelope: unknown = JSON.parse(text);\n const currentTime = now();\n if (!Number.isFinite(ttl) || ttl <= 0 || ttl > maxMs || !envelope || typeof envelope !== 'object' || !('started' in envelope) || typeof envelope.started !== 'number' || !Number.isSafeInteger(envelope.started) || envelope.started > currentTime || !('expires' in envelope) || typeof envelope.expires !== 'number' || !Number.isSafeInteger(envelope.expires) || envelope.expires <= currentTime || envelope.expires > envelope.started + ttl || envelope.expires > currentTime + ttl || !('value' in envelope)) return null;\n const value = decode(envelope.value, decimal);\n return value !== null && value !== undefined && boundedValue(value, maxValueBytes, false) && sameEncodedValue(encode(value), envelope.value) ? { value, expires: envelope.expires } : null;\n } catch { return null; }\n }\n\n async function regionalWrite(key: string | null, ttl: number | undefined, started: number, value: unknown): Promise<void> {\n if (!key || !ttl || !Number.isFinite(ttl) || ttl <= 0 || ttl > maxMs || !Number.isSafeInteger(started) || !Number.isSafeInteger(Math.floor(started + ttl)) || value === null || value === undefined || !boundedValue(value, maxValueBytes, false)) return;\n try {\n const expires = Math.floor(started + ttl);\n if (expires <= now()) return;\n const text = JSON.stringify({ started: Math.floor(started), expires, value: encode(value) });\n if (new TextEncoder().encode(text).byteLength > maxValueBytes) return;\n await cache().put(key, new Response(text, { headers: { 'Cache-Control': `public, max-age=${maxMs / 1000}` } }));\n } catch { /* Cache API is optional. */ }\n }\n\n return { regionalKey, regionalRead, regionalWrite };\n}\n\nexport const { regionalKey, regionalRead, regionalWrite } = createRegionalCache(5000);\nexport const { regionalKey: responseLeaseKey } = createRegionalCache(300_000);\n"]}
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import { isMutation, needsFreshness, matchesPath } from './chunk-JPK2AF7X.js';
|
|
2
|
+
import { createResponseWarmup } from './chunk-A4WV6RY4.js';
|
|
3
|
+
import { hasFreshnessCookie, hasFreshnessGeneration, validFreshnessHeader, hasCacheBypass } from './chunk-D2EESWMC.js';
|
|
4
|
+
import { registerRegionalDeadlineReporter } from './chunk-LHOK33GI.js';
|
|
5
|
+
import { responseLeaseKey, MAX_RESPONSE_LEASE_BYTES } from './chunk-E6OZZ5UX.js';
|
|
6
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
7
|
+
|
|
8
|
+
var scope = new AsyncLocalStorage();
|
|
9
|
+
function limitReadResponseDataUntil(deadline) {
|
|
10
|
+
const current = scope.getStore();
|
|
11
|
+
if (current) current.dataDeadline = Math.min(current.dataDeadline ?? Infinity, deadline);
|
|
12
|
+
}
|
|
13
|
+
registerRegionalDeadlineReporter(limitReadResponseDataUntil);
|
|
14
|
+
function limitReadResponseLeaseUntil(deadline) {
|
|
15
|
+
const current = scope.getStore();
|
|
16
|
+
if (!current) return;
|
|
17
|
+
if (deadline === void 0 || !Number.isFinite(deadline)) {
|
|
18
|
+
current.deadline = 0;
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
current.deadline = Math.min(current.deadline ?? Infinity, deadline);
|
|
22
|
+
}
|
|
23
|
+
var noCache = (request) => {
|
|
24
|
+
const headers = new Headers(request.headers);
|
|
25
|
+
headers.set("cache-control", "no-cache");
|
|
26
|
+
return new Request(request, { headers });
|
|
27
|
+
};
|
|
28
|
+
var bypass = (request, ignoreCacheControl) => request.body !== null || ["range", "if-match", "if-unmodified-since", "if-range"].some((name) => request.headers.has(name)) || !ignoreCacheControl && hasCacheBypass(request);
|
|
29
|
+
function entityTags(value) {
|
|
30
|
+
const tags = [];
|
|
31
|
+
let index = 0;
|
|
32
|
+
const whitespace = () => {
|
|
33
|
+
while (value[index] === " " || value[index] === " ") index++;
|
|
34
|
+
};
|
|
35
|
+
whitespace();
|
|
36
|
+
while (index < value.length) {
|
|
37
|
+
if (value.slice(index, index + 2) === "W/") index += 2;
|
|
38
|
+
if (value[index++] !== '"') return null;
|
|
39
|
+
const start = index;
|
|
40
|
+
while (index < value.length && value[index] !== '"') {
|
|
41
|
+
const code = value.charCodeAt(index++);
|
|
42
|
+
if (code < 33 || code === 127 || code > 255) return null;
|
|
43
|
+
}
|
|
44
|
+
if (value[index] !== '"') return null;
|
|
45
|
+
tags.push(value.slice(start, index++));
|
|
46
|
+
whitespace();
|
|
47
|
+
if (index === value.length) break;
|
|
48
|
+
if (value[index++] !== ",") return null;
|
|
49
|
+
whitespace();
|
|
50
|
+
if (index === value.length) return null;
|
|
51
|
+
}
|
|
52
|
+
return tags.length ? tags : null;
|
|
53
|
+
}
|
|
54
|
+
function httpDate(value) {
|
|
55
|
+
if (!value || !/^(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), \d{2} (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{4} \d{2}:\d{2}:\d{2} GMT|(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), \d{2}-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-\d{2} \d{2}:\d{2}:\d{2} GMT|(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun) (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [ \d]\d \d{2}:\d{2}:\d{2} \d{4})$/.test(value)) return NaN;
|
|
56
|
+
const time = Date.parse(value.endsWith(" GMT") ? value : `${value} GMT`);
|
|
57
|
+
if (!Number.isFinite(time)) return NaN;
|
|
58
|
+
const date = new Date(time);
|
|
59
|
+
const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
60
|
+
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
61
|
+
const day = days[date.getUTCDay()];
|
|
62
|
+
const month = months[date.getUTCMonth()];
|
|
63
|
+
const number = String(date.getUTCDate()).padStart(2, "0");
|
|
64
|
+
const clock = date.toUTCString().slice(17, 25);
|
|
65
|
+
const rfc850 = `${day}, ${number}-${month}-${String(date.getUTCFullYear() % 100).padStart(2, "0")} ${clock} GMT`;
|
|
66
|
+
const asctime = `${day?.slice(0, 3)} ${month} ${String(date.getUTCDate()).padStart(2, " ")} ${clock} ${date.getUTCFullYear()}`;
|
|
67
|
+
return value === date.toUTCString() || value === rfc850 || value === asctime ? time : NaN;
|
|
68
|
+
}
|
|
69
|
+
function conditionalHit(request, response) {
|
|
70
|
+
const condition = request.headers.get("if-none-match");
|
|
71
|
+
let matches = false;
|
|
72
|
+
if (condition !== null) {
|
|
73
|
+
if (condition.trim() === "*") matches = true;
|
|
74
|
+
else {
|
|
75
|
+
const requested = entityTags(condition);
|
|
76
|
+
const current = entityTags(response.headers.get("etag") ?? "");
|
|
77
|
+
matches = !!requested && !!current && current.length === 1 && requested.includes(current[0] ?? "");
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
const modified = httpDate(response.headers.get("last-modified"));
|
|
81
|
+
const since = httpDate(request.headers.get("if-modified-since"));
|
|
82
|
+
matches = Number.isFinite(modified) && Number.isFinite(since) && modified <= since;
|
|
83
|
+
}
|
|
84
|
+
if (!matches) return response;
|
|
85
|
+
const headers = new Headers(response.headers);
|
|
86
|
+
headers.delete("content-length");
|
|
87
|
+
void response.body?.cancel().catch(() => void 0);
|
|
88
|
+
return new Response(null, { status: 304, headers });
|
|
89
|
+
}
|
|
90
|
+
function selectedCookies(header, names) {
|
|
91
|
+
const selected = (header ?? "").split(";").map((part) => part.trimStart()).filter((part) => {
|
|
92
|
+
const separator = part.indexOf("=");
|
|
93
|
+
return separator > 0 && names.includes(part.slice(0, separator).trim());
|
|
94
|
+
});
|
|
95
|
+
return selected.length ? selected.join(";") : null;
|
|
96
|
+
}
|
|
97
|
+
function withoutCookie(header, name) {
|
|
98
|
+
if (!header) return null;
|
|
99
|
+
const value = header.split(";").filter((part) => {
|
|
100
|
+
const separator = part.indexOf("=");
|
|
101
|
+
return separator < 0 || part.slice(0, separator).trim() !== name;
|
|
102
|
+
}).join(";").trim();
|
|
103
|
+
return value || null;
|
|
104
|
+
}
|
|
105
|
+
var metadataHeader = "x-dee-wan-lease-meta";
|
|
106
|
+
async function readLease(key, ttl, permittedVary) {
|
|
107
|
+
let cached;
|
|
108
|
+
let transferred = false;
|
|
109
|
+
try {
|
|
110
|
+
cached = await caches.default.match(key);
|
|
111
|
+
if (!cached || cached.status !== 200 || !eligibleHeaders(cached.headers, permittedVary)) return null;
|
|
112
|
+
const metadata = cached.headers.get(metadataHeader);
|
|
113
|
+
if (!metadata) return null;
|
|
114
|
+
const parsed = JSON.parse(metadata);
|
|
115
|
+
if (!Array.isArray(parsed) || parsed.length !== 3) return null;
|
|
116
|
+
const [started, expires, control] = parsed;
|
|
117
|
+
const now = Date.now();
|
|
118
|
+
if (!Number.isSafeInteger(started) || !Number.isSafeInteger(expires) || started > now || expires <= now || expires > started + ttl || control !== null && typeof control !== "string") return null;
|
|
119
|
+
const headers = new Headers(cached.headers);
|
|
120
|
+
headers.delete(metadataHeader);
|
|
121
|
+
if (control === null) headers.delete("cache-control");
|
|
122
|
+
else headers.set("cache-control", control);
|
|
123
|
+
const response = new Response(cached.body, { status: cached.status, statusText: cached.statusText, headers });
|
|
124
|
+
transferred = true;
|
|
125
|
+
return { response, expires };
|
|
126
|
+
} catch {
|
|
127
|
+
return null;
|
|
128
|
+
} finally {
|
|
129
|
+
if (cached && !transferred) void cached.body?.cancel().catch(() => void 0);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function eligibleHeaders(headers, permittedVary) {
|
|
133
|
+
if (headers.has("set-cookie") || headers.has("content-encoding") || headers.has("content-disposition") || !/^application\/(?:[a-z0-9.+-]*\+)?json(?:\s*;|$)/i.test(headers.get("content-type") ?? "")) return false;
|
|
134
|
+
const vary = headers.get("vary");
|
|
135
|
+
return !vary || vary.split(",").every((name) => permittedVary.has(name.trim().toLowerCase()));
|
|
136
|
+
}
|
|
137
|
+
async function responseEntry(response, permittedVary) {
|
|
138
|
+
if (response.status !== 200 || response.headers.has(metadataHeader) || !eligibleHeaders(response.headers, permittedVary)) return null;
|
|
139
|
+
const reader = response.clone().body?.getReader();
|
|
140
|
+
if (!reader) return null;
|
|
141
|
+
const chunks = [];
|
|
142
|
+
let size = 0;
|
|
143
|
+
let timer;
|
|
144
|
+
try {
|
|
145
|
+
const timeout = new Promise((_, reject) => {
|
|
146
|
+
timer = setTimeout(() => reject(Error("body timeout")), 5e3);
|
|
147
|
+
});
|
|
148
|
+
for (; ; ) {
|
|
149
|
+
const part = await Promise.race([reader.read(), timeout]);
|
|
150
|
+
if (part.done) break;
|
|
151
|
+
size += part.value.byteLength;
|
|
152
|
+
if (size > MAX_RESPONSE_LEASE_BYTES) return null;
|
|
153
|
+
chunks.push(part.value);
|
|
154
|
+
}
|
|
155
|
+
const bytes = new Uint8Array(size);
|
|
156
|
+
let offset = 0;
|
|
157
|
+
for (const chunk of chunks) {
|
|
158
|
+
bytes.set(chunk, offset);
|
|
159
|
+
offset += chunk.byteLength;
|
|
160
|
+
}
|
|
161
|
+
const body = new TextDecoder("utf-8", { fatal: true, ignoreBOM: false }).decode(bytes);
|
|
162
|
+
JSON.parse(body);
|
|
163
|
+
const length = response.headers.get("content-length");
|
|
164
|
+
if (length !== null && (!/^(?:0|[1-9]\d*)$/.test(length) || Number(length) !== size)) return null;
|
|
165
|
+
return bytes;
|
|
166
|
+
} catch {
|
|
167
|
+
return null;
|
|
168
|
+
} finally {
|
|
169
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
170
|
+
void reader.cancel().catch(() => void 0);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function createReadResponseLease(handler, resolve) {
|
|
174
|
+
const pending = /* @__PURE__ */ new Map();
|
|
175
|
+
let foreground = 0;
|
|
176
|
+
const warming = createResponseWarmup((request, env, context) => wrapped(request, env, context), () => foreground === 0);
|
|
177
|
+
const wrapped = async (request, env, context) => {
|
|
178
|
+
const requestStarted = Date.now();
|
|
179
|
+
const requestGeneration = warming.snapshot();
|
|
180
|
+
const serve = async (input) => {
|
|
181
|
+
if (input.method !== "GET" || warming.isInternal(request)) return handler(input, env, context);
|
|
182
|
+
foreground++;
|
|
183
|
+
try {
|
|
184
|
+
return await handler(input, env, context);
|
|
185
|
+
} finally {
|
|
186
|
+
foreground--;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
const resolved = resolve(env);
|
|
190
|
+
if (!resolved) return serve(request);
|
|
191
|
+
const { config, seconds } = resolved;
|
|
192
|
+
const maxSeconds = config.maxSeconds ?? 5;
|
|
193
|
+
const refreshAhead = config.refreshAheadSeconds ?? 0;
|
|
194
|
+
if (!Number.isInteger(refreshAhead) || refreshAhead < 0 || refreshAhead > maxSeconds || !Number.isInteger(maxSeconds) || maxSeconds < 1 || maxSeconds > 300 || !Number.isInteger(seconds) || seconds <= 0 || seconds > maxSeconds || !/^[A-Za-z0-9_-]+$/.test(config.freshnessCookie)) return serve(request);
|
|
195
|
+
if (config.cookieNames !== void 0 && (!Array.isArray(config.cookieNames) || config.cookieNames.length === 0 || !config.cookieNames.every((name) => typeof name === "string" && /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name)) || new Set(config.cookieNames).size !== config.cookieNames.length || !config.credentialHeaders.some((name) => name.toLowerCase() === "cookie") || config.freshnessCookieMode === "generation" && !config.cookieNames.includes(config.freshnessCookie))) return serve(request);
|
|
196
|
+
const generationMode = config.freshnessCookieMode === "generation" && config.credentialHeaders.some((name) => name.toLowerCase() === "cookie");
|
|
197
|
+
if (isMutation(request.method)) {
|
|
198
|
+
const response2 = await handler(request, env, context);
|
|
199
|
+
if (response2.status < 200 || response2.status >= 300 || !needsFreshness(request.method, new URL(request.url).pathname, config.freshnessCookieExcludedPaths)) return response2;
|
|
200
|
+
warming.invalidate();
|
|
201
|
+
const headers = new Headers(response2.headers);
|
|
202
|
+
headers.append("set-cookie", `${config.freshnessCookie}=${generationMode ? crypto.randomUUID() : "1"}; Max-Age=${maxSeconds}; Path=/; HttpOnly; SameSite=Lax${new URL(request.url).protocol === "https:" ? "; Secure" : ""}`);
|
|
203
|
+
return new Response(response2.body, { status: response2.status, statusText: response2.statusText, headers });
|
|
204
|
+
}
|
|
205
|
+
if (request.method !== "GET") return serve(request);
|
|
206
|
+
if (hasFreshnessCookie(request, config.freshnessCookie) && (!generationMode || !hasFreshnessGeneration(request, config.freshnessCookie))) return serve(noCache(request));
|
|
207
|
+
if (config.freshnessHeader !== void 0 && !validFreshnessHeader(config.freshnessHeader)) return serve(noCache(request));
|
|
208
|
+
const forceSource = config.freshnessHeader !== void 0 && request.headers.has(config.freshnessHeader);
|
|
209
|
+
const url = new URL(request.url);
|
|
210
|
+
const headerValue = (name) => name.toLowerCase() === "cookie" && config.cookieNames !== void 0 ? selectedCookies(request.headers.get("cookie"), config.cookieNames) : request.headers.get(name);
|
|
211
|
+
const hasCredential = (name) => {
|
|
212
|
+
const value = headerValue(name);
|
|
213
|
+
if (name.toLowerCase() !== "cookie" || config.cookieNames === void 0) return !!value?.trim();
|
|
214
|
+
return (value ?? "").split(";").some((pair) => {
|
|
215
|
+
const separator = pair.indexOf("=");
|
|
216
|
+
return separator > 0 && pair.slice(0, separator).trim() !== config.freshnessCookie && !!pair.slice(separator + 1).trim();
|
|
217
|
+
});
|
|
218
|
+
};
|
|
219
|
+
if (bypass(request, config.ignoreRequestCacheControl === true) || !matchesPath(url.pathname, config.paths) || config.bypassQueryParams?.some((name) => url.searchParams.has(name)) || !config.credentialHeaders.some(hasCredential)) return serve(forceSource ? noCache(request) : request);
|
|
220
|
+
const identity = resolved.identity();
|
|
221
|
+
if (!identity) return serve(noCache(request));
|
|
222
|
+
const names = [...new Set([...config.credentialHeaders, ...config.varyHeaders].map((name) => name.toLowerCase()))].sort();
|
|
223
|
+
const permittedVary = new Set(names);
|
|
224
|
+
const ttl = seconds * 1e3;
|
|
225
|
+
const key = await responseLeaseKey(ttl, [identity[0], request.method, request.url, ...identity.slice(1), names.map((name) => [name, headerValue(name)])]);
|
|
226
|
+
if (!key) return serve(noCache(request));
|
|
227
|
+
const cached = forceSource ? null : await readLease(key, ttl, permittedVary);
|
|
228
|
+
const warmOptions = config.warmup;
|
|
229
|
+
const warmGroup = warmOptions && typeof warmOptions.scopeHeader === "string" && /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(warmOptions.scopeHeader) && config.varyHeaders.some((name) => name.toLowerCase() === warmOptions.scopeHeader.toLowerCase()) ? await responseLeaseKey(ttl, ["response-warmup-group", identity, names.map((name) => [name, headerValue(name)]), request.headers.get(warmOptions.scopeHeader)]) : null;
|
|
230
|
+
const credentialGroup = warmOptions?.catalogScope === "credential" && warmGroup && !config.credentialHeaders.some((name) => name.toLowerCase() === warmOptions.scopeHeader.toLowerCase()) ? await responseLeaseKey(ttl, ["response-warmup-credential-group", identity, names.filter((name) => name !== warmOptions.scopeHeader.toLowerCase()).map((name) => [name, name === "cookie" ? withoutCookie(headerValue(name), config.freshnessCookie) : headerValue(name)])]) : null;
|
|
231
|
+
const eligible = (target) => matchesPath(target.pathname, config.paths) && !config.bypassQueryParams?.some((name) => target.searchParams.has(name));
|
|
232
|
+
const scheduleWarm = (response2) => {
|
|
233
|
+
let transferred = false;
|
|
234
|
+
try {
|
|
235
|
+
if (!warmOptions || !warmGroup || warming.isInternal(request) || !warming.current(requestGeneration)) return;
|
|
236
|
+
const wait = context && typeof context === "object" ? Reflect.get(context, "waitUntil") : void 0;
|
|
237
|
+
if (typeof wait !== "function") return;
|
|
238
|
+
const task = warming.start(warmOptions, request, response2, identity, warmGroup, eligible, env, context, config.freshnessHeader, credentialGroup ?? void 0);
|
|
239
|
+
transferred = true;
|
|
240
|
+
Reflect.apply(wait, context, [task]);
|
|
241
|
+
} catch {
|
|
242
|
+
} finally {
|
|
243
|
+
if (!transferred) void response2.body?.cancel().catch(() => void 0);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
const fillResponse = async (response2, lease2, started, allowed, beforePut) => {
|
|
247
|
+
if (lease2.deadline === void 0 || !Number.isFinite(lease2.deadline)) return;
|
|
248
|
+
let warmResponse;
|
|
249
|
+
if (warmOptions && warmGroup && !warming.isInternal(request) && typeof waitUntil === "function") {
|
|
250
|
+
try {
|
|
251
|
+
warmResponse = response2.clone();
|
|
252
|
+
} catch {
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const expires = Math.floor(Math.min(started + ttl, lease2.deadline, lease2.dataDeadline ?? Infinity));
|
|
256
|
+
try {
|
|
257
|
+
const entry = await responseEntry(response2, permittedVary);
|
|
258
|
+
if (entry && beforePut) await beforePut;
|
|
259
|
+
if (entry && Number.isSafeInteger(expires) && expires > Date.now() && allowed() && warming.current(requestGeneration) && warming.allowed(request)) {
|
|
260
|
+
warming.verify(request);
|
|
261
|
+
if (warmResponse) {
|
|
262
|
+
const owned = warmResponse;
|
|
263
|
+
warmResponse = void 0;
|
|
264
|
+
scheduleWarm(owned);
|
|
265
|
+
}
|
|
266
|
+
const headers = new Headers(response2.headers);
|
|
267
|
+
headers.set(metadataHeader, JSON.stringify([Math.floor(started), expires, headers.get("cache-control")]));
|
|
268
|
+
headers.set("cache-control", "public, max-age=300");
|
|
269
|
+
await caches.default.put(key, new Response(entry, { status: response2.status, statusText: response2.statusText, headers }));
|
|
270
|
+
}
|
|
271
|
+
} catch {
|
|
272
|
+
} finally {
|
|
273
|
+
if (warmResponse) void warmResponse.body?.cancel().catch(() => void 0);
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
const waitUntil = context && typeof context === "object" ? Reflect.get(context, "waitUntil") : void 0;
|
|
277
|
+
if (cached) {
|
|
278
|
+
warming.verify(request);
|
|
279
|
+
if (warmOptions && warmGroup && !warming.isInternal(request) && typeof waitUntil === "function") {
|
|
280
|
+
try {
|
|
281
|
+
scheduleWarm(cached.response.clone());
|
|
282
|
+
} catch {
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (refreshAhead > 0 && refreshAhead <= seconds && cached.expires - Date.now() <= refreshAhead * 1e3 && typeof waitUntil === "function" && !pending.has(key)) {
|
|
286
|
+
const refresh = { valid: true, task: Promise.resolve() };
|
|
287
|
+
let accepted = false;
|
|
288
|
+
refresh.task = Promise.resolve().then(async () => {
|
|
289
|
+
if (!accepted) return;
|
|
290
|
+
const started = Date.now();
|
|
291
|
+
const headers = new Headers(request.headers);
|
|
292
|
+
for (const name of ["range", "if-match", "if-unmodified-since", "if-range", "if-none-match", "if-modified-since"]) headers.delete(name);
|
|
293
|
+
headers.set("cache-control", "no-cache");
|
|
294
|
+
if (config.freshnessHeader !== void 0) headers.set(config.freshnessHeader, "1");
|
|
295
|
+
const source2 = new Request(request.url, { method: "GET", headers, signal: new AbortController().signal });
|
|
296
|
+
const lease2 = {};
|
|
297
|
+
try {
|
|
298
|
+
const response2 = await scope.run(lease2, () => handler(source2, env, context));
|
|
299
|
+
try {
|
|
300
|
+
await fillResponse(response2, lease2, started, () => refresh.valid);
|
|
301
|
+
} finally {
|
|
302
|
+
void response2.body?.cancel().catch(() => void 0);
|
|
303
|
+
}
|
|
304
|
+
} catch {
|
|
305
|
+
}
|
|
306
|
+
}).finally(() => {
|
|
307
|
+
if (pending.get(key) === refresh) pending.delete(key);
|
|
308
|
+
});
|
|
309
|
+
pending.set(key, refresh);
|
|
310
|
+
try {
|
|
311
|
+
Reflect.apply(waitUntil, context, [refresh.task]);
|
|
312
|
+
accepted = true;
|
|
313
|
+
} catch {
|
|
314
|
+
pending.delete(key);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return conditionalHit(request, cached.response);
|
|
318
|
+
}
|
|
319
|
+
const priorRefresh = pending.get(key);
|
|
320
|
+
if (priorRefresh) priorRefresh.valid = false;
|
|
321
|
+
const lease = {};
|
|
322
|
+
const source = noCache(request);
|
|
323
|
+
if (config.freshnessHeader !== void 0) source.headers.set(config.freshnessHeader, "1");
|
|
324
|
+
const response = await scope.run(lease, () => serve(source));
|
|
325
|
+
const fill = fillResponse(response, lease, requestStarted, () => true, priorRefresh?.task);
|
|
326
|
+
try {
|
|
327
|
+
if (!warming.isInternal(request) && typeof waitUntil === "function") {
|
|
328
|
+
Reflect.apply(waitUntil, context, [fill]);
|
|
329
|
+
return response;
|
|
330
|
+
}
|
|
331
|
+
} catch {
|
|
332
|
+
}
|
|
333
|
+
await fill;
|
|
334
|
+
return response;
|
|
335
|
+
};
|
|
336
|
+
return wrapped;
|
|
337
|
+
}
|
|
338
|
+
function wrapReadResponseLease(handler, options) {
|
|
339
|
+
return createReadResponseLease(handler, () => {
|
|
340
|
+
if (![options.namespace, options.deployment, options.database].every((value) => typeof value === "string" && value.trim().length > 0)) return null;
|
|
341
|
+
const identity = { ...options };
|
|
342
|
+
delete identity.warmup;
|
|
343
|
+
return { config: options, seconds: options.seconds, identity: () => ["response-lease-v1", identity] };
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
var proofHeader = "x-dee-wan-read-lease-deadline";
|
|
347
|
+
function withoutProof(request) {
|
|
348
|
+
if (!request.headers.has(proofHeader)) return request;
|
|
349
|
+
const headers = new Headers(request.headers);
|
|
350
|
+
headers.delete(proofHeader);
|
|
351
|
+
return new Request(request, { headers });
|
|
352
|
+
}
|
|
353
|
+
function responseWithProof(response, deadline) {
|
|
354
|
+
if (!response.headers.has(proofHeader) && deadline === void 0) return response;
|
|
355
|
+
const headers = new Headers(response.headers);
|
|
356
|
+
headers.delete(proofHeader);
|
|
357
|
+
if (deadline !== void 0) headers.set(proofHeader, String(Math.floor(deadline)));
|
|
358
|
+
return new Response(response.body, { status: response.status, statusText: response.statusText, headers, ...response.webSocket ? { webSocket: response.webSocket } : {} });
|
|
359
|
+
}
|
|
360
|
+
function wrapReadResponseLeaseOrigin(handler) {
|
|
361
|
+
return async (request, env, context) => {
|
|
362
|
+
const lease = {};
|
|
363
|
+
const response = await scope.run(lease, () => handler(withoutProof(request), env, context));
|
|
364
|
+
const deadline = lease.deadline;
|
|
365
|
+
const type = response.headers.get("content-type") ?? "";
|
|
366
|
+
if (request.method !== "GET" || response.status !== 200 || response.headers.has("set-cookie") || !/^application\/(?:[a-z0-9.+-]*\+)?json(?:\s*;|$)/i.test(type) || deadline === void 0 || !Number.isFinite(deadline) || deadline <= Date.now()) return responseWithProof(response);
|
|
367
|
+
return responseWithProof(response, Math.min(deadline, lease.dataDeadline ?? Infinity));
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
async function forwardReadLease(request, service) {
|
|
371
|
+
let forwarded = withoutProof(request);
|
|
372
|
+
if (request.method === "GET") {
|
|
373
|
+
const headers = new Headers(forwarded.headers);
|
|
374
|
+
headers.set("accept-encoding", "identity");
|
|
375
|
+
forwarded = new Request(forwarded, { headers });
|
|
376
|
+
}
|
|
377
|
+
const response = await service.fetch(forwarded);
|
|
378
|
+
const raw = response.headers.get(proofHeader);
|
|
379
|
+
if (raw && /^\d+$/.test(raw)) {
|
|
380
|
+
const deadline = Number(raw);
|
|
381
|
+
if (Number.isSafeInteger(deadline) && deadline > Date.now()) limitReadResponseLeaseUntil(deadline);
|
|
382
|
+
}
|
|
383
|
+
return responseWithProof(response);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export { createReadResponseLease, forwardReadLease, limitReadResponseLeaseUntil, wrapReadResponseLease, wrapReadResponseLeaseOrigin };
|
|
387
|
+
//# sourceMappingURL=chunk-HGAUU4EU.js.map
|
|
388
|
+
//# sourceMappingURL=chunk-HGAUU4EU.js.map
|