@vercel/build-utils 13.23.0 → 13.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @vercel/build-utils
2
2
 
3
+ ## 13.24.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d874af6: Add support for env vars injection that reference other services in `services` with an explicit `env` configuration.
8
+
3
9
  ## 13.23.0
4
10
 
5
11
  ### Minor Changes
@@ -1,4 +1,4 @@
1
- import type { Service } from './types';
1
+ import type { EnvVars, Service } from './types';
2
2
  type Envs = {
3
3
  [key: string]: string | undefined;
4
4
  };
@@ -7,27 +7,49 @@ interface FrameworkInfo {
7
7
  envPrefix?: string;
8
8
  }
9
9
  export interface GetServiceUrlEnvVarsOptions {
10
+ requestedEnv: EnvVars;
11
+ consumerService?: Service;
12
+ services: Service[];
13
+ frameworkList: readonly FrameworkInfo[];
14
+ currentEnv?: Envs;
15
+ deploymentUrl?: string;
16
+ origin?: string;
17
+ }
18
+ export interface GetExperimentalServiceUrlEnvVarsOptions {
10
19
  services: Service[];
11
20
  frameworkList: readonly FrameworkInfo[];
12
21
  currentEnv?: Envs;
13
22
  deploymentUrl?: string;
14
23
  origin?: string;
15
- envPrefix?: string;
16
24
  }
17
25
  /**
18
- * Generate environment variables for service URLs.
26
+ * Resolve a map of declared env-var refs into concrete URL values.
19
27
  *
20
- * For each web service, generates:
21
- * 1. A base env var with the full absolute URL (e.g., BACKEND_URL=https://deploy.vercel.app/api)
22
- * for server-side use.
23
- * 2. Framework-prefixed versions with only the route prefix path
24
- * (e.g., NEXT_PUBLIC_BACKEND_URL=/api, VITE_BACKEND_URL=/api) for client-side use.
25
- * Using relative paths avoids CORS issues since the browser resolves them against
26
- * the current origin, which works correctly across production domains, preview
27
- * deployments, and custom domains.
28
+ * By default the value is the absolute URL of the referenced web service,
29
+ * while if a consumer's framework has an `envPrefix`
30
+ * (e.g. `NEXT_PUBLIC_` or `VITE_`) and the declared name starts with that prefix
31
+ * then the target's route prefix (e.g. `/api`) is used,
32
+ * which useful for client bundles where same-origin requests avoid CORS.
28
33
  *
29
34
  * Environment variables that are already set in `currentEnv` will NOT be overwritten,
30
35
  * allowing user-defined values to take precedence.
31
36
  */
32
37
  export declare function getServiceUrlEnvVars(options: GetServiceUrlEnvVarsOptions): Record<string, string>;
38
+ /**
39
+ * Legacy implicit URL injection used for `experimentalServices` (and
40
+ * auto-detected services that map to the experimentalServices shape).
41
+ *
42
+ * For each web service, generates:
43
+ * 1. `{NAME}_URL` with the absolute URL (server-side use).
44
+ * 2. `{PREFIX}{NAME}_URL` for every framework prefix in `frameworkList` that
45
+ * matches a service in the deployment, with the relative route prefix
46
+ * (client-side use; relative paths avoid CORS).
47
+ *
48
+ * Entries already present in `currentEnv` are not overwritten — user-defined
49
+ * values win.
50
+ *
51
+ * The GA `services` field replaces this with explicit `env` declarations
52
+ * handled by `getServiceUrlEnvVars`.
53
+ */
54
+ export declare function getExperimentalServiceUrlEnvVars(options: GetExperimentalServiceUrlEnvVarsOptions): Record<string, string>;
33
55
  export {};
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var get_service_url_env_vars_exports = {};
20
20
  __export(get_service_url_env_vars_exports, {
21
+ getExperimentalServiceUrlEnvVars: () => getExperimentalServiceUrlEnvVars,
21
22
  getServiceUrlEnvVars: () => getServiceUrlEnvVars
22
23
  });
23
24
  module.exports = __toCommonJS(get_service_url_env_vars_exports);
@@ -44,12 +45,46 @@ function getFrameworkEnvPrefix(frameworkSlug, frameworkList) {
44
45
  }
45
46
  function getServiceUrlEnvVars(options) {
46
47
  const {
48
+ requestedEnv,
49
+ consumerService,
47
50
  services,
48
51
  frameworkList,
49
52
  currentEnv = {},
50
53
  deploymentUrl,
51
- origin,
52
- envPrefix
54
+ origin
55
+ } = options;
56
+ const baseUrl = origin || deploymentUrl;
57
+ if (!baseUrl)
58
+ return {};
59
+ const servicesByName = new Map(services.map((s) => [s.name, s]));
60
+ const consumerEnvPrefix = getFrameworkEnvPrefix(
61
+ consumerService?.framework,
62
+ frameworkList
63
+ );
64
+ const result = {};
65
+ for (const [name, envVar] of Object.entries(requestedEnv)) {
66
+ if (name in currentEnv) {
67
+ continue;
68
+ }
69
+ if (envVar.type !== "service-ref") {
70
+ continue;
71
+ }
72
+ const target = servicesByName.get(envVar.service);
73
+ if (!target || target.type !== "web" || !target.routePrefix) {
74
+ continue;
75
+ }
76
+ const isClientSide = !!consumerEnvPrefix && name.startsWith(consumerEnvPrefix) && name.length > consumerEnvPrefix.length;
77
+ result[name] = isClientSide ? target.routePrefix : computeServiceUrl(baseUrl, target.routePrefix, !!origin);
78
+ }
79
+ return result;
80
+ }
81
+ function getExperimentalServiceUrlEnvVars(options) {
82
+ const {
83
+ services,
84
+ frameworkList,
85
+ currentEnv = {},
86
+ deploymentUrl,
87
+ origin
53
88
  } = options;
54
89
  const baseUrl = origin || deploymentUrl;
55
90
  if (!baseUrl || !services || services.length === 0) {
@@ -73,12 +108,11 @@ function getServiceUrlEnvVars(options) {
73
108
  service.routePrefix,
74
109
  !!origin
75
110
  );
76
- const effectiveBaseEnvVarName = envPrefix ? `${envPrefix}${baseEnvVarName}` : baseEnvVarName;
77
- if (!(effectiveBaseEnvVarName in currentEnv)) {
78
- envVars[effectiveBaseEnvVarName] = absoluteUrl;
111
+ if (!(baseEnvVarName in currentEnv)) {
112
+ envVars[baseEnvVarName] = absoluteUrl;
79
113
  }
80
114
  for (const prefix of frameworkPrefixes) {
81
- const prefixedEnvVarName = envPrefix ? `${prefix}${envPrefix}${baseEnvVarName}` : `${prefix}${baseEnvVarName}`;
115
+ const prefixedEnvVarName = `${prefix}${baseEnvVarName}`;
82
116
  if (!(prefixedEnvVarName in currentEnv)) {
83
117
  envVars[prefixedEnvVarName] = service.routePrefix;
84
118
  }
@@ -88,5 +122,6 @@ function getServiceUrlEnvVars(options) {
88
122
  }
89
123
  // Annotate the CommonJS export names for ESM import in node:
90
124
  0 && (module.exports = {
125
+ getExperimentalServiceUrlEnvVars,
91
126
  getServiceUrlEnvVars
92
127
  });
package/dist/index.d.ts CHANGED
@@ -15,12 +15,12 @@ import debug from './debug';
15
15
  import getIgnoreFilter from './get-ignore-filter';
16
16
  import { getPlatformEnv } from './get-platform-env';
17
17
  import { getPrefixedEnvVars } from './get-prefixed-env-vars';
18
- import { getServiceUrlEnvVars } from './get-service-url-env-vars';
18
+ import { getServiceUrlEnvVars, getExperimentalServiceUrlEnvVars } from './get-service-url-env-vars';
19
19
  import { cloneEnv } from './clone-env';
20
20
  import { hardLinkDir } from './hard-link-dir';
21
21
  import { validateNpmrc } from './validate-npmrc';
22
22
  export type { NodejsLambdaOptions };
23
- 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, };
23
+ 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, };
24
24
  export { EdgeFunction } from './edge-function';
25
25
  export { readConfigFile, getPackageJson } from './fs/read-config-file';
26
26
  export { normalizePath } from './fs/normalize-path';
package/dist/index.js CHANGED
@@ -34539,6 +34539,7 @@ __export(src_exports, {
34539
34539
  getDiscontinuedNodeVersions: () => getDiscontinuedNodeVersions,
34540
34540
  getEncryptedEnv: () => getEncryptedEnv,
34541
34541
  getEnvForPackageManager: () => getEnvForPackageManager,
34542
+ getExperimentalServiceUrlEnvVars: () => getExperimentalServiceUrlEnvVars,
34542
34543
  getIgnoreFilter: () => get_ignore_filter_default,
34543
34544
  getInstalledPackageVersion: () => getInstalledPackageVersion,
34544
34545
  getInternalServiceCronPath: () => getInternalServiceCronPath,
@@ -37949,12 +37950,46 @@ function getFrameworkEnvPrefix(frameworkSlug, frameworkList) {
37949
37950
  }
37950
37951
  function getServiceUrlEnvVars(options) {
37951
37952
  const {
37953
+ requestedEnv,
37954
+ consumerService,
37952
37955
  services,
37953
37956
  frameworkList,
37954
37957
  currentEnv = {},
37955
37958
  deploymentUrl,
37956
- origin,
37957
- envPrefix
37959
+ origin
37960
+ } = options;
37961
+ const baseUrl = origin || deploymentUrl;
37962
+ if (!baseUrl)
37963
+ return {};
37964
+ const servicesByName = new Map(services.map((s) => [s.name, s]));
37965
+ const consumerEnvPrefix = getFrameworkEnvPrefix(
37966
+ consumerService?.framework,
37967
+ frameworkList
37968
+ );
37969
+ const result = {};
37970
+ for (const [name, envVar] of Object.entries(requestedEnv)) {
37971
+ if (name in currentEnv) {
37972
+ continue;
37973
+ }
37974
+ if (envVar.type !== "service-ref") {
37975
+ continue;
37976
+ }
37977
+ const target = servicesByName.get(envVar.service);
37978
+ if (!target || target.type !== "web" || !target.routePrefix) {
37979
+ continue;
37980
+ }
37981
+ const isClientSide = !!consumerEnvPrefix && name.startsWith(consumerEnvPrefix) && name.length > consumerEnvPrefix.length;
37982
+ result[name] = isClientSide ? target.routePrefix : computeServiceUrl(baseUrl, target.routePrefix, !!origin);
37983
+ }
37984
+ return result;
37985
+ }
37986
+ function getExperimentalServiceUrlEnvVars(options) {
37987
+ const {
37988
+ services,
37989
+ frameworkList,
37990
+ currentEnv = {},
37991
+ deploymentUrl,
37992
+ origin
37958
37993
  } = options;
37959
37994
  const baseUrl = origin || deploymentUrl;
37960
37995
  if (!baseUrl || !services || services.length === 0) {
@@ -37978,12 +38013,11 @@ function getServiceUrlEnvVars(options) {
37978
38013
  service.routePrefix,
37979
38014
  !!origin
37980
38015
  );
37981
- const effectiveBaseEnvVarName = envPrefix ? `${envPrefix}${baseEnvVarName}` : baseEnvVarName;
37982
- if (!(effectiveBaseEnvVarName in currentEnv)) {
37983
- envVars[effectiveBaseEnvVarName] = absoluteUrl;
38016
+ if (!(baseEnvVarName in currentEnv)) {
38017
+ envVars[baseEnvVarName] = absoluteUrl;
37984
38018
  }
37985
38019
  for (const prefix of frameworkPrefixes) {
37986
- const prefixedEnvVarName = envPrefix ? `${prefix}${envPrefix}${baseEnvVarName}` : `${prefix}${baseEnvVarName}`;
38020
+ const prefixedEnvVarName = `${prefix}${baseEnvVarName}`;
37987
38021
  if (!(prefixedEnvVarName in currentEnv)) {
37988
38022
  envVars[prefixedEnvVarName] = service.routePrefix;
37989
38023
  }
@@ -40298,6 +40332,7 @@ function getExtendedPayload({
40298
40332
  getDiscontinuedNodeVersions,
40299
40333
  getEncryptedEnv,
40300
40334
  getEnvForPackageManager,
40335
+ getExperimentalServiceUrlEnvVars,
40301
40336
  getIgnoreFilter,
40302
40337
  getInstalledPackageVersion,
40303
40338
  getInternalServiceCronPath,
package/dist/types.d.ts CHANGED
@@ -500,6 +500,12 @@ export interface ServiceQueueTopic {
500
500
  export type ServiceTopics = string[] | ServiceQueueTopic[];
501
501
  export declare const JOB_TRIGGERS: readonly ["queue", "schedule", "workflow"];
502
502
  export type JobTrigger = (typeof JOB_TRIGGERS)[number];
503
+ export interface ServiceRefEnvVar {
504
+ type: 'service-ref';
505
+ service: string;
506
+ }
507
+ export type EnvVar = ServiceRefEnvVar;
508
+ export type EnvVars = Record<string, EnvVar>;
503
509
  export interface Service {
504
510
  name: string;
505
511
  type: ServiceType;
@@ -518,8 +524,7 @@ export interface Service {
518
524
  schedule?: string | string[];
519
525
  handlerFunction?: string;
520
526
  topics?: ServiceTopics;
521
- /** custom prefix to inject service URL env vars */
522
- envPrefix?: string;
527
+ env?: EnvVars;
523
528
  }
524
529
  export declare function getServiceQueueTopicConfigs(config: {
525
530
  type?: ServiceType;
@@ -744,8 +749,7 @@ export interface ExperimentalServiceConfig {
744
749
  /** Cron schedule expression(s) (e.g., "0 0 * * *") */
745
750
  schedule?: string | string[];
746
751
  topics?: ServiceTopics;
747
- /** Custom prefix to use to inject service URL env vars */
748
- envPrefix?: string;
752
+ env?: EnvVars;
749
753
  }
750
754
  /**
751
755
  * Map of service name to service configuration.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/build-utils",
3
- "version": "13.23.0",
3
+ "version": "13.24.0",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.js",