@netlify/build 33.4.7 → 33.5.1

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.
@@ -3,7 +3,7 @@ export function logBundleResults({ logs, results }: {
3
3
  results: import("@netlify/zip-it-and-ship-it").FunctionResult[];
4
4
  }): void;
5
5
  export function logFunctionsNonExistingDir(logs: any, relativeFunctionsSrc: any): void;
6
- export function logFunctionsToBundle({ logs, userFunctions, userFunctionsSrc, userFunctionsSrcExists, internalFunctions, internalFunctionsSrc, frameworkFunctions, type, }: {
6
+ export function logFunctionsToBundle({ logs, userFunctions, userFunctionsSrc, userFunctionsSrcExists, internalFunctions, internalFunctionsSrc, frameworkFunctions, generatedFunctions, type, }: {
7
7
  logs: any;
8
8
  userFunctions: any;
9
9
  userFunctionsSrc: any;
@@ -11,6 +11,7 @@ export function logFunctionsToBundle({ logs, userFunctions, userFunctionsSrc, us
11
11
  internalFunctions: any;
12
12
  internalFunctionsSrc: any;
13
13
  frameworkFunctions: any;
14
+ generatedFunctions: any;
14
15
  type?: string | undefined;
15
16
  }): void;
16
17
  export function logSecretsScanSkipMessage(logs: any, msg: any): void;
@@ -48,17 +48,31 @@ export const logFunctionsNonExistingDir = function (logs, relativeFunctionsSrc)
48
48
  log(logs, `The Netlify Functions setting targets a non-existing directory: ${relativeFunctionsSrc}`);
49
49
  };
50
50
  // Print the list of Netlify Functions about to be bundled
51
- export const logFunctionsToBundle = function ({ logs, userFunctions, userFunctionsSrc, userFunctionsSrcExists, internalFunctions, internalFunctionsSrc, frameworkFunctions, type = 'Functions', }) {
51
+ export const logFunctionsToBundle = function ({ logs, userFunctions, userFunctionsSrc, userFunctionsSrcExists, internalFunctions, internalFunctionsSrc, frameworkFunctions, generatedFunctions, type = 'Functions', }) {
52
+ let needsSpace = false;
53
+ if (generatedFunctions.length !== 0) {
54
+ for (const id in generatedFunctions) {
55
+ const { displayName, generatorType, functionNames } = generatedFunctions[id];
56
+ if (needsSpace)
57
+ log(logs, '');
58
+ log(logs, `Packaging ${type} generated by ${THEME.highlightWords(displayName)} ${generatorType}:`);
59
+ logArray(logs, functionNames, { indent: false });
60
+ needsSpace = true;
61
+ }
62
+ }
52
63
  if (internalFunctions.length !== 0) {
64
+ if (needsSpace)
65
+ log(logs, '');
53
66
  log(logs, `Packaging ${type} from ${THEME.highlightWords(internalFunctionsSrc)} directory:`);
54
67
  logArray(logs, internalFunctions, { indent: false });
68
+ needsSpace = true;
55
69
  }
56
70
  if (frameworkFunctions.length !== 0) {
57
- if (internalFunctions.length !== 0) {
71
+ if (needsSpace)
58
72
  log(logs, '');
59
- }
60
73
  log(logs, `Packaging ${type} generated by your framework:`);
61
74
  logArray(logs, frameworkFunctions, { indent: false });
75
+ needsSpace = true;
62
76
  }
63
77
  if (!userFunctionsSrcExists) {
64
78
  return;
@@ -67,9 +81,8 @@ export const logFunctionsToBundle = function ({ logs, userFunctions, userFunctio
67
81
  log(logs, `No ${type} were found in ${THEME.highlightWords(userFunctionsSrc)} directory`);
68
82
  return;
69
83
  }
70
- if (internalFunctions.length !== 0 || frameworkFunctions.length !== 0) {
84
+ if (needsSpace)
71
85
  log(logs, '');
72
- }
73
86
  log(logs, `Packaging ${type} from ${THEME.highlightWords(userFunctionsSrc)} directory:`);
74
87
  logArray(logs, userFunctions, { indent: false });
75
88
  };
@@ -17,4 +17,7 @@ export function run({ event, error, constants, envChanges, featureFlags, netlify
17
17
  [x: string]: any;
18
18
  };
19
19
  configMutations: any;
20
+ returnValue: {
21
+ generatedFunctions: any[];
22
+ } | undefined;
20
23
  }>;
@@ -12,8 +12,9 @@ export const run = async function ({ event, error, constants, envChanges, featur
12
12
  return context.with(getGlobalContext(), async () => {
13
13
  const method = methods[event];
14
14
  const runState = {};
15
+ const generatedFunctions = [];
15
16
  const systemLog = getSystemLog();
16
- const utils = getUtils({ event, constants, runState });
17
+ const utils = getUtils({ event, constants, generatedFunctions, runState });
17
18
  const netlifyConfigCopy = cloneNetlifyConfig(netlifyConfig);
18
19
  const runOptions = {
19
20
  utils,
@@ -32,6 +33,7 @@ export const run = async function ({ event, error, constants, envChanges, featur
32
33
  logPluginMethodEnd(verbose);
33
34
  const newEnvChanges = getNewEnvChanges(envBefore, netlifyConfig, netlifyConfigCopy);
34
35
  const configMutations = getConfigMutations(netlifyConfig, netlifyConfigCopy, event);
35
- return { ...runState, newEnvChanges, configMutations };
36
+ const returnValue = generatedFunctions.length ? { generatedFunctions } : undefined;
37
+ return { ...runState, newEnvChanges, configMutations, returnValue };
36
38
  });
37
39
  };
@@ -1,10 +1,11 @@
1
- export function getUtils({ event, constants: { FUNCTIONS_SRC, INTERNAL_FUNCTIONS_SRC, CACHE_DIR }, runState, }: {
1
+ export function getUtils({ event, constants: { FUNCTIONS_SRC, INTERNAL_FUNCTIONS_SRC, CACHE_DIR }, generatedFunctions, runState, }: {
2
2
  event: any;
3
3
  constants: {
4
4
  FUNCTIONS_SRC: any;
5
5
  INTERNAL_FUNCTIONS_SRC: any;
6
6
  CACHE_DIR: any;
7
7
  };
8
+ generatedFunctions?: never[] | undefined;
8
9
  runState: any;
9
10
  }): {
10
11
  build: {
@@ -25,6 +26,7 @@ export function getUtils({ event, constants: { FUNCTIONS_SRC, INTERNAL_FUNCTIONS
25
26
  add: (src: any) => Promise<void>;
26
27
  list: any;
27
28
  listAll: any;
29
+ generate: (functionPath: any) => any;
28
30
  };
29
31
  status: {
30
32
  show: any;
@@ -7,11 +7,11 @@ import { isSoftFailEvent } from '../events.js';
7
7
  import { addLazyProp } from './lazy.js';
8
8
  import { show } from './status.js';
9
9
  // Retrieve the `utils` argument.
10
- export const getUtils = function ({ event, constants: { FUNCTIONS_SRC, INTERNAL_FUNCTIONS_SRC, CACHE_DIR }, runState, }) {
10
+ export const getUtils = function ({ event, constants: { FUNCTIONS_SRC, INTERNAL_FUNCTIONS_SRC, CACHE_DIR }, generatedFunctions = [], runState, }) {
11
11
  run.command = runCommand;
12
12
  const build = getBuildUtils(event);
13
13
  const cache = getCacheUtils(CACHE_DIR);
14
- const functions = getFunctionsUtils(FUNCTIONS_SRC, INTERNAL_FUNCTIONS_SRC);
14
+ const functions = getFunctionsUtils(FUNCTIONS_SRC, INTERNAL_FUNCTIONS_SRC, generatedFunctions);
15
15
  const status = getStatusUtils(runState);
16
16
  const utils = { build, cache, run, functions, status };
17
17
  addLazyProp(utils, 'git', () => getGitUtils());
@@ -30,12 +30,14 @@ const getBuildUtils = function (event) {
30
30
  const getCacheUtils = function (CACHE_DIR) {
31
31
  return cacheBindOpts({ cacheDir: CACHE_DIR });
32
32
  };
33
- const getFunctionsUtils = function (FUNCTIONS_SRC, INTERNAL_FUNCTIONS_SRC) {
33
+ const getFunctionsUtils = function (FUNCTIONS_SRC, INTERNAL_FUNCTIONS_SRC, generatedFunctions) {
34
34
  const functionsDirectories = [INTERNAL_FUNCTIONS_SRC, FUNCTIONS_SRC].filter(Boolean);
35
35
  const add = (src) => functionsAdd(src, INTERNAL_FUNCTIONS_SRC, { fail: failBuild });
36
36
  const list = functionsList.bind(null, functionsDirectories, { fail: failBuild });
37
37
  const listAll = functionsListAll.bind(null, functionsDirectories, { fail: failBuild });
38
- return { add, list, listAll };
38
+ const generate = (functionPath) => generatedFunctions.push({ path: functionPath });
39
+ /** @type import('../../types/options/netlify_plugin_functions_util.js').NetlifyPluginFunctionsUtil */
40
+ return { add, list, listAll, generate };
39
41
  };
40
42
  const getStatusUtils = function (runState) {
41
43
  return { show: show.bind(undefined, runState) };
@@ -123,6 +123,7 @@ const logFunctions = async ({ frameworksAPISrcPath, internalSrcDirectory, intern
123
123
  internalFunctionsSrc: internalSrcDirectory,
124
124
  frameworkFunctions: frameworkFunctions.map(({ name }) => name),
125
125
  type: 'Edge Functions',
126
+ generatedFunctions: [],
126
127
  });
127
128
  };
128
129
  export const bundleEdgeFunctions = {
@@ -1,7 +1,7 @@
1
1
  import { zipFunctions, type FunctionResult } from '@netlify/zip-it-and-ship-it';
2
2
  export declare const bundleFunctions: {
3
3
  event: string;
4
- coreStep: ({ childEnv, constants: { INTERNAL_FUNCTIONS_SRC: relativeInternalFunctionsSrc, IS_LOCAL: isRunningLocally, FUNCTIONS_SRC: relativeFunctionsSrc, FUNCTIONS_DIST: relativeFunctionsDist, }, buildDir, branch, packagePath, logs, netlifyConfig, featureFlags, repositoryRoot, userNodeVersion, systemLog, }: {
4
+ coreStep: ({ childEnv, constants: { INTERNAL_FUNCTIONS_SRC: relativeInternalFunctionsSrc, IS_LOCAL: isRunningLocally, FUNCTIONS_SRC: relativeFunctionsSrc, FUNCTIONS_DIST: relativeFunctionsDist, }, buildDir, branch, packagePath, logs, netlifyConfig, featureFlags, repositoryRoot, userNodeVersion, systemLog, returnValues, }: {
5
5
  childEnv: any;
6
6
  constants: {
7
7
  INTERNAL_FUNCTIONS_SRC: any;
@@ -18,6 +18,7 @@ export declare const bundleFunctions: {
18
18
  repositoryRoot: any;
19
19
  userNodeVersion: any;
20
20
  systemLog: any;
21
+ returnValues: any;
21
22
  }) => Promise<{
22
23
  tags?: undefined;
23
24
  metrics?: undefined;
@@ -37,13 +38,14 @@ export declare const bundleFunctions: {
37
38
  coreStepId: string;
38
39
  coreStepName: string;
39
40
  coreStepDescription: () => string;
40
- condition: ({ buildDir, constants: { INTERNAL_FUNCTIONS_SRC, FUNCTIONS_SRC }, packagePath, }: {
41
+ condition: ({ buildDir, constants: { INTERNAL_FUNCTIONS_SRC, FUNCTIONS_SRC }, packagePath, returnValues, }: {
41
42
  buildDir: any;
42
43
  constants: {
43
44
  INTERNAL_FUNCTIONS_SRC: any;
44
45
  FUNCTIONS_SRC: any;
45
46
  };
46
47
  packagePath: any;
48
+ returnValues: any;
47
49
  }) => Promise<boolean>;
48
50
  };
49
51
  export declare const zipItAndShipIt: {
@@ -1,4 +1,4 @@
1
- import { resolve } from 'path';
1
+ import { basename, resolve } from 'path';
2
2
  import { RUNTIME, zipFunctions } from '@netlify/zip-it-and-ship-it';
3
3
  import { pathExists } from 'path-exists';
4
4
  import { addErrorInfo } from '../../error/info.js';
@@ -46,7 +46,7 @@ const validateCustomRoutes = function (functions) {
46
46
  }
47
47
  }
48
48
  };
49
- const zipFunctionsAndLogResults = async ({ branch, buildDir, childEnv, featureFlags, functionsConfig, functionsDist, functionsSrc, frameworkFunctionsSrc, internalFunctionsSrc, isRunningLocally, logs, repositoryRoot, userNodeVersion, systemLog, }) => {
49
+ const zipFunctionsAndLogResults = async ({ branch, buildDir, childEnv, featureFlags, functionsConfig, functionsDist, functionsSrc, generatedFunctions, frameworkFunctionsSrc, internalFunctionsSrc, isRunningLocally, logs, repositoryRoot, userNodeVersion, systemLog, }) => {
50
50
  const zisiParameters = getZisiParameters({
51
51
  branch,
52
52
  buildDir,
@@ -63,7 +63,7 @@ const zipFunctionsAndLogResults = async ({ branch, buildDir, childEnv, featureFl
63
63
  try {
64
64
  // Printing an empty line before bundling output.
65
65
  log(logs, '');
66
- const sourceDirectories = [internalFunctionsSrc, frameworkFunctionsSrc, functionsSrc].filter(Boolean);
66
+ const sourceDirectories = [internalFunctionsSrc, frameworkFunctionsSrc, functionsSrc, ...generatedFunctions].filter(Boolean);
67
67
  const results = await zipItAndShipIt.zipFunctions(sourceDirectories, functionsDist, zisiParameters);
68
68
  validateCustomRoutes(results);
69
69
  const bundlers = Array.from(getBundlers(results));
@@ -75,7 +75,7 @@ const zipFunctionsAndLogResults = async ({ branch, buildDir, childEnv, featureFl
75
75
  }
76
76
  };
77
77
  // Plugin to package Netlify functions with @netlify/zip-it-and-ship-it
78
- const coreStep = async function ({ childEnv, constants: { INTERNAL_FUNCTIONS_SRC: relativeInternalFunctionsSrc, IS_LOCAL: isRunningLocally, FUNCTIONS_SRC: relativeFunctionsSrc, FUNCTIONS_DIST: relativeFunctionsDist, }, buildDir, branch, packagePath, logs, netlifyConfig, featureFlags, repositoryRoot, userNodeVersion, systemLog, }) {
78
+ const coreStep = async function ({ childEnv, constants: { INTERNAL_FUNCTIONS_SRC: relativeInternalFunctionsSrc, IS_LOCAL: isRunningLocally, FUNCTIONS_SRC: relativeFunctionsSrc, FUNCTIONS_DIST: relativeFunctionsDist, }, buildDir, branch, packagePath, logs, netlifyConfig, featureFlags, repositoryRoot, userNodeVersion, systemLog, returnValues, }) {
79
79
  const functionsSrc = relativeFunctionsSrc === undefined ? undefined : resolve(buildDir, relativeFunctionsSrc);
80
80
  const functionsDist = resolve(buildDir, relativeFunctionsDist);
81
81
  const internalFunctionsSrc = resolve(buildDir, relativeInternalFunctionsSrc);
@@ -98,6 +98,7 @@ const coreStep = async function ({ childEnv, constants: { INTERNAL_FUNCTIONS_SRC
98
98
  log(logs, '');
99
99
  }
100
100
  }
101
+ const generatedFunctions = getGeneratedFunctionPaths(returnValues);
101
102
  logFunctionsToBundle({
102
103
  logs,
103
104
  userFunctions,
@@ -106,8 +107,12 @@ const coreStep = async function ({ childEnv, constants: { INTERNAL_FUNCTIONS_SRC
106
107
  internalFunctions,
107
108
  internalFunctionsSrc: relativeInternalFunctionsSrc,
108
109
  frameworkFunctions,
110
+ generatedFunctions: getGeneratedFunctionsByGenerator(returnValues),
109
111
  });
110
- if (userFunctions.length === 0 && internalFunctions.length === 0 && frameworkFunctions.length === 0) {
112
+ if (userFunctions.length === 0 &&
113
+ internalFunctions.length === 0 &&
114
+ frameworkFunctions.length === 0 &&
115
+ generatedFunctions.length === 0) {
111
116
  return {};
112
117
  }
113
118
  const { bundlers } = await zipFunctionsAndLogResults({
@@ -125,6 +130,7 @@ const coreStep = async function ({ childEnv, constants: { INTERNAL_FUNCTIONS_SRC
125
130
  repositoryRoot,
126
131
  userNodeVersion,
127
132
  systemLog,
133
+ generatedFunctions,
128
134
  });
129
135
  const metrics = getMetrics(internalFunctions, userFunctions);
130
136
  return {
@@ -138,7 +144,7 @@ const coreStep = async function ({ childEnv, constants: { INTERNAL_FUNCTIONS_SRC
138
144
  // one configured by the user or the internal one) exists. We use a dynamic
139
145
  // `condition` because the directories might be created by the build command
140
146
  // or plugins.
141
- const hasFunctionsDirectories = async function ({ buildDir, constants: { INTERNAL_FUNCTIONS_SRC, FUNCTIONS_SRC }, packagePath, }) {
147
+ const hasFunctionsDirectories = async function ({ buildDir, constants: { INTERNAL_FUNCTIONS_SRC, FUNCTIONS_SRC }, packagePath, returnValues, }) {
142
148
  const hasFunctionsSrc = FUNCTIONS_SRC !== undefined && FUNCTIONS_SRC !== '';
143
149
  if (hasFunctionsSrc) {
144
150
  return true;
@@ -148,7 +154,39 @@ const hasFunctionsDirectories = async function ({ buildDir, constants: { INTERNA
148
154
  return true;
149
155
  }
150
156
  const frameworkFunctionsSrc = resolve(buildDir, packagePath || '', FRAMEWORKS_API_FUNCTIONS_ENDPOINT);
151
- return await pathExists(frameworkFunctionsSrc);
157
+ if (await pathExists(frameworkFunctionsSrc)) {
158
+ return true;
159
+ }
160
+ // We must run the core step if the return value of any of the previous steps
161
+ // has declared generated functions.
162
+ for (const id in returnValues) {
163
+ if (returnValues[id].generatedFunctions && returnValues[id].generatedFunctions.length !== 0) {
164
+ return true;
165
+ }
166
+ }
167
+ return false;
168
+ };
169
+ // Takes a list of return values and produces an array with the paths of all
170
+ // generated functions.
171
+ const getGeneratedFunctionPaths = (returnValues) => {
172
+ return Object.values(returnValues).flatMap((returnValue) => returnValue.generatedFunctions?.map((func) => func.path) || []);
173
+ };
174
+ // Takes a list of return values and produces an object with the names of the
175
+ // generated functions for each generator. This is used for printing logs only.
176
+ const getGeneratedFunctionsByGenerator = (returnValues) => {
177
+ const result = {};
178
+ for (const id in returnValues) {
179
+ const { displayName, generatedFunctions, generatorType } = returnValues[id];
180
+ if (!generatedFunctions || generatedFunctions.length === 0) {
181
+ continue;
182
+ }
183
+ result[id] = {
184
+ displayName,
185
+ generatorType,
186
+ functionNames: generatedFunctions.map((func) => basename(func.path)),
187
+ };
188
+ }
189
+ return result;
152
190
  };
153
191
  export const bundleFunctions = {
154
192
  event: 'onBuild',
@@ -1,4 +1,4 @@
1
- export declare const fireCoreStep: ({ coreStep, coreStepId, coreStepName, configPath, outputConfigPath, buildDir, repositoryRoot, packagePath, constants, buildbotServerSocket, events, logs, quiet, nodePath, childEnv, context, branch, envChanges, errorParams, configOpts, netlifyConfig, defaultConfig, configMutations, headersPath, redirectsPath, featureFlags, debug, systemLog, saveConfig, userNodeVersion, explicitSecretKeys, enhancedSecretScan, edgeFunctionsBootstrapURL, deployId, outputFlusher, api, }: {
1
+ export declare const fireCoreStep: ({ coreStep, coreStepId, coreStepName, configPath, outputConfigPath, buildDir, repositoryRoot, packagePath, constants, buildbotServerSocket, events, logs, quiet, nodePath, childEnv, context, branch, envChanges, errorParams, configOpts, netlifyConfig, defaultConfig, configMutations, headersPath, redirectsPath, featureFlags, debug, systemLog, saveConfig, userNodeVersion, explicitSecretKeys, enhancedSecretScan, edgeFunctionsBootstrapURL, deployId, outputFlusher, api, returnValues, }: {
2
2
  coreStep: any;
3
3
  coreStepId: any;
4
4
  coreStepName: any;
@@ -35,6 +35,7 @@ export declare const fireCoreStep: ({ coreStep, coreStepId, coreStepName, config
35
35
  deployId: any;
36
36
  outputFlusher: any;
37
37
  api: any;
38
+ returnValues: any;
38
39
  }) => Promise<{
39
40
  newEnvChanges: any;
40
41
  netlifyConfig: any;
@@ -3,7 +3,7 @@ import { addErrorInfo, isBuildError } from '../error/info.js';
3
3
  import { addOutputFlusher } from '../log/logger.js';
4
4
  import { updateNetlifyConfig, listConfigSideFiles } from './update_config.js';
5
5
  // Fire a core step
6
- export const fireCoreStep = async function ({ coreStep, coreStepId, coreStepName, configPath, outputConfigPath, buildDir, repositoryRoot, packagePath, constants, buildbotServerSocket, events, logs, quiet, nodePath, childEnv, context, branch, envChanges, errorParams, configOpts, netlifyConfig, defaultConfig, configMutations, headersPath, redirectsPath, featureFlags, debug, systemLog, saveConfig, userNodeVersion, explicitSecretKeys, enhancedSecretScan, edgeFunctionsBootstrapURL, deployId, outputFlusher, api, }) {
6
+ export const fireCoreStep = async function ({ coreStep, coreStepId, coreStepName, configPath, outputConfigPath, buildDir, repositoryRoot, packagePath, constants, buildbotServerSocket, events, logs, quiet, nodePath, childEnv, context, branch, envChanges, errorParams, configOpts, netlifyConfig, defaultConfig, configMutations, headersPath, redirectsPath, featureFlags, debug, systemLog, saveConfig, userNodeVersion, explicitSecretKeys, enhancedSecretScan, edgeFunctionsBootstrapURL, deployId, outputFlusher, api, returnValues, }) {
7
7
  const logsA = outputFlusher ? addOutputFlusher(logs, outputFlusher) : logs;
8
8
  try {
9
9
  const configSideFiles = await listConfigSideFiles([headersPath, redirectsPath]);
@@ -38,6 +38,7 @@ export const fireCoreStep = async function ({ coreStep, coreStepId, coreStepName
38
38
  enhancedSecretScan,
39
39
  edgeFunctionsBootstrapURL,
40
40
  deployId,
41
+ returnValues,
41
42
  });
42
43
  const { netlifyConfig: netlifyConfigA, configMutations: configMutationsA, headersPath: headersPathA, redirectsPath: redirectsPathA, } = await updateNetlifyConfig({
43
44
  configOpts,
@@ -32,6 +32,7 @@ export function firePluginStep({ event, childProcess, packageName, packagePath,
32
32
  headersPath: any;
33
33
  redirectsPath: any;
34
34
  newStatus: any;
35
+ returnValue: any;
35
36
  newError?: undefined;
36
37
  } | {
37
38
  newError: any;
@@ -41,4 +42,5 @@ export function firePluginStep({ event, childProcess, packageName, packagePath,
41
42
  headersPath?: undefined;
42
43
  redirectsPath?: undefined;
43
44
  newStatus?: undefined;
45
+ returnValue?: undefined;
44
46
  }>;
@@ -18,7 +18,7 @@ export const firePluginStep = async function ({ event, childProcess, packageName
18
18
  const logsA = outputFlusher ? addOutputFlusher(logs, outputFlusher) : logs;
19
19
  try {
20
20
  const configSideFiles = await listConfigSideFiles([headersPath, redirectsPath]);
21
- const { newEnvChanges, configMutations: newConfigMutations, status, } = await callChild({
21
+ const { newEnvChanges, configMutations: newConfigMutations, returnValue, status, } = await callChild({
22
22
  childProcess,
23
23
  eventName: 'run',
24
24
  payload: {
@@ -58,6 +58,7 @@ export const firePluginStep = async function ({ event, childProcess, packageName
58
58
  headersPath: headersPathA,
59
59
  redirectsPath: redirectsPathA,
60
60
  newStatus,
61
+ returnValue,
61
62
  };
62
63
  }
63
64
  catch (newError) {
@@ -1,4 +1,4 @@
1
- export function getStepReturn({ event, packageName, newError, newEnvChanges, newStatus, coreStep, coreStepName: timerName, childEnv, mode, api, errorMonitor, deployId, netlifyConfig, configMutations, headersPath, redirectsPath, logs, outputFlusher, debug, timers, durationNs, testOpts, systemLog, quiet, metrics, }: {
1
+ export function getStepReturn({ event, packageName, newError, newEnvChanges, newStatus, coreStep, coreStepName: timerName, childEnv, mode, api, errorMonitor, deployId, netlifyConfig, configMutations, headersPath, redirectsPath, logs, outputFlusher, debug, timers, durationNs, testOpts, systemLog, quiet, metrics, returnValue, }: {
2
2
  event: any;
3
3
  packageName: any;
4
4
  newError: any;
@@ -24,6 +24,7 @@ export function getStepReturn({ event, packageName, newError, newEnvChanges, new
24
24
  systemLog: any;
25
25
  quiet: any;
26
26
  metrics: any;
27
+ returnValue: any;
27
28
  }): Promise<{
28
29
  failedPlugin: string[];
29
30
  newStatus: {
@@ -53,4 +54,5 @@ export function getStepReturn({ event, packageName, newError, newEnvChanges, new
53
54
  newStatus: any;
54
55
  timers: any;
55
56
  metrics: any;
57
+ returnValue: any;
56
58
  };
@@ -1,7 +1,7 @@
1
1
  import { logTimer } from '../log/messages/core.js';
2
2
  import { handleStepError } from './error.js';
3
3
  // Retrieve the return value of a step
4
- export const getStepReturn = function ({ event, packageName, newError, newEnvChanges, newStatus, coreStep, coreStepName: timerName = `${packageName} ${event}`, childEnv, mode, api, errorMonitor, deployId, netlifyConfig, configMutations, headersPath, redirectsPath, logs, outputFlusher, debug, timers, durationNs, testOpts, systemLog, quiet, metrics, }) {
4
+ export const getStepReturn = function ({ event, packageName, newError, newEnvChanges, newStatus, coreStep, coreStepName: timerName = `${packageName} ${event}`, childEnv, mode, api, errorMonitor, deployId, netlifyConfig, configMutations, headersPath, redirectsPath, logs, outputFlusher, debug, timers, durationNs, testOpts, systemLog, quiet, metrics, returnValue, }) {
5
5
  if (newError !== undefined) {
6
6
  return handleStepError({
7
7
  event,
@@ -21,5 +21,15 @@ export const getStepReturn = function ({ event, packageName, newError, newEnvCha
21
21
  if (!quiet) {
22
22
  logTimer(logs, durationNs, timerName, systemLog, outputFlusher);
23
23
  }
24
- return { newEnvChanges, netlifyConfig, configMutations, headersPath, redirectsPath, newStatus, timers, metrics };
24
+ return {
25
+ newEnvChanges,
26
+ netlifyConfig,
27
+ configMutations,
28
+ headersPath,
29
+ redirectsPath,
30
+ newStatus,
31
+ timers,
32
+ metrics,
33
+ returnValue,
34
+ };
25
35
  };
@@ -1,4 +1,4 @@
1
- export declare const runStep: ({ event, childProcess, packageName, coreStep, coreStepId, coreStepName, coreStepDescription, coreStepQuiet, pluginPackageJson, loadedFrom, origin, condition, configPath, outputConfigPath, buildDir, packagePath, repositoryRoot, nodePath, index, childEnv, context, branch, envChanges, constants, steps, buildbotServerSocket, events, mode, api, errorMonitor, deployId, errorParams, error, failedPlugins, configOpts, netlifyConfig, defaultConfig, configMutations, headersPath, redirectsPath, logs, debug, systemLog, verbose, saveConfig, timers, testOpts, featureFlags, quiet, userNodeVersion, explicitSecretKeys, enhancedSecretScan, edgeFunctionsBootstrapURL, extensionMetadata, }: {
1
+ export declare const runStep: ({ event, childProcess, packageName, coreStep, coreStepId, coreStepName, coreStepDescription, coreStepQuiet, pluginPackageJson, loadedFrom, origin, condition, configPath, outputConfigPath, buildDir, packagePath, repositoryRoot, nodePath, index, childEnv, context, branch, envChanges, constants, steps, buildbotServerSocket, events, mode, api, errorMonitor, deployId, errorParams, error, failedPlugins, configOpts, netlifyConfig, defaultConfig, configMutations, headersPath, redirectsPath, logs, debug, systemLog, verbose, saveConfig, timers, testOpts, featureFlags, quiet, userNodeVersion, explicitSecretKeys, enhancedSecretScan, edgeFunctionsBootstrapURL, extensionMetadata, returnValues, }: {
2
2
  event: any;
3
3
  childProcess: any;
4
4
  packageName: any;
@@ -53,4 +53,5 @@ export declare const runStep: ({ event, childProcess, packageName, coreStep, cor
53
53
  enhancedSecretScan: any;
54
54
  edgeFunctionsBootstrapURL: any;
55
55
  extensionMetadata: any;
56
+ returnValues: any;
56
57
  }) => Promise<{}>;
@@ -11,7 +11,7 @@ import { firePluginStep } from './plugin.js';
11
11
  import { getStepReturn } from './return.js';
12
12
  const tracer = trace.getTracer('steps');
13
13
  // Run a step (core, build command or plugin)
14
- export const runStep = async function ({ event, childProcess, packageName, coreStep, coreStepId, coreStepName, coreStepDescription, coreStepQuiet, pluginPackageJson, loadedFrom, origin, condition, configPath, outputConfigPath, buildDir, packagePath, repositoryRoot, nodePath, index, childEnv, context, branch, envChanges, constants, steps, buildbotServerSocket, events, mode, api, errorMonitor, deployId, errorParams, error, failedPlugins, configOpts, netlifyConfig, defaultConfig, configMutations, headersPath, redirectsPath, logs, debug, systemLog, verbose, saveConfig, timers, testOpts, featureFlags, quiet, userNodeVersion, explicitSecretKeys, enhancedSecretScan, edgeFunctionsBootstrapURL, extensionMetadata, }) {
14
+ export const runStep = async function ({ event, childProcess, packageName, coreStep, coreStepId, coreStepName, coreStepDescription, coreStepQuiet, pluginPackageJson, loadedFrom, origin, condition, configPath, outputConfigPath, buildDir, packagePath, repositoryRoot, nodePath, index, childEnv, context, branch, envChanges, constants, steps, buildbotServerSocket, events, mode, api, errorMonitor, deployId, errorParams, error, failedPlugins, configOpts, netlifyConfig, defaultConfig, configMutations, headersPath, redirectsPath, logs, debug, systemLog, verbose, saveConfig, timers, testOpts, featureFlags, quiet, userNodeVersion, explicitSecretKeys, enhancedSecretScan, edgeFunctionsBootstrapURL, extensionMetadata, returnValues, }) {
15
15
  // Add relevant attributes to the upcoming span context
16
16
  const attributes = {
17
17
  'build.execution.step.name': coreStepName,
@@ -47,6 +47,7 @@ export const runStep = async function ({ event, childProcess, packageName, coreS
47
47
  explicitSecretKeys,
48
48
  enhancedSecretScan,
49
49
  deployId,
50
+ returnValues,
50
51
  featureFlags,
51
52
  });
52
53
  span.setAttribute('build.execution.step.should_run', shouldRun);
@@ -61,7 +62,7 @@ export const runStep = async function ({ event, childProcess, packageName, coreS
61
62
  };
62
63
  const outputFlusher = new OutputFlusher(logPluginStart);
63
64
  const fireStep = getFireStep(packageName, coreStepId, event);
64
- const { newEnvChanges, netlifyConfig: netlifyConfigA = netlifyConfig, configMutations: configMutationsA = configMutations, headersPath: headersPathA = headersPath, redirectsPath: redirectsPathA = redirectsPath, newError, newStatus, timers: timersA, durationNs, metrics, } = await fireStep({
65
+ const { newEnvChanges, netlifyConfig: netlifyConfigA = netlifyConfig, configMutations: configMutationsA = configMutations, headersPath: headersPathA = headersPath, redirectsPath: redirectsPathA = redirectsPath, newError, newStatus, timers: timersA, durationNs, metrics, returnValue, } = await fireStep({
65
66
  extensionMetadata,
66
67
  defaultConfig,
67
68
  event,
@@ -109,6 +110,7 @@ export const runStep = async function ({ event, childProcess, packageName, coreS
109
110
  edgeFunctionsBootstrapURL,
110
111
  deployId,
111
112
  api,
113
+ returnValues,
112
114
  });
113
115
  const newValues = await getStepReturn({
114
116
  event,
@@ -136,6 +138,7 @@ export const runStep = async function ({ event, childProcess, packageName, coreS
136
138
  systemLog,
137
139
  quiet: quiet || coreStepQuiet,
138
140
  metrics,
141
+ returnValue,
139
142
  });
140
143
  span.end();
141
144
  return { ...newValues, newIndex: index + 1 };
@@ -172,7 +175,7 @@ export const runStep = async function ({ event, childProcess, packageName, coreS
172
175
  // or available. However, one might be created by a build plugin, in which case,
173
176
  // those core plugins should be triggered. We use a dynamic `condition()` to
174
177
  // model this behavior.
175
- const shouldRunStep = async function ({ event, packageName, error, packagePath, failedPlugins, netlifyConfig, condition, constants, buildbotServerSocket, buildDir, saveConfig, explicitSecretKeys, enhancedSecretScan, deployId, featureFlags = {}, }) {
178
+ const shouldRunStep = async function ({ event, packageName, error, packagePath, failedPlugins, netlifyConfig, condition, constants, buildbotServerSocket, buildDir, saveConfig, explicitSecretKeys, enhancedSecretScan, deployId, returnValues, featureFlags = {}, }) {
176
179
  if (failedPlugins.includes(packageName) ||
177
180
  (condition !== undefined &&
178
181
  !(await condition({
@@ -185,6 +188,7 @@ const shouldRunStep = async function ({ event, packageName, error, packagePath,
185
188
  explicitSecretKeys,
186
189
  enhancedSecretScan,
187
190
  deployId,
191
+ returnValues,
188
192
  featureFlags,
189
193
  })))) {
190
194
  return false;
@@ -202,7 +206,7 @@ const getFireStep = function (packageName, coreStepId, event) {
202
206
  const parentTag = normalizeTagName(packageName);
203
207
  return measureDuration(tFireStep, event, { parentTag, category: 'pluginEvent' });
204
208
  };
205
- const tFireStep = function ({ defaultConfig, event, childProcess, packageName, pluginPackageJson, loadedFrom, outputFlusher, origin, coreStep, coreStepId, coreStepName, configPath, outputConfigPath, buildDir, repositoryRoot, packagePath, nodePath, childEnv, context, branch, envChanges, constants, steps, buildbotServerSocket, events, error, logs, debug, quiet, systemLog, verbose, saveConfig, errorParams, configOpts, netlifyConfig, configMutations, headersPath, redirectsPath, featureFlags, userNodeVersion, explicitSecretKeys, enhancedSecretScan, edgeFunctionsBootstrapURL, deployId, extensionMetadata, api, }) {
209
+ const tFireStep = function ({ defaultConfig, event, childProcess, packageName, pluginPackageJson, loadedFrom, outputFlusher, origin, coreStep, coreStepId, coreStepName, configPath, outputConfigPath, buildDir, repositoryRoot, packagePath, nodePath, childEnv, context, branch, envChanges, constants, steps, buildbotServerSocket, events, error, logs, debug, quiet, systemLog, verbose, saveConfig, errorParams, configOpts, netlifyConfig, configMutations, headersPath, redirectsPath, featureFlags, userNodeVersion, explicitSecretKeys, enhancedSecretScan, edgeFunctionsBootstrapURL, deployId, extensionMetadata, api, returnValues, }) {
206
210
  if (coreStep !== undefined) {
207
211
  return fireCoreStep({
208
212
  coreStep,
@@ -241,6 +245,7 @@ const tFireStep = function ({ defaultConfig, event, childProcess, packageName, p
241
245
  edgeFunctionsBootstrapURL,
242
246
  deployId,
243
247
  api,
248
+ returnValues,
244
249
  });
245
250
  }
246
251
  return firePluginStep({
@@ -43,4 +43,5 @@ export function runSteps({ defaultConfig, steps, buildbotServerSocket, events, c
43
43
  timers: any;
44
44
  configMutations: never[];
45
45
  metrics: never[];
46
+ returnValues: {};
46
47
  }>;
@@ -8,8 +8,8 @@ import { runStep } from './run_step.js';
8
8
  // If an error arises, runs `onError` events.
9
9
  // Runs `onEnd` events at the end, whether an error was thrown or not.
10
10
  export const runSteps = async function ({ defaultConfig, steps, buildbotServerSocket, events, configPath, outputConfigPath, headersPath, redirectsPath, buildDir, packagePath, repositoryRoot, nodePath, childEnv, context, branch, constants, mode, api, errorMonitor, deployId, errorParams, netlifyConfig, configOpts, logs, debug, systemLog, verbose, saveConfig, timers, testOpts, featureFlags, quiet, userNodeVersion, explicitSecretKeys, enhancedSecretScan, edgeFunctionsBootstrapURL, }) {
11
- const { index: stepsCount, error: errorA, netlifyConfig: netlifyConfigC, statuses: statusesB, failedPlugins: failedPluginsA, timers: timersC, configMutations: configMutationsB, metrics: metricsC, } = await pReduce(steps, async ({ index, error, failedPlugins, envChanges, netlifyConfig: netlifyConfigA, configMutations, headersPath: headersPathA, redirectsPath: redirectsPathA, statuses, timers: timersA, metrics: metricsA, }, { event, childProcess, packageName, extensionMetadata, coreStep, coreStepId, coreStepName, coreStepDescription, pluginPackageJson, loadedFrom, origin, condition, quiet: coreStepQuiet, }) => {
12
- const { newIndex = index, newError = error, failedPlugin = [], newEnvChanges = {}, netlifyConfig: netlifyConfigB = netlifyConfigA, configMutations: configMutationsA = configMutations, headersPath: headersPathB = headersPathA, redirectsPath: redirectsPathB = redirectsPathA, newStatus, timers: timersB = timersA, metrics: metricsB = [], } = await runStep({
11
+ const { index: stepsCount, error: errorA, netlifyConfig: netlifyConfigC, statuses: statusesB, failedPlugins: failedPluginsA, timers: timersC, configMutations: configMutationsB, metrics: metricsC, returnValues, } = await pReduce(steps, async ({ index, error, failedPlugins, envChanges, netlifyConfig: netlifyConfigA, configMutations, headersPath: headersPathA, redirectsPath: redirectsPathA, statuses, timers: timersA, metrics: metricsA, returnValues, }, { event, childProcess, packageName, extensionMetadata, coreStep, coreStepId, coreStepName, coreStepDescription, pluginPackageJson, loadedFrom, origin, condition, quiet: coreStepQuiet, }) => {
12
+ const { newIndex = index, newError = error, failedPlugin = [], newEnvChanges = {}, netlifyConfig: netlifyConfigB = netlifyConfigA, configMutations: configMutationsA = configMutations, headersPath: headersPathB = headersPathA, redirectsPath: redirectsPathB = redirectsPathA, newStatus, timers: timersB = timersA, metrics: metricsB = [], returnValue, } = await runStep({
13
13
  event,
14
14
  childProcess,
15
15
  packageName,
@@ -44,6 +44,7 @@ export const runSteps = async function ({ defaultConfig, steps, buildbotServerSo
44
44
  deployId,
45
45
  errorParams,
46
46
  error,
47
+ returnValues,
47
48
  failedPlugins,
48
49
  configOpts,
49
50
  defaultConfig,
@@ -66,6 +67,14 @@ export const runSteps = async function ({ defaultConfig, steps, buildbotServerSo
66
67
  edgeFunctionsBootstrapURL,
67
68
  });
68
69
  const statusesA = addStatus({ newStatus, statuses, event, packageName, pluginPackageJson });
70
+ /** @type import('../types/step.js').ReturnValue */
71
+ const augmentedReturnValue = returnValue
72
+ ? {
73
+ ...returnValue,
74
+ displayName: extensionMetadata?.name || extensionMetadata?.slug || packageName,
75
+ generatorType: extensionMetadata ? 'extension' : 'build plugin',
76
+ }
77
+ : undefined;
69
78
  return {
70
79
  index: newIndex,
71
80
  error: newError,
@@ -78,6 +87,7 @@ export const runSteps = async function ({ defaultConfig, steps, buildbotServerSo
78
87
  statuses: statusesA,
79
88
  timers: timersB,
80
89
  metrics: [...metricsA, ...metricsB],
90
+ returnValues: augmentedReturnValue ? { ...returnValues, [packageName]: augmentedReturnValue } : returnValues,
81
91
  };
82
92
  }, {
83
93
  index: 0,
@@ -90,6 +100,7 @@ export const runSteps = async function ({ defaultConfig, steps, buildbotServerSo
90
100
  statuses: [],
91
101
  timers,
92
102
  metrics: [],
103
+ returnValues: {},
93
104
  });
94
105
  // Instead of throwing any build failure right away, we wait for `onError`,
95
106
  // etc. to complete. This is why we are throwing only now.
@@ -105,5 +116,6 @@ export const runSteps = async function ({ defaultConfig, steps, buildbotServerSo
105
116
  timers: timersC,
106
117
  configMutations: configMutationsB,
107
118
  metrics: metricsC,
119
+ returnValues,
108
120
  };
109
121
  };
@@ -24,5 +24,15 @@ export interface NetlifyPluginFunctionsUtil {
24
24
  * @param path Path to the function file or directory.
25
25
  */
26
26
  add(path: string): Promise<void>;
27
+ /**
28
+ * Registers a function generated by the plugin. Unlike `add`, which copies
29
+ * the function to the project directory, `generate` simply informs the build
30
+ * process that there's a function to be bundled at a specific location. The
31
+ * plugin is responsible for holding the source of the function and all the
32
+ * required files, including npm modules.
33
+ *
34
+ * @param mainFile Absolute path to the function's main file.
35
+ */
36
+ generate(mainFile: string): void;
27
37
  }
28
38
  export {};
@@ -0,0 +1,9 @@
1
+ interface GeneratedFunction {
2
+ path: string;
3
+ }
4
+ export interface ReturnValue {
5
+ displayName: string;
6
+ generatedFunctions?: GeneratedFunction[];
7
+ generatorType: 'build plugin' | 'extension';
8
+ }
9
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/build",
3
- "version": "33.4.7",
3
+ "version": "33.5.1",
4
4
  "description": "Netlify build module",
5
5
  "type": "module",
6
6
  "exports": "./lib/index.js",
@@ -67,16 +67,16 @@
67
67
  "license": "MIT",
68
68
  "dependencies": {
69
69
  "@bugsnag/js": "^8.0.0",
70
- "@netlify/blobs": "^10.0.1",
70
+ "@netlify/blobs": "^10.0.2",
71
71
  "@netlify/cache-utils": "^6.0.3",
72
72
  "@netlify/config": "^23.0.11",
73
73
  "@netlify/edge-bundler": "14.0.6",
74
- "@netlify/functions-utils": "^6.0.11",
74
+ "@netlify/functions-utils": "^6.0.13",
75
75
  "@netlify/git-utils": "^6.0.2",
76
76
  "@netlify/opentelemetry-utils": "^2.0.1",
77
77
  "@netlify/plugins-list": "^6.80.0",
78
78
  "@netlify/run-utils": "^6.0.2",
79
- "@netlify/zip-it-and-ship-it": "12.1.5",
79
+ "@netlify/zip-it-and-ship-it": "12.2.1",
80
80
  "@sindresorhus/slugify": "^2.0.0",
81
81
  "ansi-escapes": "^7.0.0",
82
82
  "chalk": "^5.0.0",
@@ -85,7 +85,7 @@
85
85
  "fdir": "^6.0.1",
86
86
  "figures": "^6.0.0",
87
87
  "filter-obj": "^6.0.0",
88
- "hot-shots": "10.2.1",
88
+ "hot-shots": "11.1.0",
89
89
  "indent-string": "^5.0.0",
90
90
  "is-plain-obj": "^4.0.0",
91
91
  "keep-func-props": "^6.0.0",
@@ -138,7 +138,7 @@
138
138
  "moize": "^6.0.0",
139
139
  "npm-run-all2": "^6.0.0",
140
140
  "process-exists": "^5.0.0",
141
- "sinon": "^20.0.0",
141
+ "sinon": "^21.0.0",
142
142
  "tmp-promise": "^3.0.2",
143
143
  "tsd": "^0.32.0",
144
144
  "vitest": "^3.0.0",
@@ -156,5 +156,5 @@
156
156
  "engines": {
157
157
  "node": ">=18.14.0"
158
158
  },
159
- "gitHead": "e663c8f1a5667e6737c689c33f7cabd6b2a98774"
159
+ "gitHead": "a317a69700be1392b54976ef34b456ac47d75f5a"
160
160
  }