@vercel/routing-utils
Advanced tools
| /** | ||
| * Normalize a route prefix to always have a leading slash and no trailing slash | ||
| * unless it is root (`/`). | ||
| */ | ||
| export declare function normalizeRoutePrefix(routePrefix: string): string; | ||
| /** | ||
| * Create a service ownership guard: | ||
| * - Root services exclude all non-root prefixes. | ||
| * - Non-root services are constrained to their prefix and exclude descendants. | ||
| */ | ||
| export declare function getOwnershipGuard(ownerPrefix: string, allRoutePrefixes: string[]): string; | ||
| export declare function scopeRouteSourceToOwnership(source: string, ownershipGuard: string): string; |
| "use strict"; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| var service_route_ownership_exports = {}; | ||
| __export(service_route_ownership_exports, { | ||
| getOwnershipGuard: () => getOwnershipGuard, | ||
| normalizeRoutePrefix: () => normalizeRoutePrefix, | ||
| scopeRouteSourceToOwnership: () => scopeRouteSourceToOwnership | ||
| }); | ||
| module.exports = __toCommonJS(service_route_ownership_exports); | ||
| function normalizeRoutePrefix(routePrefix) { | ||
| let normalized = routePrefix.startsWith("/") ? routePrefix : `/${routePrefix}`; | ||
| if (normalized !== "/" && normalized.endsWith("/")) { | ||
| normalized = normalized.slice(0, -1); | ||
| } | ||
| return normalized || "/"; | ||
| } | ||
| function escapeForRegex(value) { | ||
| return value.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&"); | ||
| } | ||
| function toPrefixMatcher(routePrefix) { | ||
| return `${escapeForRegex(routePrefix)}(?:/|$)`; | ||
| } | ||
| function isDescendantPrefix(candidate, prefix) { | ||
| return candidate !== prefix && candidate.startsWith(`${prefix}/`); | ||
| } | ||
| function getOwnershipGuard(ownerPrefix, allRoutePrefixes) { | ||
| const owner = normalizeRoutePrefix(ownerPrefix); | ||
| const normalizedPrefixes = Array.from( | ||
| new Set(allRoutePrefixes.map(normalizeRoutePrefix)) | ||
| ); | ||
| const nonRootPrefixes = normalizedPrefixes.filter((prefix) => prefix !== "/").sort((a, b) => b.length - a.length); | ||
| if (owner === "/") { | ||
| return nonRootPrefixes.map((prefix) => `(?!${toPrefixMatcher(prefix)})`).join(""); | ||
| } | ||
| const descendants = nonRootPrefixes.filter( | ||
| (prefix) => isDescendantPrefix(prefix, owner) | ||
| ); | ||
| const positive = `(?=${toPrefixMatcher(owner)})`; | ||
| const negative = descendants.map((prefix) => `(?!${toPrefixMatcher(prefix)})`).join(""); | ||
| return `${positive}${negative}`; | ||
| } | ||
| function scopeRouteSourceToOwnership(source, ownershipGuard) { | ||
| if (!ownershipGuard) { | ||
| return source; | ||
| } | ||
| const inner = source.startsWith("^") ? source.slice(1) : source; | ||
| return `^${ownershipGuard}(?:${inner})`; | ||
| } | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| getOwnershipGuard, | ||
| normalizeRoutePrefix, | ||
| scopeRouteSourceToOwnership | ||
| }); |
+57
-18
@@ -24,2 +24,3 @@ "use strict"; | ||
| getCleanUrls: () => import_superstatic2.getCleanUrls, | ||
| getOwnershipGuard: () => import_service_route_ownership.getOwnershipGuard, | ||
| getTransformedRoutes: () => getTransformedRoutes, | ||
@@ -29,3 +30,5 @@ isHandler: () => isHandler, | ||
| mergeRoutes: () => import_merge.mergeRoutes, | ||
| normalizeRoutePrefix: () => import_service_route_ownership.normalizeRoutePrefix, | ||
| normalizeRoutes: () => normalizeRoutes, | ||
| scopeRouteSourceToOwnership: () => import_service_route_ownership.scopeRouteSourceToOwnership, | ||
| sourceToRegex: () => import_superstatic2.sourceToRegex | ||
@@ -38,2 +41,3 @@ }); | ||
| var import_merge = require("./merge"); | ||
| var import_service_route_ownership = require("./service-route-ownership"); | ||
| __reExport(src_exports, require("./schemas"), module.exports); | ||
@@ -57,2 +61,31 @@ var import_superstatic2 = require("./superstatic"); | ||
| } | ||
| function convertRouteAliases(route, index) { | ||
| if (route.source !== void 0) { | ||
| if (route.src !== void 0) { | ||
| throw new Error( | ||
| `Route at index ${index} cannot define both \`src\` and \`source\`. Please use only one.` | ||
| ); | ||
| } | ||
| route.src = route.source; | ||
| delete route.source; | ||
| } | ||
| if (route.destination !== void 0) { | ||
| if (route.dest !== void 0) { | ||
| throw new Error( | ||
| `Route at index ${index} cannot define both \`dest\` and \`destination\`. Please use only one.` | ||
| ); | ||
| } | ||
| route.dest = route.destination; | ||
| delete route.destination; | ||
| } | ||
| if (route.statusCode !== void 0) { | ||
| if (route.status !== void 0) { | ||
| throw new Error( | ||
| `Route at index ${index} cannot define both \`status\` and \`statusCode\`. Please use only one.` | ||
| ); | ||
| } | ||
| route.status = route.statusCode; | ||
| delete route.statusCode; | ||
| } | ||
| } | ||
| function normalizeRoutes(inputRoutes) { | ||
@@ -68,2 +101,9 @@ if (!inputRoutes || inputRoutes.length === 0) { | ||
| routes.push(route); | ||
| if (!isHandler(route)) { | ||
| try { | ||
| convertRouteAliases(route, i); | ||
| } catch (err) { | ||
| errors.push(err.message); | ||
| } | ||
| } | ||
| const keys = Object.keys(route); | ||
@@ -104,3 +144,3 @@ if (isHandler(route)) { | ||
| errors.push( | ||
| `Route at index ${i} cannot define \`dest\` after \`handle: hit\`.` | ||
| `Route at index ${i} cannot define \`dest\`/\`destination\` after \`handle: hit\`.` | ||
| ); | ||
@@ -110,3 +150,3 @@ } | ||
| errors.push( | ||
| `Route at index ${i} cannot define \`status\` after \`handle: hit\`.` | ||
| `Route at index ${i} cannot define \`status\`/\`statusCode\` after \`handle: hit\`.` | ||
| ); | ||
@@ -132,3 +172,3 @@ } | ||
| errors.push( | ||
| `Route at index ${i} must define either \`handle\` or \`src\` property.` | ||
| `Route at index ${i} must define either \`src\` or \`source\` property.` | ||
| ); | ||
@@ -149,3 +189,3 @@ } | ||
| } catch (err) { | ||
| const prop = type === "Route" ? "src" : "source"; | ||
| const prop = type === "Route" ? "src`/`source" : "source"; | ||
| return `${type} at index ${index} has invalid \`${prop}\` regular expression "${src}".`; | ||
@@ -223,16 +263,4 @@ } | ||
| const { cleanUrls, rewrites, redirects, headers, trailingSlash } = vercelConfig; | ||
| let { routes = null } = vercelConfig; | ||
| if (routes) { | ||
| const hasNewProperties = typeof cleanUrls !== "undefined" || typeof trailingSlash !== "undefined" || typeof redirects !== "undefined" || typeof headers !== "undefined" || typeof rewrites !== "undefined"; | ||
| if (hasNewProperties) { | ||
| const error = createError( | ||
| "invalid_mixed_routes", | ||
| "If `rewrites`, `redirects`, `headers`, `cleanUrls` or `trailingSlash` are used, then `routes` cannot be present.", | ||
| "https://vercel.link/mix-routing-props", | ||
| "Learn More" | ||
| ); | ||
| return { routes, error }; | ||
| } | ||
| return normalizeRoutes(routes); | ||
| } | ||
| const { routes: userRoutes = null } = vercelConfig; | ||
| let routes = null; | ||
| if (typeof cleanUrls !== "undefined") { | ||
@@ -258,2 +286,10 @@ const normalized = normalizeRoutes( | ||
| } | ||
| if (userRoutes) { | ||
| const normalized = normalizeRoutes(userRoutes); | ||
| if (normalized.error) { | ||
| return { routes, error: normalized.error }; | ||
| } | ||
| routes = routes || []; | ||
| routes.push(...normalized.routes || []); | ||
| } | ||
| if (typeof redirects !== "undefined") { | ||
@@ -380,2 +416,3 @@ const code = "invalid_redirect"; | ||
| getCleanUrls, | ||
| getOwnershipGuard, | ||
| getTransformedRoutes, | ||
@@ -385,3 +422,5 @@ isHandler, | ||
| mergeRoutes, | ||
| normalizeRoutePrefix, | ||
| normalizeRoutes, | ||
| scopeRouteSourceToOwnership, | ||
| sourceToRegex, | ||
@@ -388,0 +427,0 @@ ...require("./schemas"), |
+1
-0
| import { GetRoutesProps, NormalizedRoutes, Route, RouteWithHandle } from './types'; | ||
| export { appendRoutesToPhase } from './append'; | ||
| export { mergeRoutes } from './merge'; | ||
| export { getOwnershipGuard, normalizeRoutePrefix, scopeRouteSourceToOwnership, } from './service-route-ownership'; | ||
| export * from './schemas'; | ||
@@ -5,0 +6,0 @@ export { getCleanUrls, sourceToRegex } from './superstatic'; |
+57
-18
@@ -24,2 +24,3 @@ "use strict"; | ||
| getCleanUrls: () => import_superstatic2.getCleanUrls, | ||
| getOwnershipGuard: () => import_service_route_ownership.getOwnershipGuard, | ||
| getTransformedRoutes: () => getTransformedRoutes, | ||
@@ -29,3 +30,5 @@ isHandler: () => isHandler, | ||
| mergeRoutes: () => import_merge.mergeRoutes, | ||
| normalizeRoutePrefix: () => import_service_route_ownership.normalizeRoutePrefix, | ||
| normalizeRoutes: () => normalizeRoutes, | ||
| scopeRouteSourceToOwnership: () => import_service_route_ownership.scopeRouteSourceToOwnership, | ||
| sourceToRegex: () => import_superstatic2.sourceToRegex | ||
@@ -38,2 +41,3 @@ }); | ||
| var import_merge = require("./merge"); | ||
| var import_service_route_ownership = require("./service-route-ownership"); | ||
| __reExport(src_exports, require("./schemas"), module.exports); | ||
@@ -57,2 +61,31 @@ var import_superstatic2 = require("./superstatic"); | ||
| } | ||
| function convertRouteAliases(route, index) { | ||
| if (route.source !== void 0) { | ||
| if (route.src !== void 0) { | ||
| throw new Error( | ||
| `Route at index ${index} cannot define both \`src\` and \`source\`. Please use only one.` | ||
| ); | ||
| } | ||
| route.src = route.source; | ||
| delete route.source; | ||
| } | ||
| if (route.destination !== void 0) { | ||
| if (route.dest !== void 0) { | ||
| throw new Error( | ||
| `Route at index ${index} cannot define both \`dest\` and \`destination\`. Please use only one.` | ||
| ); | ||
| } | ||
| route.dest = route.destination; | ||
| delete route.destination; | ||
| } | ||
| if (route.statusCode !== void 0) { | ||
| if (route.status !== void 0) { | ||
| throw new Error( | ||
| `Route at index ${index} cannot define both \`status\` and \`statusCode\`. Please use only one.` | ||
| ); | ||
| } | ||
| route.status = route.statusCode; | ||
| delete route.statusCode; | ||
| } | ||
| } | ||
| function normalizeRoutes(inputRoutes) { | ||
@@ -68,2 +101,9 @@ if (!inputRoutes || inputRoutes.length === 0) { | ||
| routes.push(route); | ||
| if (!isHandler(route)) { | ||
| try { | ||
| convertRouteAliases(route, i); | ||
| } catch (err) { | ||
| errors.push(err.message); | ||
| } | ||
| } | ||
| const keys = Object.keys(route); | ||
@@ -104,3 +144,3 @@ if (isHandler(route)) { | ||
| errors.push( | ||
| `Route at index ${i} cannot define \`dest\` after \`handle: hit\`.` | ||
| `Route at index ${i} cannot define \`dest\`/\`destination\` after \`handle: hit\`.` | ||
| ); | ||
@@ -110,3 +150,3 @@ } | ||
| errors.push( | ||
| `Route at index ${i} cannot define \`status\` after \`handle: hit\`.` | ||
| `Route at index ${i} cannot define \`status\`/\`statusCode\` after \`handle: hit\`.` | ||
| ); | ||
@@ -132,3 +172,3 @@ } | ||
| errors.push( | ||
| `Route at index ${i} must define either \`handle\` or \`src\` property.` | ||
| `Route at index ${i} must define either \`src\` or \`source\` property.` | ||
| ); | ||
@@ -149,3 +189,3 @@ } | ||
| } catch (err) { | ||
| const prop = type === "Route" ? "src" : "source"; | ||
| const prop = type === "Route" ? "src`/`source" : "source"; | ||
| return `${type} at index ${index} has invalid \`${prop}\` regular expression "${src}".`; | ||
@@ -223,16 +263,4 @@ } | ||
| const { cleanUrls, rewrites, redirects, headers, trailingSlash } = vercelConfig; | ||
| let { routes = null } = vercelConfig; | ||
| if (routes) { | ||
| const hasNewProperties = typeof cleanUrls !== "undefined" || typeof trailingSlash !== "undefined" || typeof redirects !== "undefined" || typeof headers !== "undefined" || typeof rewrites !== "undefined"; | ||
| if (hasNewProperties) { | ||
| const error = createError( | ||
| "invalid_mixed_routes", | ||
| "If `rewrites`, `redirects`, `headers`, `cleanUrls` or `trailingSlash` are used, then `routes` cannot be present.", | ||
| "https://vercel.link/mix-routing-props", | ||
| "Learn More" | ||
| ); | ||
| return { routes, error }; | ||
| } | ||
| return normalizeRoutes(routes); | ||
| } | ||
| const { routes: userRoutes = null } = vercelConfig; | ||
| let routes = null; | ||
| if (typeof cleanUrls !== "undefined") { | ||
@@ -258,2 +286,10 @@ const normalized = normalizeRoutes( | ||
| } | ||
| if (userRoutes) { | ||
| const normalized = normalizeRoutes(userRoutes); | ||
| if (normalized.error) { | ||
| return { routes, error: normalized.error }; | ||
| } | ||
| routes = routes || []; | ||
| routes.push(...normalized.routes || []); | ||
| } | ||
| if (typeof redirects !== "undefined") { | ||
@@ -380,2 +416,3 @@ const code = "invalid_redirect"; | ||
| getCleanUrls, | ||
| getOwnershipGuard, | ||
| getTransformedRoutes, | ||
@@ -385,3 +422,5 @@ isHandler, | ||
| mergeRoutes, | ||
| normalizeRoutePrefix, | ||
| normalizeRoutes, | ||
| scopeRouteSourceToOwnership, | ||
| sourceToRegex, | ||
@@ -388,0 +427,0 @@ ...require("./schemas"), |
+17
-2
@@ -367,3 +367,2 @@ "use strict"; | ||
| type: "array", | ||
| deprecated: true, | ||
| description: "A list of routes objects used to rewrite paths to point towards other internal or external paths", | ||
@@ -375,3 +374,3 @@ example: [{ dest: "https://docs.example.com", src: "/docs" }], | ||
| type: "object", | ||
| required: ["src"], | ||
| anyOf: [{ required: ["src"] }, { required: ["source"] }], | ||
| additionalProperties: false, | ||
@@ -383,2 +382,6 @@ properties: { | ||
| }, | ||
| source: { | ||
| type: "string", | ||
| maxLength: 4096 | ||
| }, | ||
| dest: { | ||
@@ -388,2 +391,6 @@ type: "string", | ||
| }, | ||
| destination: { | ||
| type: "string", | ||
| maxLength: 4096 | ||
| }, | ||
| headers: { | ||
@@ -413,2 +420,3 @@ type: "object", | ||
| important: { | ||
| deprecated: true, | ||
| type: "boolean" | ||
@@ -423,2 +431,3 @@ }, | ||
| override: { | ||
| deprecated: true, | ||
| type: "boolean" | ||
@@ -437,2 +446,7 @@ }, | ||
| }, | ||
| statusCode: { | ||
| type: "integer", | ||
| minimum: 100, | ||
| maximum: 999 | ||
| }, | ||
| locale: { | ||
@@ -503,2 +517,3 @@ type: "object", | ||
| type: "object", | ||
| deprecated: true, | ||
| required: ["handle"], | ||
@@ -505,0 +520,0 @@ additionalProperties: false, |
+12
-0
@@ -60,5 +60,7 @@ import { HandleValue } from './index'; | ||
| continue?: boolean; | ||
| /** @deprecated */ | ||
| override?: boolean; | ||
| caseSensitive?: boolean; | ||
| check?: boolean; | ||
| /** @deprecated */ | ||
| important?: boolean; | ||
@@ -78,2 +80,11 @@ status?: number; | ||
| /** | ||
| * Aliases for `src`, `dest`, and `status`. These provide consistency with the | ||
| * `rewrites`, `redirects`, and `headers` fields which use `source`, `destination`, | ||
| * and `statusCode`. During normalization, these are converted to their canonical | ||
| * forms (`src`, `dest`, `status`) and stripped from the route object. | ||
| */ | ||
| source?: string; | ||
| destination?: string; | ||
| statusCode?: number; | ||
| /** | ||
| * A middleware key within the `output` key under the build result. | ||
@@ -94,2 +105,3 @@ * Overrides a `middleware` definition. | ||
| export type RouteWithHandle = { | ||
| /** @deprecated Internal use only. Do not use in vercel.json. */ | ||
| handle: HandleValue; | ||
@@ -96,0 +108,0 @@ src?: string; |
+1
-1
| { | ||
| "name": "@vercel/routing-utils", | ||
| "version": "5.4.0-canary.20260211174907.cdd2da6", | ||
| "version": "6.0.0", | ||
| "description": "Vercel routing utilities", | ||
@@ -5,0 +5,0 @@ "main": "./dist/index.js", |
Sorry, the diff of this file is too big to display
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
218795
3.49%18
12.5%4664
4.64%1
-50%