UNPKG

@scayle/storefront-nuxt

Version:

Nuxt integration for the SCAYLE Commerce Engine and Storefront API

110 lines (109 loc) 3.46 kB
import { sendRedirect, getRequestURL } from "h3"; import { UnstorageCache } from "@scayle/storefront-core"; import { getRedirectLookupUrls, getTargetLocation } from "./redirects.utils.js"; import { useRuntimeConfig } from "#imports"; const REDIS_REDIRECT_PREFIX = ":REDIRECT"; const REDIRECT_NOT_SET = "REDIRECT_NOT_SET"; const REDIRECT_CACHE_TTL = 120; async function fetchRedirectWithCache(sourceUrl, storefrontAPIClient, redirectCache, log, waitUntil) { try { const cachedResult = await redirectCache.get(sourceUrl); if (cachedResult) { if (cachedResult === REDIRECT_NOT_SET) { return null; } return cachedResult; } } catch (e) { log.error("Error fetching redirect from cache", e); } log.debug("No cached result for redirect; querying SAPI"); let sapiResult; try { sapiResult = await storefrontAPIClient.redirects.post(sourceUrl); } catch (error) { log.error( `Error: Failed to fetch redirects ... ${error} for sourceURL: ${sourceUrl}` ); return null; } const isValidRedirect = (redirect) => { return redirect && redirect?.source && redirect?.target && redirect.source !== redirect.target; }; if (!sapiResult || !isValidRedirect(sapiResult)) { waitUntil( redirectCache.set(sourceUrl, REDIRECT_NOT_SET, REDIRECT_CACHE_TTL).catch((e) => log.error("Error saving redirect to cache", e)) ); return null; } waitUntil( redirectCache.set( sapiResult.source, { target: sapiResult.target, statusCode: sapiResult.statusCode }, REDIRECT_CACHE_TTL ).catch((e) => log.error("Error saving redirect to cache", e)) ); return sapiResult; } export async function useRedirects(event) { if (!event.context.$rpcContext) { return; } const config = useRuntimeConfig(); const $storefrontConfig = config.storefront; const options = $storefrontConfig.redirects; const url = getRequestURL(event, { xForwardedProto: true, xForwardedHost: true }); const log = event.context.$rpcContext.log.space("sfc").space("redirects"); const shopCache = event.context.$cache; const redirectCache = new UnstorageCache( shopCache.storage, shopCache.prefix + REDIS_REDIRECT_PREFIX ); const sapiClient = event.context.$rpcContext.sapiClient; const queryParamWhitelist = new Set(options?.queryParamWhitelist ?? []); log.debug(`Querying redirect for ${url.toString()}`); const { relativeSourceUrl, absoluteSourceUrl } = getRedirectLookupUrls( url, queryParamWhitelist ); const [relativeRedirect, absoluteRedirect] = await Promise.all([ fetchRedirectWithCache( relativeSourceUrl, sapiClient, redirectCache, log, event.waitUntil ), fetchRedirectWithCache( absoluteSourceUrl, sapiClient, redirectCache, log, event.waitUntil ) ]); if (relativeRedirect && absoluteRedirect) { log.info(`There are multiple valid redirects for: ${url.toString()}`); } const redirect = relativeRedirect ?? absoluteRedirect; if (!redirect) { log.debug(`There are no valid redirects for: ${url.toString()}`); return; } try { log.debug(`Redirecting to ${redirect.target}`); await sendRedirect( event, getTargetLocation(url, redirect.target, queryParamWhitelist), redirect.statusCode ); } catch (error) { log.error(`Error: Failed to execute redirect ... ${error}`); } }