UNPKG

@paroicms/server

Version:
168 lines 6.97 kB
import { ApiError, applyPixelRatioToResizeRule, generateImageSlug, } from "@paroicms/public-server-lib"; import { parseSizeName } from "@paroicms/server-image-cache-engine"; import { HTTP_MAX_AGE } from "../../express/http-constants.js"; import { getRouteParameter, serve301Redirect, serve304NotModified, } from "../../express/http-helpers.js"; import { makeUrlOfImageVariant, makeUrlOfMediaFile, makeUrlOfUnversionedImageVariant, } from "../../helpers/url-helpers.js"; import { parseImageRawSizeNameAndExt, parseImageRenderedResizeRuleAndExt, } from "./_media-serve-helpers.js"; export async function serveFilecontroller(siteContext, httpContext, routeParams) { const { req, res } = httpContext; const mediaId = getRouteParameter(routeParams, "mediaId"); const nameAndExt = getRouteParameter(routeParams, "nameAndExt"); const cacheControl = "max-age=0"; const ifNoneMatch = req.headers["if-none-match"]; const media = await siteContext.mediaStorage.getMediaWithBinary(mediaId); if (!media) throw new ApiError(`media '${mediaId}' not found`, 404); if (media.resourceVersion === ifNoneMatch) { return serve304NotModified(httpContext, { cacheControl, etag: media.resourceVersion, }); } const { url, filename } = makeUrlOfMediaFile(siteContext, { mediaId, mediaType: media.mediaType, originalName: media.originalName }, { returnObj: true }); if (filename !== nameAndExt) return serve301Redirect(httpContext, url); res.append("Cache-Control", cacheControl); res.append("Etag", media.resourceVersion); res.append("Content-Type", media.mediaType); res.append("Content-Length", media.binaryFile.byteLength.toString()); res.send(media.binaryFile); } export async function serveCacheImageController(siteContext, httpContext, routeParams) { const mediaId = getRouteParameter(routeParams, "mediaId"); const resourceVersion = getRouteParameter(routeParams, "resourceVersion"); const nameAndExt = getRouteParameter(routeParams, "nameAndExt"); if (resourceVersion === "unversioned") { await serveUnversionedFTextImage(siteContext, httpContext, { mediaId, nameAndExt, }); return; } const { req, res } = httpContext; const cacheControl = `public, max-age=${HTTP_MAX_AGE}, immutable`; const ifNoneMatch = req.headers["if-none-match"]; const parsed = parseImageRawSizeNameAndExt(nameAndExt); if (!parsed) throw new ApiError(404); const { rawSizeName, mediaType } = parsed; const { width: rawWidth, height: rawHeight } = parseSizeName(rawSizeName); const file = await siteContext.imageCache.getImageVariantWithBinary({ mediaId, mediaType, rawWidth, rawHeight, }); if (!file) throw new ApiError(404); if (ifNoneMatch === file.resourceVersion) { return serve304NotModified(httpContext, { cacheControl, etag: file.resourceVersion, }); } const newUrl = makeUrlOfImageVariant(siteContext, { mediaId, mediaType: file.mediaType, rawSizeName, resourceVersion: file.resourceVersion, slug: file.slug, }, { returnObj: true }); if (file.resourceVersion !== resourceVersion || newUrl.filename !== nameAndExt) { return serve301Redirect(httpContext, newUrl.url); } res.append("Cache-Control", cacheControl); res.append("Etag", file.resourceVersion); res.append("Content-Type", file.mediaType); res.append("Content-Length", file.binaryFile.byteLength.toString()); res.send(file.binaryFile); } async function serveUnversionedFTextImage(siteContext, httpContext, routeParams) { const { mediaId, nameAndExt } = routeParams; const parsed = parseImageRenderedResizeRuleAndExt(nameAndExt); if (!parsed) throw new ApiError(404); const { resizeRule, mediaType } = parsed; if (!siteContext.themeConf.fTextImageResizeRules.includes(resizeRule)) throw new ApiError(404); if (mediaType !== "image/webp") throw new ApiError(404); await serveUnversionedImage(siteContext, httpContext, { mediaId, mediaType, ownerHandle: `fText:${resizeRule}`, isHandleReusable: true, resizeRule, ensureUrlFilename: nameAndExt, }); } export async function serveUnversionedImage(siteContext, httpContext, options) { const { req, res } = httpContext; const cacheControl = "max-age=0"; const ifNoneMatch = req.headers["if-none-match"]; const { mediaId, mediaType, ownerHandle, isHandleReusable, resizeRule, ensureUrlFilename } = options; const rawResizeR = applyPixelRatioToResizeRule(resizeRule, siteContext.themeConf.pixelRatio); let variant = await siteContext.imageCache.getImageVariantWithBinaryByOwner({ mediaId, mediaType, ownerHandle, rawResizeR, }); if (variant) { if (ifNoneMatch === variant.resourceVersion) { return serve304NotModified(httpContext, { cacheControl, etag: variant.resourceVersion, }); } } else { variant = await createUnversionedImageVariant(siteContext, { ownerHandle, isHandleReusable, mediaId, mediaType, rawResizeR, }); if (!variant) throw new ApiError(404); } if (ensureUrlFilename) { const newUrl = makeUrlOfUnversionedImageVariant(siteContext, { mediaId, mediaType: variant.mediaType, resizeRule, slug: variant.slug, }, { returnObj: true }); if (newUrl.filename !== ensureUrlFilename) { return serve301Redirect(httpContext, newUrl.url); } } res.append("Cache-Control", cacheControl); res.append("Etag", variant.resourceVersion); res.append("Content-Type", variant.mediaType); res.append("Content-Length", variant.binaryFile.byteLength.toString()); res.send(variant.binaryFile); } async function createUnversionedImageVariant(siteContext, options) { const { ownerHandle, isHandleReusable, mediaId, mediaType, rawResizeR } = options; const media = await siteContext.mediaStorage.getMedia({ mediaId }); if (!media || media.kind !== "image") return; const variant = await siteContext.imageCache.makeImageAvailable({ ownerHandle, isHandleReusable, rawResizeR, mediaType, sourceImage: { mediaId: media.id, mediaType: media.mediaType, rawWidth: media.rawWidth, rawHeight: media.rawHeight, slug: generateImageSlug(media.originalName), }, canBeRetrievedByOwner: true, }); return await siteContext.imageCache.getImageVariantWithBinary(variant); } //# sourceMappingURL=media-serve.controller.js.map