@push.rocks/webrequest
Version:
Modern, fetch-compatible web request library with intelligent HTTP caching, retry strategies, and fault tolerance.
145 lines • 8.98 kB
JavaScript
/**
* HTTP Cache Header parsing and utilities
* Implements RFC 7234 (HTTP Caching)
*/
/**
* Parse Cache-Control header into metadata
*/
export function parseCacheControl(cacheControlHeader) {
const metadata = {
maxAge: 0,
immutable: false,
noCache: false,
noStore: false,
mustRevalidate: false,
};
if (!cacheControlHeader) {
return metadata;
}
const directives = cacheControlHeader
.toLowerCase()
.split(',')
.map((d) => d.trim());
for (const directive of directives) {
if (directive === 'no-cache') {
metadata.noCache = true;
}
else if (directive === 'no-store') {
metadata.noStore = true;
}
else if (directive === 'immutable') {
metadata.immutable = true;
}
else if (directive === 'must-revalidate') {
metadata.mustRevalidate = true;
}
else if (directive.startsWith('max-age=')) {
const maxAge = parseInt(directive.split('=')[1], 10);
if (!isNaN(maxAge)) {
metadata.maxAge = maxAge * 1000; // Convert to milliseconds
}
}
}
return metadata;
}
/**
* Parse Expires header into timestamp
*/
export function parseExpires(expiresHeader) {
if (!expiresHeader) {
return undefined;
}
try {
const date = new Date(expiresHeader);
return date.getTime();
}
catch {
return undefined;
}
}
/**
* Extract cache metadata from response headers
*/
export function extractCacheMetadata(headers) {
const cacheControl = headers.get('cache-control');
const expires = headers.get('expires');
const etag = headers.get('etag');
const lastModified = headers.get('last-modified');
const metadata = parseCacheControl(cacheControl);
// If no max-age from Cache-Control, try Expires header
if (metadata.maxAge === 0 && expires) {
const expiresTime = parseExpires(expires);
if (expiresTime) {
metadata.maxAge = Math.max(0, expiresTime - Date.now());
}
}
return {
maxAge: metadata.maxAge || 0,
etag: etag || undefined,
lastModified: lastModified || undefined,
immutable: metadata.immutable || false,
noCache: metadata.noCache || false,
noStore: metadata.noStore || false,
mustRevalidate: metadata.mustRevalidate || false,
};
}
/**
* Check if a cached response is still fresh
*/
export function isFresh(cacheEntry, metadata) {
// no-store means never cache
if (metadata.noStore) {
return false;
}
// If immutable, it's always fresh
if (metadata.immutable) {
return true;
}
const age = Date.now() - cacheEntry.timestamp;
const maxAge = cacheEntry.maxAge || metadata.maxAge || 0;
// If no max-age specified, consider stale
if (maxAge === 0) {
return false;
}
return age < maxAge;
}
/**
* Check if revalidation is required
*/
export function requiresRevalidation(metadata) {
return metadata.noCache || metadata.mustRevalidate;
}
/**
* Create conditional request headers for revalidation
*/
export function createConditionalHeaders(cacheEntry) {
const headers = {};
if (cacheEntry.etag) {
headers['if-none-match'] = cacheEntry.etag;
}
if (cacheEntry.lastModified) {
headers['if-modified-since'] = cacheEntry.lastModified;
}
return headers;
}
/**
* Convert Headers object to plain object for storage
*/
export function headersToObject(headers) {
const obj = {};
headers.forEach((value, key) => {
obj[key] = value;
});
return obj;
}
/**
* Convert plain object back to Headers
*/
export function objectToHeaders(obj) {
const headers = new Headers();
Object.entries(obj).forEach(([key, value]) => {
headers.set(key, value);
});
return headers;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUuaGVhZGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2NhY2hlL2NhY2hlLmhlYWRlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBSUg7O0dBRUc7QUFDSCxNQUFNLFVBQVUsaUJBQWlCLENBQy9CLGtCQUFpQztJQUVqQyxNQUFNLFFBQVEsR0FBNEI7UUFDeEMsTUFBTSxFQUFFLENBQUM7UUFDVCxTQUFTLEVBQUUsS0FBSztRQUNoQixPQUFPLEVBQUUsS0FBSztRQUNkLE9BQU8sRUFBRSxLQUFLO1FBQ2QsY0FBYyxFQUFFLEtBQUs7S0FDdEIsQ0FBQztJQUVGLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQ3hCLE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7SUFFRCxNQUFNLFVBQVUsR0FBRyxrQkFBa0I7U0FDbEMsV0FBVyxFQUFFO1NBQ2IsS0FBSyxDQUFDLEdBQUcsQ0FBQztTQUNWLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFFeEIsS0FBSyxNQUFNLFNBQVMsSUFBSSxVQUFVLEVBQUUsQ0FBQztRQUNuQyxJQUFJLFNBQVMsS0FBSyxVQUFVLEVBQUUsQ0FBQztZQUM3QixRQUFRLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQztRQUMxQixDQUFDO2FBQU0sSUFBSSxTQUFTLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDcEMsUUFBUSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7UUFDMUIsQ0FBQzthQUFNLElBQUksU0FBUyxLQUFLLFdBQVcsRUFBRSxDQUFDO1lBQ3JDLFFBQVEsQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDO1FBQzVCLENBQUM7YUFBTSxJQUFJLFNBQVMsS0FBSyxpQkFBaUIsRUFBRSxDQUFDO1lBQzNDLFFBQVEsQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDO1FBQ2pDLENBQUM7YUFBTSxJQUFJ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