astro
Version:
Astro is a modern site builder with web best practices, performance, and DX front-of-mind.
77 lines (76 loc) • 2.33 kB
JavaScript
// @ts-expect-error
import { fsDenyGlob, safeModulePaths, viteFSConfig } from "astro:assets";
import { readFile } from "node:fs/promises";
import os from "node:os";
import { isFileLoadingAllowed } from "vite";
import { handleImageRequest, loadRemoteImage } from "./shared.js";
function replaceFileSystemReferences(src) {
return os.platform().includes("win32") ? src.replace(/^\/@fs\//, "") : src.replace(/^\/@fs/, "");
}
async function loadLocalImage(src, url) {
let returnValue;
let fsPath;
// Vite uses /@fs/ to denote filesystem access, but we need to convert that to a real path to load it
if (src.startsWith("/@fs/")) {
fsPath = replaceFileSystemReferences(src);
}
// Vite only uses the fs config, but the types ask for the full config
if (fsPath && isFileLoadingAllowed({
fsDenyGlob,
server: { fs: viteFSConfig },
safeModulePaths
}, fsPath)) {
try {
returnValue = await readFile(fsPath);
} catch {
returnValue = undefined;
}
// If we couldn't load it directly, try loading it through Vite as a fallback, which will also respect Vite's fs rules
if (!returnValue) {
try {
const res = await fetch(new URL(src, url));
if (res.ok) {
returnValue = Buffer.from(await res.arrayBuffer());
}
} catch {
returnValue = undefined;
}
}
} else {
// Otherwise, we'll assume it's a local URL and try to load it via fetch
const sourceUrl = new URL(src, url.origin);
// This is only allowed if this is the same origin
if (sourceUrl.origin !== url.origin) {
return { kind: "invalid-path" };
}
const buffer = await loadRemoteImage(sourceUrl);
return buffer ? {
kind: "loaded",
buffer
} : { kind: "failed" };
}
return returnValue ? {
kind: "loaded",
buffer: returnValue
} : { kind: "failed" };
}
/**
* Endpoint used in dev and SSR to serve optimized images by the base image services
*/
export const GET = async ({ request, logger }) => {
if (!import.meta.env.DEV) {
logger.error("The dev image endpoint can only be used in dev mode.");
return new Response("Invalid endpoint", { status: 500 });
}
try {
return await handleImageRequest({
request,
loadLocalImage,
logger
});
} catch (err) {
const message = `Could not process image request: ${err}`;
logger.error(message);
return new Response(message, { status: 500 });
}
};