402 lines
19 KiB
JavaScript
402 lines
19 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
0 && (module.exports = {
|
|
normalizeVercelUrl: null,
|
|
interpolateDynamicPath: null,
|
|
getUtils: null
|
|
});
|
|
function _export(target, all) {
|
|
for(var name in all)Object.defineProperty(target, name, {
|
|
enumerable: true,
|
|
get: all[name]
|
|
});
|
|
}
|
|
_export(exports, {
|
|
normalizeVercelUrl: function() {
|
|
return normalizeVercelUrl;
|
|
},
|
|
interpolateDynamicPath: function() {
|
|
return interpolateDynamicPath;
|
|
},
|
|
getUtils: function() {
|
|
return getUtils;
|
|
}
|
|
});
|
|
const _url = require("url");
|
|
const _normalizelocalepath = require("../shared/lib/i18n/normalize-locale-path");
|
|
const _pathmatch = require("../shared/lib/router/utils/path-match");
|
|
const _routeregex = require("../shared/lib/router/utils/route-regex");
|
|
const _routematcher = require("../shared/lib/router/utils/route-matcher");
|
|
const _preparedestination = require("../shared/lib/router/utils/prepare-destination");
|
|
const _acceptheader = require("./accept-header");
|
|
const _detectlocalecookie = require("../shared/lib/i18n/detect-locale-cookie");
|
|
const _detectdomainlocale = require("../shared/lib/i18n/detect-domain-locale");
|
|
const _denormalizepagepath = require("../shared/lib/page-path/denormalize-page-path");
|
|
const _cookie = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/cookie"));
|
|
const _constants = require("../shared/lib/constants");
|
|
const _requestmeta = require("./request-meta");
|
|
const _removetrailingslash = require("../shared/lib/router/utils/remove-trailing-slash");
|
|
const _apppaths = require("../shared/lib/router/utils/app-paths");
|
|
const _constants1 = require("../lib/constants");
|
|
function _interop_require_default(obj) {
|
|
return obj && obj.__esModule ? obj : {
|
|
default: obj
|
|
};
|
|
}
|
|
function normalizeVercelUrl(req, trustQuery, paramKeys, pageIsDynamic, defaultRouteRegex) {
|
|
// make sure to normalize req.url on Vercel to strip dynamic params
|
|
// from the query which are added during routing
|
|
if (pageIsDynamic && trustQuery && defaultRouteRegex) {
|
|
const _parsedUrl = (0, _url.parse)(req.url, true);
|
|
delete _parsedUrl.search;
|
|
for (const key of Object.keys(_parsedUrl.query)){
|
|
if (key !== _constants1.NEXT_QUERY_PARAM_PREFIX && key.startsWith(_constants1.NEXT_QUERY_PARAM_PREFIX) || (paramKeys || Object.keys(defaultRouteRegex.groups)).includes(key)) {
|
|
delete _parsedUrl.query[key];
|
|
}
|
|
}
|
|
req.url = (0, _url.format)(_parsedUrl);
|
|
}
|
|
}
|
|
function interpolateDynamicPath(pathname, params, defaultRouteRegex) {
|
|
if (!defaultRouteRegex) return pathname;
|
|
for (const param of Object.keys(defaultRouteRegex.groups)){
|
|
const { optional , repeat } = defaultRouteRegex.groups[param];
|
|
let builtParam = `[${repeat ? "..." : ""}${param}]`;
|
|
if (optional) {
|
|
builtParam = `[${builtParam}]`;
|
|
}
|
|
const paramIdx = pathname.indexOf(builtParam);
|
|
if (paramIdx > -1) {
|
|
let paramValue;
|
|
const value = params[param];
|
|
if (Array.isArray(value)) {
|
|
paramValue = value.map((v)=>v && encodeURIComponent(v)).join("/");
|
|
} else if (value) {
|
|
paramValue = encodeURIComponent(value);
|
|
} else {
|
|
paramValue = "";
|
|
}
|
|
pathname = pathname.slice(0, paramIdx) + paramValue + pathname.slice(paramIdx + builtParam.length);
|
|
}
|
|
}
|
|
return pathname;
|
|
}
|
|
function getUtils({ page , i18n , basePath , rewrites , pageIsDynamic , trailingSlash , caseSensitive }) {
|
|
let defaultRouteRegex;
|
|
let dynamicRouteMatcher;
|
|
let defaultRouteMatches;
|
|
if (pageIsDynamic) {
|
|
defaultRouteRegex = (0, _routeregex.getNamedRouteRegex)(page, false);
|
|
dynamicRouteMatcher = (0, _routematcher.getRouteMatcher)(defaultRouteRegex);
|
|
defaultRouteMatches = dynamicRouteMatcher(page);
|
|
}
|
|
function handleRewrites(req, parsedUrl) {
|
|
const rewriteParams = {};
|
|
let fsPathname = parsedUrl.pathname;
|
|
const matchesPage = ()=>{
|
|
const fsPathnameNoSlash = (0, _removetrailingslash.removeTrailingSlash)(fsPathname || "");
|
|
return fsPathnameNoSlash === (0, _removetrailingslash.removeTrailingSlash)(page) || (dynamicRouteMatcher == null ? void 0 : dynamicRouteMatcher(fsPathnameNoSlash));
|
|
};
|
|
const checkRewrite = (rewrite)=>{
|
|
const matcher = (0, _pathmatch.getPathMatch)(rewrite.source + (trailingSlash ? "(/)?" : ""), {
|
|
removeUnnamedParams: true,
|
|
strict: true,
|
|
sensitive: !!caseSensitive
|
|
});
|
|
let params = matcher(parsedUrl.pathname);
|
|
if ((rewrite.has || rewrite.missing) && params) {
|
|
const hasParams = (0, _preparedestination.matchHas)(req, parsedUrl.query, rewrite.has, rewrite.missing);
|
|
if (hasParams) {
|
|
Object.assign(params, hasParams);
|
|
} else {
|
|
params = false;
|
|
}
|
|
}
|
|
if (params) {
|
|
const { parsedDestination , destQuery } = (0, _preparedestination.prepareDestination)({
|
|
appendParamsToQuery: true,
|
|
destination: rewrite.destination,
|
|
params: params,
|
|
query: parsedUrl.query
|
|
});
|
|
// if the rewrite destination is external break rewrite chain
|
|
if (parsedDestination.protocol) {
|
|
return true;
|
|
}
|
|
Object.assign(rewriteParams, destQuery, params);
|
|
Object.assign(parsedUrl.query, parsedDestination.query);
|
|
delete parsedDestination.query;
|
|
Object.assign(parsedUrl, parsedDestination);
|
|
fsPathname = parsedUrl.pathname;
|
|
if (basePath) {
|
|
fsPathname = fsPathname.replace(new RegExp(`^${basePath}`), "") || "/";
|
|
}
|
|
if (i18n) {
|
|
const destLocalePathResult = (0, _normalizelocalepath.normalizeLocalePath)(fsPathname, i18n.locales);
|
|
fsPathname = destLocalePathResult.pathname;
|
|
parsedUrl.query.nextInternalLocale = destLocalePathResult.detectedLocale || params.nextInternalLocale;
|
|
}
|
|
if (fsPathname === page) {
|
|
return true;
|
|
}
|
|
if (pageIsDynamic && dynamicRouteMatcher) {
|
|
const dynamicParams = dynamicRouteMatcher(fsPathname);
|
|
if (dynamicParams) {
|
|
parsedUrl.query = {
|
|
...parsedUrl.query,
|
|
...dynamicParams
|
|
};
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
for (const rewrite of rewrites.beforeFiles || []){
|
|
checkRewrite(rewrite);
|
|
}
|
|
if (fsPathname !== page) {
|
|
let finished = false;
|
|
for (const rewrite of rewrites.afterFiles || []){
|
|
finished = checkRewrite(rewrite);
|
|
if (finished) break;
|
|
}
|
|
if (!finished && !matchesPage()) {
|
|
for (const rewrite of rewrites.fallback || []){
|
|
finished = checkRewrite(rewrite);
|
|
if (finished) break;
|
|
}
|
|
}
|
|
}
|
|
return rewriteParams;
|
|
}
|
|
function handleBasePath(req, parsedUrl) {
|
|
// always strip the basePath if configured since it is required
|
|
req.url = req.url.replace(new RegExp(`^${basePath}`), "") || "/";
|
|
parsedUrl.pathname = parsedUrl.pathname.replace(new RegExp(`^${basePath}`), "") || "/";
|
|
}
|
|
function getParamsFromRouteMatches(req, renderOpts, detectedLocale) {
|
|
return (0, _routematcher.getRouteMatcher)(function() {
|
|
const { groups , routeKeys } = defaultRouteRegex;
|
|
return {
|
|
re: {
|
|
// Simulate a RegExp match from the \`req.url\` input
|
|
exec: (str)=>{
|
|
const obj = Object.fromEntries(new URLSearchParams(str));
|
|
const matchesHasLocale = i18n && detectedLocale && obj["1"] === detectedLocale;
|
|
for (const key of Object.keys(obj)){
|
|
const value = obj[key];
|
|
if (key !== _constants1.NEXT_QUERY_PARAM_PREFIX && key.startsWith(_constants1.NEXT_QUERY_PARAM_PREFIX)) {
|
|
const normalizedKey = key.substring(_constants1.NEXT_QUERY_PARAM_PREFIX.length);
|
|
obj[normalizedKey] = value;
|
|
delete obj[key];
|
|
}
|
|
}
|
|
// favor named matches if available
|
|
const routeKeyNames = Object.keys(routeKeys || {});
|
|
const filterLocaleItem = (val)=>{
|
|
if (i18n) {
|
|
// locale items can be included in route-matches
|
|
// for fallback SSG pages so ensure they are
|
|
// filtered
|
|
const isCatchAll = Array.isArray(val);
|
|
const _val = isCatchAll ? val[0] : val;
|
|
if (typeof _val === "string" && i18n.locales.some((item)=>{
|
|
if (item.toLowerCase() === _val.toLowerCase()) {
|
|
detectedLocale = item;
|
|
renderOpts.locale = detectedLocale;
|
|
return true;
|
|
}
|
|
return false;
|
|
})) {
|
|
// remove the locale item from the match
|
|
if (isCatchAll) {
|
|
val.splice(0, 1);
|
|
}
|
|
// the value is only a locale item and
|
|
// shouldn't be added
|
|
return isCatchAll ? val.length === 0 : true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
if (routeKeyNames.every((name)=>obj[name])) {
|
|
return routeKeyNames.reduce((prev, keyName)=>{
|
|
const paramName = routeKeys == null ? void 0 : routeKeys[keyName];
|
|
if (paramName && !filterLocaleItem(obj[keyName])) {
|
|
prev[groups[paramName].pos] = obj[keyName];
|
|
}
|
|
return prev;
|
|
}, {});
|
|
}
|
|
return Object.keys(obj).reduce((prev, key)=>{
|
|
if (!filterLocaleItem(obj[key])) {
|
|
let normalizedKey = key;
|
|
if (matchesHasLocale) {
|
|
normalizedKey = parseInt(key, 10) - 1 + "";
|
|
}
|
|
return Object.assign(prev, {
|
|
[normalizedKey]: obj[key]
|
|
});
|
|
}
|
|
return prev;
|
|
}, {});
|
|
}
|
|
},
|
|
groups
|
|
};
|
|
}())(req.headers["x-now-route-matches"]);
|
|
}
|
|
function normalizeDynamicRouteParams(params, ignoreOptional) {
|
|
let hasValidParams = true;
|
|
if (!defaultRouteRegex) return {
|
|
params,
|
|
hasValidParams: false
|
|
};
|
|
params = Object.keys(defaultRouteRegex.groups).reduce((prev, key)=>{
|
|
let value = params[key];
|
|
if (typeof value === "string") {
|
|
value = (0, _apppaths.normalizeRscPath)(value, true);
|
|
}
|
|
if (Array.isArray(value)) {
|
|
value = value.map((val)=>{
|
|
if (typeof val === "string") {
|
|
val = (0, _apppaths.normalizeRscPath)(val, true);
|
|
}
|
|
return val;
|
|
});
|
|
}
|
|
// if the value matches the default value we can't rely
|
|
// on the parsed params, this is used to signal if we need
|
|
// to parse x-now-route-matches or not
|
|
const defaultValue = defaultRouteMatches[key];
|
|
const isOptional = defaultRouteRegex.groups[key].optional;
|
|
const isDefaultValue = Array.isArray(defaultValue) ? defaultValue.some((defaultVal)=>{
|
|
return Array.isArray(value) ? value.some((val)=>val.includes(defaultVal)) : value == null ? void 0 : value.includes(defaultVal);
|
|
}) : value == null ? void 0 : value.includes(defaultValue);
|
|
if (isDefaultValue || typeof value === "undefined" && !(isOptional && ignoreOptional)) {
|
|
hasValidParams = false;
|
|
}
|
|
// non-provided optional values should be undefined so normalize
|
|
// them to undefined
|
|
if (isOptional && (!value || Array.isArray(value) && value.length === 1 && // fallback optional catch-all SSG pages have
|
|
// [[...paramName]] for the root path on Vercel
|
|
(value[0] === "index" || value[0] === `[[...${key}]]`))) {
|
|
value = undefined;
|
|
delete params[key];
|
|
}
|
|
// query values from the proxy aren't already split into arrays
|
|
// so make sure to normalize catch-all values
|
|
if (value && typeof value === "string" && defaultRouteRegex.groups[key].repeat) {
|
|
value = value.split("/");
|
|
}
|
|
if (value) {
|
|
prev[key] = value;
|
|
}
|
|
return prev;
|
|
}, {});
|
|
return {
|
|
params,
|
|
hasValidParams
|
|
};
|
|
}
|
|
function handleLocale(req, res, parsedUrl, routeNoAssetPath, shouldNotRedirect) {
|
|
if (!i18n) return;
|
|
const pathname = parsedUrl.pathname || "/";
|
|
let defaultLocale = i18n.defaultLocale;
|
|
let detectedLocale = (0, _detectlocalecookie.detectLocaleCookie)(req, i18n.locales);
|
|
let acceptPreferredLocale;
|
|
try {
|
|
acceptPreferredLocale = i18n.localeDetection !== false ? (0, _acceptheader.acceptLanguage)(req.headers["accept-language"], i18n.locales) : detectedLocale;
|
|
} catch (_) {
|
|
acceptPreferredLocale = detectedLocale;
|
|
}
|
|
const { host } = req.headers || {};
|
|
// remove port from host and remove port if present
|
|
const hostname = host && host.split(":")[0].toLowerCase();
|
|
const detectedDomain = (0, _detectdomainlocale.detectDomainLocale)(i18n.domains, hostname);
|
|
if (detectedDomain) {
|
|
defaultLocale = detectedDomain.defaultLocale;
|
|
detectedLocale = defaultLocale;
|
|
(0, _requestmeta.addRequestMeta)(req, "__nextIsLocaleDomain", true);
|
|
}
|
|
// if not domain specific locale use accept-language preferred
|
|
detectedLocale = detectedLocale || acceptPreferredLocale;
|
|
let localeDomainRedirect;
|
|
const localePathResult = (0, _normalizelocalepath.normalizeLocalePath)(pathname, i18n.locales);
|
|
routeNoAssetPath = (0, _normalizelocalepath.normalizeLocalePath)(routeNoAssetPath, i18n.locales).pathname;
|
|
if (localePathResult.detectedLocale) {
|
|
detectedLocale = localePathResult.detectedLocale;
|
|
req.url = (0, _url.format)({
|
|
...parsedUrl,
|
|
pathname: localePathResult.pathname
|
|
});
|
|
(0, _requestmeta.addRequestMeta)(req, "__nextStrippedLocale", true);
|
|
parsedUrl.pathname = localePathResult.pathname;
|
|
}
|
|
// If a detected locale is a domain specific locale and we aren't already
|
|
// on that domain and path prefix redirect to it to prevent duplicate
|
|
// content from multiple domains
|
|
if (detectedDomain) {
|
|
const localeToCheck = localePathResult.detectedLocale ? detectedLocale : acceptPreferredLocale;
|
|
const matchedDomain = (0, _detectdomainlocale.detectDomainLocale)(i18n.domains, undefined, localeToCheck);
|
|
if (matchedDomain && matchedDomain.domain !== detectedDomain.domain) {
|
|
localeDomainRedirect = `http${matchedDomain.http ? "" : "s"}://${matchedDomain.domain}/${localeToCheck === matchedDomain.defaultLocale ? "" : localeToCheck}`;
|
|
}
|
|
}
|
|
const denormalizedPagePath = (0, _denormalizepagepath.denormalizePagePath)(pathname);
|
|
const detectedDefaultLocale = !detectedLocale || detectedLocale.toLowerCase() === defaultLocale.toLowerCase();
|
|
const shouldStripDefaultLocale = false;
|
|
// detectedDefaultLocale &&
|
|
// denormalizedPagePath.toLowerCase() === \`/\${i18n.defaultLocale.toLowerCase()}\`
|
|
const shouldAddLocalePrefix = !detectedDefaultLocale && denormalizedPagePath === "/";
|
|
detectedLocale = detectedLocale || i18n.defaultLocale;
|
|
if (!shouldNotRedirect && !req.headers["x-vercel-id"] && i18n.localeDetection !== false && (localeDomainRedirect || shouldAddLocalePrefix || shouldStripDefaultLocale)) {
|
|
// set the NEXT_LOCALE cookie when a user visits the default locale
|
|
// with the locale prefix so that they aren't redirected back to
|
|
// their accept-language preferred locale
|
|
if (shouldStripDefaultLocale && acceptPreferredLocale !== defaultLocale) {
|
|
const previous = res.getHeader("set-cookie");
|
|
res.setHeader("set-cookie", [
|
|
...typeof previous === "string" ? [
|
|
previous
|
|
] : Array.isArray(previous) ? previous : [],
|
|
_cookie.default.serialize("NEXT_LOCALE", defaultLocale, {
|
|
httpOnly: true,
|
|
path: "/"
|
|
})
|
|
]);
|
|
}
|
|
res.setHeader("Location", (0, _url.format)({
|
|
// make sure to include any query values when redirecting
|
|
...parsedUrl,
|
|
pathname: localeDomainRedirect ? localeDomainRedirect : shouldStripDefaultLocale ? basePath || "/" : `${basePath}/${detectedLocale}`
|
|
}));
|
|
res.statusCode = _constants.TEMPORARY_REDIRECT_STATUS;
|
|
res.end();
|
|
return;
|
|
}
|
|
detectedLocale = localePathResult.detectedLocale || detectedDomain && detectedDomain.defaultLocale || defaultLocale;
|
|
return {
|
|
defaultLocale,
|
|
detectedLocale,
|
|
routeNoAssetPath
|
|
};
|
|
}
|
|
return {
|
|
handleLocale,
|
|
handleRewrites,
|
|
handleBasePath,
|
|
defaultRouteRegex,
|
|
dynamicRouteMatcher,
|
|
defaultRouteMatches,
|
|
getParamsFromRouteMatches,
|
|
normalizeDynamicRouteParams,
|
|
normalizeVercelUrl: (req, trustQuery, paramKeys)=>normalizeVercelUrl(req, trustQuery, paramKeys, pageIsDynamic, defaultRouteRegex),
|
|
interpolateDynamicPath: (pathname, params)=>interpolateDynamicPath(pathname, params, defaultRouteRegex)
|
|
};
|
|
}
|
|
|
|
//# sourceMappingURL=server-utils.js.map
|