edgerender
Version:
Render at the edge
120 lines • 4.6 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Assets = void 0;
const lite_1 = __importDefault(require("mime/lite"));
const utils_1 = require("./utils");
const response_1 = require("./response");
class Assets {
path;
log;
prefix;
manifest;
kv_namespace;
security_headers;
headers;
constructor(config, security_headers, log) {
this.path = config.path || '/assets/';
if (!this.path.startsWith('/') || !this.path.endsWith('/')) {
throw Error('static path must start and end with "/"');
}
this.prefix = new RegExp(`^${utils_1.escape_regex(this.path)}`);
if (typeof config.content_manifest === 'string') {
this.manifest = JSON.parse(config.content_manifest);
}
else {
this.manifest = null;
}
this.kv_namespace = config.kv_namespace;
this.security_headers = security_headers;
this.headers = {
'cache-control': config.cache_control || 'public, max-age=86400',
};
this.log = log;
}
is_static_path(pathname) {
return pathname.startsWith(this.path);
}
async response(request, pathname) {
// stripe leading slashes and "assets to match the format in static_manifest
const asset_path = pathname.replace(this.prefix, '');
let content_key;
if (this.manifest) {
content_key = this.manifest[asset_path];
if (!content_key) {
throw this.not_found_error(pathname);
}
}
else {
content_key = asset_path;
}
if (this.kv_namespace == undefined) {
console.warn('KV namespace not defined, static assets not available');
throw this.not_found_error(pathname);
}
const body = await this.kv_namespace.get(content_key, 'arrayBuffer');
if (body === null) {
// if we have a manifest then it's unexpected that the key doesn't exist, otherwise it's just a 404
if (this.manifest) {
// TODO log to sentry
console.error(`content_key "${content_key}" found for asset_path "${pathname}", but no value in the KV store`);
}
throw this.not_found_error(pathname);
}
else {
return {
body,
mime_type: this.mime_type(pathname),
headers: this.headers,
};
}
}
not_found_error(pathname) {
return new response_1.HttpError(404, `static asset "${pathname}" not found`);
}
async cached_proxy(request, url, custom_mime_type = null) {
const cache_key = `cached-file:${url}`;
if (this.kv_namespace == undefined) {
throw new Error(`KV namespace not defined, static assets not available`);
}
const cache_value = await this.kv_namespace.getWithMetadata(cache_key, 'stream');
if (cache_value.value) {
const metadata = cache_value.metadata || {};
return {
body: cache_value.value,
mime_type: custom_mime_type || metadata.mime_type || response_1.MimeTypes.octetStream,
headers: this.headers,
};
}
if (this.log) {
console.debug(`"${url}" not yet cached, downloading`);
}
const r = await fetch(url, request);
if (r.status != 200) {
throw new response_1.HttpError(502, `Error getting "${url}", upstream response: ${r.status}`);
}
const mime_type = custom_mime_type || r.headers.get('content-type') || response_1.MimeTypes.octetStream;
const body = await r.arrayBuffer();
await this.kv_namespace.put(cache_key, body, { expirationTtl: 3600 * 24 * 30, metadata: { mime_type } });
return { body, mime_type, headers: this.headers };
}
mime_type(pathname) {
const m = pathname.toLocaleLowerCase().match(/\.([a-z]+)$/);
let mime_type = undefined;
if (m) {
const ext = m[0];
mime_type = known_mime_types[ext];
if (!mime_type) {
mime_type = lite_1.default.getType(ext);
}
}
return mime_type || response_1.MimeTypes.octetStream;
}
}
exports.Assets = Assets;
const known_mime_types = {
'.ico': response_1.MimeTypes.ico,
};
//# sourceMappingURL=assets.js.map