UNPKG

next

Version:

The React Framework

279 lines (278 loc) • 12.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { getUtils: null, interpolateDynamicPath: null, normalizeDynamicRouteParams: null, normalizeVercelUrl: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getUtils: function() { return getUtils; }, interpolateDynamicPath: function() { return interpolateDynamicPath; }, normalizeDynamicRouteParams: function() { return normalizeDynamicRouteParams; }, normalizeVercelUrl: function() { return normalizeVercelUrl; } }); 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 _removetrailingslash = require("../shared/lib/router/utils/remove-trailing-slash"); const _apppaths = require("../shared/lib/router/utils/app-paths"); const _constants = require("../lib/constants"); const _utils = require("./web/utils"); function normalizeVercelUrl(req, paramKeys, defaultRouteRegex) { // make sure to normalize req.url on Vercel to strip dynamic and rewrite // params from the query which are added during routing const _parsedUrl = (0, _url.parse)(req.url, true); delete _parsedUrl.search; for (const key of Object.keys(_parsedUrl.query)){ const isNextQueryPrefix = key !== _constants.NEXT_QUERY_PARAM_PREFIX && key.startsWith(_constants.NEXT_QUERY_PARAM_PREFIX); const isNextInterceptionMarkerPrefix = key !== _constants.NEXT_INTERCEPTION_MARKER_PREFIX && key.startsWith(_constants.NEXT_INTERCEPTION_MARKER_PREFIX); if (isNextQueryPrefix || isNextInterceptionMarkerPrefix || paramKeys.includes(key) || defaultRouteRegex && 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}]`; } 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.replaceAll(builtParam, paramValue); } return pathname; } function normalizeDynamicRouteParams(query, defaultRouteRegex, defaultRouteMatches, ignoreMissingOptional) { let hasValidParams = true; let params = {}; for (const key of Object.keys(defaultRouteRegex.groups)){ let value = query[key]; if (typeof value === 'string') { value = (0, _apppaths.normalizeRscURL)(value); } else if (Array.isArray(value)) { value = value.map(_apppaths.normalizeRscURL); } // 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 && ignoreMissingOptional)) { return { params: {}, 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 query[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) { params[key] = value; } } return { params, hasValidParams }; } function getUtils({ page, i18n, basePath, rewrites, pageIsDynamic, trailingSlash, caseSensitive }) { let defaultRouteRegex; let dynamicRouteMatcher; let defaultRouteMatches; if (pageIsDynamic) { defaultRouteRegex = (0, _routeregex.getNamedRouteRegex)(page, { prefixRouteKeys: 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 }); if (!parsedUrl.pathname) return false; 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 (!fsPathname) return false; if (basePath) { fsPathname = fsPathname.replace(new RegExp(`^${basePath}`), '') || '/'; } if (i18n) { const result = (0, _normalizelocalepath.normalizeLocalePath)(fsPathname, i18n.locales); fsPathname = result.pathname; parsedUrl.query.nextInternalLocale = result.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 getParamsFromRouteMatches(routeMatchesHeader) { // If we don't have a default route regex, we can't get params from route // matches if (!defaultRouteRegex) return null; const { groups, routeKeys } = defaultRouteRegex; const matcher = (0, _routematcher.getRouteMatcher)({ re: { // Simulate a RegExp match from the \`req.url\` input exec: (str)=>{ // Normalize all the prefixed query params. const obj = Object.fromEntries(new URLSearchParams(str)); for (const [key, value] of Object.entries(obj)){ const normalizedKey = (0, _utils.normalizeNextQueryParam)(key); if (!normalizedKey) continue; obj[normalizedKey] = value; delete obj[key]; } // Use all the named route keys. const result = {}; for (const keyName of Object.keys(routeKeys)){ const paramName = routeKeys[keyName]; // If this param name is not a valid parameter name, then skip it. if (!paramName) continue; const group = groups[paramName]; const value = obj[keyName]; // When we're missing a required param, we can't match the route. if (!group.optional && !value) return null; result[group.pos] = value; } return result; } }, groups }); const routeMatches = matcher(routeMatchesHeader); if (!routeMatches) return null; return routeMatches; } return { handleRewrites, defaultRouteRegex, dynamicRouteMatcher, defaultRouteMatches, getParamsFromRouteMatches, /** * Normalize dynamic route params. * * @param query - The query params to normalize. * @param ignoreMissingOptional - Whether to ignore missing optional params. * @returns The normalized params and whether they are valid. */ normalizeDynamicRouteParams: (query, ignoreMissingOptional)=>{ if (!defaultRouteRegex || !defaultRouteMatches) { return { params: {}, hasValidParams: false }; } return normalizeDynamicRouteParams(query, defaultRouteRegex, defaultRouteMatches, ignoreMissingOptional); }, normalizeVercelUrl: (req, paramKeys)=>normalizeVercelUrl(req, paramKeys, defaultRouteRegex), interpolateDynamicPath: (pathname, params)=>interpolateDynamicPath(pathname, params, defaultRouteRegex) }; } //# sourceMappingURL=server-utils.js.map