You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@vercel/backends

Package Overview
Dependencies
Maintainers
2
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@vercel/backends - npm Package Compare versions

Comparing version
0.0.46
to
0.0.47
+226
-8
./dist/index.mjs

@@ -6,3 +6,3 @@ import { builtinModules, createRequire } from "node:module";

import { lstat, readFile, rm, stat } from "node:fs/promises";
import { dirname as dirname$1, extname as extname$1, isAbsolute, join as join$1, relative } from "node:path";
import { basename, dirname as dirname$1, extname as extname$1, isAbsolute, join as join$1, relative } from "node:path";
import { build as build$2 } from "rolldown";

@@ -678,2 +678,163 @@ import { exports } from "resolve.exports";

//#endregion
//#region src/service-vc-init.ts
async function applyServiceVcInit(args) {
const { format, extension } = await resolveShimFormat(args);
const handlerDir = dirname$1(args.handler);
const vcInitName = `${basename(args.handler, extname$1(args.handler))}.__vc_service_vc_init${extension}`;
const vcInitHandler = handlerDir === "." ? vcInitName : join$1(handlerDir, vcInitName);
const handlerImportPath = `./${basename(args.handler)}`;
const vcInitSource = format === "esm" ? createEsmServiceVcInit(handlerImportPath) : createCjsServiceVcInit(handlerImportPath);
return {
handler: vcInitHandler,
files: {
...args.files,
[vcInitHandler]: new FileBlob({
data: vcInitSource,
mode: 420
})
}
};
}
async function resolveShimFormat(args) {
const { format } = await resolveEntrypointAndFormat({
entrypoint: args.handler,
workPath: args.workPath
});
return {
format,
extension: extname$1(args.handler) || (format === "esm" ? ".mjs" : ".cjs")
};
}
const sharedShimPrelude = String.raw`
const PATCH_SYMBOL = Symbol.for('vc.service.route-prefix-strip.patch')
function normalizeServiceRoutePrefix(rawPrefix) {
if (!rawPrefix) {
return ''
}
let prefix = String(rawPrefix).trim()
if (!prefix) {
return ''
}
if (!prefix.startsWith('/')) {
prefix = '/' + prefix
}
if (prefix !== '/') {
prefix = prefix.replace(/\/+$/, '')
}
return prefix === '/' ? '' : prefix
}
function getServiceRoutePrefix() {
const enabled = String(
process.env.VERCEL_SERVICE_ROUTE_PREFIX_STRIP || ''
).toLowerCase()
if (enabled !== '1' && enabled !== 'true') {
return ''
}
return normalizeServiceRoutePrefix(process.env.VERCEL_SERVICE_ROUTE_PREFIX || '')
}
function stripServiceRoutePrefix(requestUrl, prefix) {
if (typeof requestUrl !== 'string' || requestUrl === '*') {
return requestUrl
}
const queryIndex = requestUrl.indexOf('?')
const rawPath =
queryIndex === -1 ? requestUrl : requestUrl.slice(0, queryIndex)
const query = queryIndex === -1 ? '' : requestUrl.slice(queryIndex)
let path = rawPath || '/'
if (!path.startsWith('/')) {
path = '/' + path
}
if (!prefix) {
return path + query
}
if (path === prefix) {
return '/' + query
}
if (path.startsWith(prefix + '/')) {
return path.slice(prefix.length) + query
}
return path + query
}
function patchServerRequestUrl(ServerCtor) {
const prefix = getServiceRoutePrefix()
if (!prefix || globalThis[PATCH_SYMBOL]) {
return
}
globalThis[PATCH_SYMBOL] = true
const originalEmit = ServerCtor.prototype.emit
ServerCtor.prototype.emit = function patchedEmit(event, request, ...args) {
if (event === 'request' && request && typeof request.url === 'string') {
request.url = stripServiceRoutePrefix(request.url, prefix)
}
return originalEmit.call(this, event, request, ...args)
}
}
`;
function createEsmServiceVcInit(handlerImportPath) {
return `
import { Server } from 'node:http'
${sharedShimPrelude}
// Patch the HTTP server before loading user code so apps that attach request
// listeners during module evaluation see the stripped service-relative URL.
patchServerRequestUrl(Server)
const originalModule = await import(${JSON.stringify(handlerImportPath)})
/**
* Match the Node serverless loader behavior: TS/CJS/ESM interop can leave us
* with nested \`.default\` wrappers, so peel off a few layers to recover the
* actual user entrypoint shape.
*/
function unwrapDefaultExport(value) {
let current = value
for (let i = 0; i < 5; i++) {
if (current && typeof current === 'object' && 'default' in current && current.default) {
current = current.default
} else {
break
}
}
return current
}
const entrypoint = unwrapDefaultExport(originalModule)
// Re-export the resolved entrypoint so the surrounding runtime still sees the
// same handler shape after this service bootstrap runs.
export default typeof entrypoint === 'undefined' ? originalModule : entrypoint
`.trimStart();
}
function createCjsServiceVcInit(handlerImportPath) {
return `
const { Server } = require('node:http')
${sharedShimPrelude}
patchServerRequestUrl(Server)
module.exports = require(${JSON.stringify(handlerImportPath)})
`.trimStart();
}
//#endregion
//#region src/rolldown/nft.ts

@@ -1480,6 +1641,19 @@ const nft = async (args) => {

});
const serviceRoutePrefix = normalizeServiceRoutePrefix(args.config?.routePrefix ?? args.service?.routePrefix);
const shouldStripServiceRoutePrefix = !!serviceRoutePrefix && (typeof args.config?.serviceName === "string" || !!args.service);
let lambdaFiles = files;
let lambdaHandler = handler;
if (shouldStripServiceRoutePrefix) {
const shimmedLambda = await applyServiceVcInit({
files,
handler,
workPath: nftWorkPath
});
lambdaFiles = shimmedLambda.files;
lambdaHandler = shimmedLambda.handler;
}
const lambda = new NodejsLambda({
runtime: nodeVersion.runtime,
handler,
files,
handler: lambdaHandler,
files: lambdaFiles,
framework: rolldownResult.framework,

@@ -1492,14 +1666,31 @@ shouldAddHelpers: false,

});
if (shouldStripServiceRoutePrefix && serviceRoutePrefix) lambda.environment = {
...lambda.environment,
VERCEL_SERVICE_ROUTE_PREFIX: serviceRoutePrefix,
VERCEL_SERVICE_ROUTE_PREFIX_STRIP: "1"
};
const serviceName = typeof args.config?.serviceName === "string" && args.config.serviceName !== "" ? args.config.serviceName : void 0;
const internalServiceFunctionPath = typeof serviceName === "string" && serviceName !== "" ? `/_svc/${serviceName}/index` : void 0;
const internalServiceOutputPath = internalServiceFunctionPath?.slice(1);
const remapRouteDestination = (route) => {
const prefixedRoute = maybePrefixServiceRouteSource(route, serviceRoutePrefix);
if (!internalServiceFunctionPath || !route.dest) return prefixedRoute;
return {
...prefixedRoute,
dest: internalServiceFunctionPath
};
};
const routes = [
{ handle: "filesystem" },
...introspectionResult.routes,
...introspectionResult.routes.map(remapRouteDestination),
{
src: "/(.*)",
dest: "/"
src: getServiceCatchallSource(serviceRoutePrefix),
dest: internalServiceFunctionPath ?? "/"
}
];
const output = { index: lambda };
const output = internalServiceOutputPath ? { [internalServiceOutputPath]: lambda } : { index: lambda };
for (const route of routes) if (route.dest) {
if (route.dest === "/") continue;
output[route.dest] = lambda;
const outputPath = route.dest === internalServiceFunctionPath && internalServiceOutputPath ? internalServiceOutputPath : route.dest;
output[outputPath] = lambda;
}

@@ -1516,4 +1707,31 @@ return {

const normalizeArray = (value) => Array.isArray(value) ? value : value ? [value] : [];
const normalizeServiceRoutePrefix = (routePrefix) => {
if (typeof routePrefix !== "string" || routePrefix === "" || routePrefix === ".") return;
let normalized = routePrefix.startsWith("/") ? routePrefix : `/${routePrefix}`;
if (normalized !== "/" && normalized.endsWith("/")) normalized = normalized.slice(0, -1);
return normalized === "/" ? void 0 : normalized;
};
const maybePrefixServiceRouteSource = (route, routePrefix) => {
if (!routePrefix || typeof route.dest !== "string" || !route.dest.startsWith("/")) return route;
return {
...route,
src: getPrefixedRouteSource(route.src, route.dest, routePrefix)
};
};
const getPrefixedRouteSource = (routeSource, routePath, routePrefix) => {
if (!routeSource) return routeSource;
if (routePath === routePrefix || routePath.startsWith(`${routePrefix}/`)) return routeSource;
const escapedRoutePrefix = toRegexSource(routePrefix);
if (routeSource.startsWith("^(?:")) return `^(?:${escapedRoutePrefix}${routeSource.slice(4)}`;
if (routeSource.startsWith("^")) return `^${escapedRoutePrefix}${routeSource.slice(1)}`;
return `${escapedRoutePrefix}${routeSource}`;
};
const getServiceCatchallSource = (routePrefix) => {
if (!routePrefix) return "/(.*)";
return `^${escapeForRegex(routePrefix)}(?:/(.*))?$`;
};
const escapeForRegex = (value) => value.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
const toRegexSource = (value) => escapeForRegex(value).replaceAll("/", "\\/");
//#endregion
export { build, build$1 as cervelBuild, serve as cervelServe, findEntrypoint, findEntrypointOrThrow, getBuildSummary, introspectApp, nodeFileTrace, prepareCache, srvxOptions, version };

@@ -6,3 +6,3 @@ import { builtinModules, createRequire } from "node:module";

import { lstat, readFile, rm, stat } from "node:fs/promises";
import { dirname as dirname$1, extname as extname$1, isAbsolute, join as join$1, relative } from "node:path";
import { basename, dirname as dirname$1, extname as extname$1, isAbsolute, join as join$1, relative } from "node:path";
import { build as build$2 } from "rolldown";

@@ -678,2 +678,163 @@ import { exports } from "resolve.exports";

//#endregion
//#region src/service-vc-init.ts
async function applyServiceVcInit(args) {
const { format, extension } = await resolveShimFormat(args);
const handlerDir = dirname$1(args.handler);
const vcInitName = `${basename(args.handler, extname$1(args.handler))}.__vc_service_vc_init${extension}`;
const vcInitHandler = handlerDir === "." ? vcInitName : join$1(handlerDir, vcInitName);
const handlerImportPath = `./${basename(args.handler)}`;
const vcInitSource = format === "esm" ? createEsmServiceVcInit(handlerImportPath) : createCjsServiceVcInit(handlerImportPath);
return {
handler: vcInitHandler,
files: {
...args.files,
[vcInitHandler]: new FileBlob({
data: vcInitSource,
mode: 420
})
}
};
}
async function resolveShimFormat(args) {
const { format } = await resolveEntrypointAndFormat({
entrypoint: args.handler,
workPath: args.workPath
});
return {
format,
extension: extname$1(args.handler) || (format === "esm" ? ".mjs" : ".cjs")
};
}
const sharedShimPrelude = String.raw`
const PATCH_SYMBOL = Symbol.for('vc.service.route-prefix-strip.patch')
function normalizeServiceRoutePrefix(rawPrefix) {
if (!rawPrefix) {
return ''
}
let prefix = String(rawPrefix).trim()
if (!prefix) {
return ''
}
if (!prefix.startsWith('/')) {
prefix = '/' + prefix
}
if (prefix !== '/') {
prefix = prefix.replace(/\/+$/, '')
}
return prefix === '/' ? '' : prefix
}
function getServiceRoutePrefix() {
const enabled = String(
process.env.VERCEL_SERVICE_ROUTE_PREFIX_STRIP || ''
).toLowerCase()
if (enabled !== '1' && enabled !== 'true') {
return ''
}
return normalizeServiceRoutePrefix(process.env.VERCEL_SERVICE_ROUTE_PREFIX || '')
}
function stripServiceRoutePrefix(requestUrl, prefix) {
if (typeof requestUrl !== 'string' || requestUrl === '*') {
return requestUrl
}
const queryIndex = requestUrl.indexOf('?')
const rawPath =
queryIndex === -1 ? requestUrl : requestUrl.slice(0, queryIndex)
const query = queryIndex === -1 ? '' : requestUrl.slice(queryIndex)
let path = rawPath || '/'
if (!path.startsWith('/')) {
path = '/' + path
}
if (!prefix) {
return path + query
}
if (path === prefix) {
return '/' + query
}
if (path.startsWith(prefix + '/')) {
return path.slice(prefix.length) + query
}
return path + query
}
function patchServerRequestUrl(ServerCtor) {
const prefix = getServiceRoutePrefix()
if (!prefix || globalThis[PATCH_SYMBOL]) {
return
}
globalThis[PATCH_SYMBOL] = true
const originalEmit = ServerCtor.prototype.emit
ServerCtor.prototype.emit = function patchedEmit(event, request, ...args) {
if (event === 'request' && request && typeof request.url === 'string') {
request.url = stripServiceRoutePrefix(request.url, prefix)
}
return originalEmit.call(this, event, request, ...args)
}
}
`;
function createEsmServiceVcInit(handlerImportPath) {
return `
import { Server } from 'node:http'
${sharedShimPrelude}
// Patch the HTTP server before loading user code so apps that attach request
// listeners during module evaluation see the stripped service-relative URL.
patchServerRequestUrl(Server)
const originalModule = await import(${JSON.stringify(handlerImportPath)})
/**
* Match the Node serverless loader behavior: TS/CJS/ESM interop can leave us
* with nested \`.default\` wrappers, so peel off a few layers to recover the
* actual user entrypoint shape.
*/
function unwrapDefaultExport(value) {
let current = value
for (let i = 0; i < 5; i++) {
if (current && typeof current === 'object' && 'default' in current && current.default) {
current = current.default
} else {
break
}
}
return current
}
const entrypoint = unwrapDefaultExport(originalModule)
// Re-export the resolved entrypoint so the surrounding runtime still sees the
// same handler shape after this service bootstrap runs.
export default typeof entrypoint === 'undefined' ? originalModule : entrypoint
`.trimStart();
}
function createCjsServiceVcInit(handlerImportPath) {
return `
const { Server } = require('node:http')
${sharedShimPrelude}
patchServerRequestUrl(Server)
module.exports = require(${JSON.stringify(handlerImportPath)})
`.trimStart();
}
//#endregion
//#region src/rolldown/nft.ts

@@ -1480,6 +1641,19 @@ const nft = async (args) => {

});
const serviceRoutePrefix = normalizeServiceRoutePrefix(args.config?.routePrefix ?? args.service?.routePrefix);
const shouldStripServiceRoutePrefix = !!serviceRoutePrefix && (typeof args.config?.serviceName === "string" || !!args.service);
let lambdaFiles = files;
let lambdaHandler = handler;
if (shouldStripServiceRoutePrefix) {
const shimmedLambda = await applyServiceVcInit({
files,
handler,
workPath: nftWorkPath
});
lambdaFiles = shimmedLambda.files;
lambdaHandler = shimmedLambda.handler;
}
const lambda = new NodejsLambda({
runtime: nodeVersion.runtime,
handler,
files,
handler: lambdaHandler,
files: lambdaFiles,
framework: rolldownResult.framework,

@@ -1492,14 +1666,31 @@ shouldAddHelpers: false,

});
if (shouldStripServiceRoutePrefix && serviceRoutePrefix) lambda.environment = {
...lambda.environment,
VERCEL_SERVICE_ROUTE_PREFIX: serviceRoutePrefix,
VERCEL_SERVICE_ROUTE_PREFIX_STRIP: "1"
};
const serviceName = typeof args.config?.serviceName === "string" && args.config.serviceName !== "" ? args.config.serviceName : void 0;
const internalServiceFunctionPath = typeof serviceName === "string" && serviceName !== "" ? `/_svc/${serviceName}/index` : void 0;
const internalServiceOutputPath = internalServiceFunctionPath?.slice(1);
const remapRouteDestination = (route) => {
const prefixedRoute = maybePrefixServiceRouteSource(route, serviceRoutePrefix);
if (!internalServiceFunctionPath || !route.dest) return prefixedRoute;
return {
...prefixedRoute,
dest: internalServiceFunctionPath
};
};
const routes = [
{ handle: "filesystem" },
...introspectionResult.routes,
...introspectionResult.routes.map(remapRouteDestination),
{
src: "/(.*)",
dest: "/"
src: getServiceCatchallSource(serviceRoutePrefix),
dest: internalServiceFunctionPath ?? "/"
}
];
const output = { index: lambda };
const output = internalServiceOutputPath ? { [internalServiceOutputPath]: lambda } : { index: lambda };
for (const route of routes) if (route.dest) {
if (route.dest === "/") continue;
output[route.dest] = lambda;
const outputPath = route.dest === internalServiceFunctionPath && internalServiceOutputPath ? internalServiceOutputPath : route.dest;
output[outputPath] = lambda;
}

@@ -1516,4 +1707,31 @@ return {

const normalizeArray = (value) => Array.isArray(value) ? value : value ? [value] : [];
const normalizeServiceRoutePrefix = (routePrefix) => {
if (typeof routePrefix !== "string" || routePrefix === "" || routePrefix === ".") return;
let normalized = routePrefix.startsWith("/") ? routePrefix : `/${routePrefix}`;
if (normalized !== "/" && normalized.endsWith("/")) normalized = normalized.slice(0, -1);
return normalized === "/" ? void 0 : normalized;
};
const maybePrefixServiceRouteSource = (route, routePrefix) => {
if (!routePrefix || typeof route.dest !== "string" || !route.dest.startsWith("/")) return route;
return {
...route,
src: getPrefixedRouteSource(route.src, route.dest, routePrefix)
};
};
const getPrefixedRouteSource = (routeSource, routePath, routePrefix) => {
if (!routeSource) return routeSource;
if (routePath === routePrefix || routePath.startsWith(`${routePrefix}/`)) return routeSource;
const escapedRoutePrefix = toRegexSource(routePrefix);
if (routeSource.startsWith("^(?:")) return `^(?:${escapedRoutePrefix}${routeSource.slice(4)}`;
if (routeSource.startsWith("^")) return `^${escapedRoutePrefix}${routeSource.slice(1)}`;
return `${escapedRoutePrefix}${routeSource}`;
};
const getServiceCatchallSource = (routePrefix) => {
if (!routePrefix) return "/(.*)";
return `^${escapeForRegex(routePrefix)}(?:/(.*))?$`;
};
const escapeForRegex = (value) => value.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
const toRegexSource = (value) => escapeForRegex(value).replaceAll("/", "\\/");
//#endregion
export { build, build$1 as cervelBuild, serve as cervelServe, findEntrypoint, findEntrypointOrThrow, getBuildSummary, introspectApp, nodeFileTrace, prepareCache, srvxOptions, version };
+1
-1
{
"name": "@vercel/backends",
"version": "0.0.46",
"version": "0.0.47",
"license": "Apache-2.0",

@@ -5,0 +5,0 @@ "main": "./dist/index.mjs",