@vercel/build-utils
Advanced tools
+6
-0
| # @vercel/build-utils | ||
| ## 13.24.0 | ||
| ### Minor Changes | ||
| - d874af6: Add support for env vars injection that reference other services in `services` with an explicit `env` configuration. | ||
| ## 13.23.0 | ||
@@ -4,0 +10,0 @@ |
@@ -1,2 +0,2 @@ | ||
| import type { Service } from './types'; | ||
| import type { EnvVars, Service } from './types'; | ||
| type Envs = { | ||
@@ -10,2 +10,4 @@ [key: string]: string | undefined; | ||
| export interface GetServiceUrlEnvVarsOptions { | ||
| requestedEnv: EnvVars; | ||
| consumerService?: Service; | ||
| services: Service[]; | ||
@@ -16,15 +18,18 @@ frameworkList: readonly FrameworkInfo[]; | ||
| origin?: string; | ||
| envPrefix?: string; | ||
| } | ||
| export interface GetExperimentalServiceUrlEnvVarsOptions { | ||
| services: Service[]; | ||
| frameworkList: readonly FrameworkInfo[]; | ||
| currentEnv?: Envs; | ||
| deploymentUrl?: string; | ||
| origin?: string; | ||
| } | ||
| /** | ||
| * Generate environment variables for service URLs. | ||
| * Resolve a map of declared env-var refs into concrete URL values. | ||
| * | ||
| * For each web service, generates: | ||
| * 1. A base env var with the full absolute URL (e.g., BACKEND_URL=https://deploy.vercel.app/api) | ||
| * for server-side use. | ||
| * 2. Framework-prefixed versions with only the route prefix path | ||
| * (e.g., NEXT_PUBLIC_BACKEND_URL=/api, VITE_BACKEND_URL=/api) for client-side use. | ||
| * Using relative paths avoids CORS issues since the browser resolves them against | ||
| * the current origin, which works correctly across production domains, preview | ||
| * deployments, and custom domains. | ||
| * By default the value is the absolute URL of the referenced web service, | ||
| * while if a consumer's framework has an `envPrefix` | ||
| * (e.g. `NEXT_PUBLIC_` or `VITE_`) and the declared name starts with that prefix | ||
| * then the target's route prefix (e.g. `/api`) is used, | ||
| * which useful for client bundles where same-origin requests avoid CORS. | ||
| * | ||
@@ -35,2 +40,19 @@ * Environment variables that are already set in `currentEnv` will NOT be overwritten, | ||
| export declare function getServiceUrlEnvVars(options: GetServiceUrlEnvVarsOptions): Record<string, string>; | ||
| /** | ||
| * Legacy implicit URL injection used for `experimentalServices` (and | ||
| * auto-detected services that map to the experimentalServices shape). | ||
| * | ||
| * For each web service, generates: | ||
| * 1. `{NAME}_URL` with the absolute URL (server-side use). | ||
| * 2. `{PREFIX}{NAME}_URL` for every framework prefix in `frameworkList` that | ||
| * matches a service in the deployment, with the relative route prefix | ||
| * (client-side use; relative paths avoid CORS). | ||
| * | ||
| * Entries already present in `currentEnv` are not overwritten — user-defined | ||
| * values win. | ||
| * | ||
| * The GA `services` field replaces this with explicit `env` declarations | ||
| * handled by `getServiceUrlEnvVars`. | ||
| */ | ||
| export declare function getExperimentalServiceUrlEnvVars(options: GetExperimentalServiceUrlEnvVarsOptions): Record<string, string>; | ||
| export {}; |
@@ -21,2 +21,3 @@ "use strict"; | ||
| __export(get_service_url_env_vars_exports, { | ||
| getExperimentalServiceUrlEnvVars: () => getExperimentalServiceUrlEnvVars, | ||
| getServiceUrlEnvVars: () => getServiceUrlEnvVars | ||
@@ -48,2 +49,4 @@ }); | ||
| const { | ||
| requestedEnv, | ||
| consumerService, | ||
| services, | ||
@@ -53,6 +56,38 @@ frameworkList, | ||
| deploymentUrl, | ||
| origin, | ||
| envPrefix | ||
| origin | ||
| } = options; | ||
| const baseUrl = origin || deploymentUrl; | ||
| if (!baseUrl) | ||
| return {}; | ||
| const servicesByName = new Map(services.map((s) => [s.name, s])); | ||
| const consumerEnvPrefix = getFrameworkEnvPrefix( | ||
| consumerService?.framework, | ||
| frameworkList | ||
| ); | ||
| const result = {}; | ||
| for (const [name, envVar] of Object.entries(requestedEnv)) { | ||
| if (name in currentEnv) { | ||
| continue; | ||
| } | ||
| if (envVar.type !== "service-ref") { | ||
| continue; | ||
| } | ||
| const target = servicesByName.get(envVar.service); | ||
| if (!target || target.type !== "web" || !target.routePrefix) { | ||
| continue; | ||
| } | ||
| const isClientSide = !!consumerEnvPrefix && name.startsWith(consumerEnvPrefix) && name.length > consumerEnvPrefix.length; | ||
| result[name] = isClientSide ? target.routePrefix : computeServiceUrl(baseUrl, target.routePrefix, !!origin); | ||
| } | ||
| return result; | ||
| } | ||
| function getExperimentalServiceUrlEnvVars(options) { | ||
| const { | ||
| services, | ||
| frameworkList, | ||
| currentEnv = {}, | ||
| deploymentUrl, | ||
| origin | ||
| } = options; | ||
| const baseUrl = origin || deploymentUrl; | ||
| if (!baseUrl || !services || services.length === 0) { | ||
@@ -79,8 +114,7 @@ return {}; | ||
| ); | ||
| const effectiveBaseEnvVarName = envPrefix ? `${envPrefix}${baseEnvVarName}` : baseEnvVarName; | ||
| if (!(effectiveBaseEnvVarName in currentEnv)) { | ||
| envVars[effectiveBaseEnvVarName] = absoluteUrl; | ||
| if (!(baseEnvVarName in currentEnv)) { | ||
| envVars[baseEnvVarName] = absoluteUrl; | ||
| } | ||
| for (const prefix of frameworkPrefixes) { | ||
| const prefixedEnvVarName = envPrefix ? `${prefix}${envPrefix}${baseEnvVarName}` : `${prefix}${baseEnvVarName}`; | ||
| const prefixedEnvVarName = `${prefix}${baseEnvVarName}`; | ||
| if (!(prefixedEnvVarName in currentEnv)) { | ||
@@ -95,3 +129,4 @@ envVars[prefixedEnvVarName] = service.routePrefix; | ||
| 0 && (module.exports = { | ||
| getExperimentalServiceUrlEnvVars, | ||
| getServiceUrlEnvVars | ||
| }); |
+2
-2
@@ -18,3 +18,3 @@ import FileBlob from './file-blob'; | ||
| import { getPrefixedEnvVars } from './get-prefixed-env-vars'; | ||
| import { getServiceUrlEnvVars } from './get-service-url-env-vars'; | ||
| import { getServiceUrlEnvVars, getExperimentalServiceUrlEnvVars } from './get-service-url-env-vars'; | ||
| import { cloneEnv } from './clone-env'; | ||
@@ -24,3 +24,3 @@ import { hardLinkDir } from './hard-link-dir'; | ||
| export type { NodejsLambdaOptions }; | ||
| export { FileBlob, FileFsRef, FileRef, Lambda, NodejsLambda, createLambda, Prerender, download, downloadFile, DownloadedFiles, getWriteableDirectory, glob, GlobOptions, rename, spawnAsync, getScriptName, installDependencies, runPackageJsonScript, execCommand, spawnCommand, walkParentDirs, getNodeBinPath, getNodeBinPaths, getSupportedNodeVersion, isBunVersion, getSupportedBunVersion, detectPackageManager, runNpmInstall, NpmInstallOutput, runBundleInstall, runPipInstall, PipInstallResult, runShellScript, runCustomInstallCommand, resetCustomInstallCommandSet, getEnvForPackageManager, getNodeVersion, getPathForPackageManager, getLatestNodeVersion, getDiscontinuedNodeVersions, getSpawnOptions, getPlatformEnv, getPrefixedEnvVars, getServiceUrlEnvVars, streamToBuffer, streamToBufferChunks, debug, isSymbolicLink, isDirectory, getLambdaOptionsFromFunction, sanitizeConsumerName, scanParentDirs, findPackageJson, getIgnoreFilter, cloneEnv, hardLinkDir, traverseUpDirectories, validateNpmrc, }; | ||
| export { FileBlob, FileFsRef, FileRef, Lambda, NodejsLambda, createLambda, Prerender, download, downloadFile, DownloadedFiles, getWriteableDirectory, glob, GlobOptions, rename, spawnAsync, getScriptName, installDependencies, runPackageJsonScript, execCommand, spawnCommand, walkParentDirs, getNodeBinPath, getNodeBinPaths, getSupportedNodeVersion, isBunVersion, getSupportedBunVersion, detectPackageManager, runNpmInstall, NpmInstallOutput, runBundleInstall, runPipInstall, PipInstallResult, runShellScript, runCustomInstallCommand, resetCustomInstallCommandSet, getEnvForPackageManager, getNodeVersion, getPathForPackageManager, getLatestNodeVersion, getDiscontinuedNodeVersions, getSpawnOptions, getPlatformEnv, getPrefixedEnvVars, getServiceUrlEnvVars, getExperimentalServiceUrlEnvVars, streamToBuffer, streamToBufferChunks, debug, isSymbolicLink, isDirectory, getLambdaOptionsFromFunction, sanitizeConsumerName, scanParentDirs, findPackageJson, getIgnoreFilter, cloneEnv, hardLinkDir, traverseUpDirectories, validateNpmrc, }; | ||
| export { EdgeFunction } from './edge-function'; | ||
@@ -27,0 +27,0 @@ export { readConfigFile, getPackageJson } from './fs/read-config-file'; |
+8
-4
@@ -503,2 +503,8 @@ import type FileRef from './file-ref'; | ||
| export type JobTrigger = (typeof JOB_TRIGGERS)[number]; | ||
| export interface ServiceRefEnvVar { | ||
| type: 'service-ref'; | ||
| service: string; | ||
| } | ||
| export type EnvVar = ServiceRefEnvVar; | ||
| export type EnvVars = Record<string, EnvVar>; | ||
| export interface Service { | ||
@@ -522,4 +528,3 @@ name: string; | ||
| topics?: ServiceTopics; | ||
| /** custom prefix to inject service URL env vars */ | ||
| envPrefix?: string; | ||
| env?: EnvVars; | ||
| } | ||
@@ -749,4 +754,3 @@ export declare function getServiceQueueTopicConfigs(config: { | ||
| topics?: ServiceTopics; | ||
| /** Custom prefix to use to inject service URL env vars */ | ||
| envPrefix?: string; | ||
| env?: EnvVars; | ||
| } | ||
@@ -753,0 +757,0 @@ /** |
+1
-1
| { | ||
| "name": "@vercel/build-utils", | ||
| "version": "13.23.0", | ||
| "version": "13.24.0", | ||
| "license": "Apache-2.0", | ||
@@ -5,0 +5,0 @@ "main": "./dist/index.js", |
Sorry, the diff of this file is too big to display
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
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 11 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 3 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
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
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
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 11 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 3 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
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
1997220
0.16%51256
0.19%