@scayle/storefront-nuxt
Version:
Nuxt integration for the SCAYLE Commerce Engine and Storefront API
110 lines (109 loc) • 3.46 kB
JavaScript
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}`);
}
}