@netlify/build 33.4.6 → 33.5.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.
Files changed (43) hide show
  1. package/lib/core/build.js +1 -15
  2. package/lib/error/colors.js +8 -2
  3. package/lib/error/monitor/report.js +7 -1
  4. package/lib/error/types.d.ts +1 -1
  5. package/lib/log/messages/core_steps.d.ts +2 -1
  6. package/lib/log/messages/core_steps.js +18 -5
  7. package/lib/log/serialize.d.ts +2 -2
  8. package/lib/log/serialize.js +2 -2
  9. package/lib/plugins/child/run.d.ts +3 -0
  10. package/lib/plugins/child/run.js +4 -2
  11. package/lib/plugins/child/utils.d.ts +3 -1
  12. package/lib/plugins/child/utils.js +6 -4
  13. package/lib/plugins/compatibility.d.ts +1 -1
  14. package/lib/plugins/list.js +5 -2
  15. package/lib/plugins/manifest/load.js +4 -4
  16. package/lib/plugins/manifest/main.d.ts +1 -1
  17. package/lib/plugins/options.d.ts +1 -1
  18. package/lib/plugins/plugin_conditions.d.ts +1 -1
  19. package/lib/plugins/spawn.d.ts +1 -1
  20. package/lib/plugins_core/edge_functions/index.js +1 -0
  21. package/lib/plugins_core/functions/index.d.ts +5 -3
  22. package/lib/plugins_core/functions/index.js +45 -7
  23. package/lib/plugins_core/functions/zisi.d.ts +1 -1
  24. package/lib/steps/core_step.d.ts +2 -1
  25. package/lib/steps/core_step.js +2 -1
  26. package/lib/steps/plugin.d.ts +2 -0
  27. package/lib/steps/plugin.js +2 -1
  28. package/lib/steps/return.d.ts +3 -1
  29. package/lib/steps/return.js +12 -2
  30. package/lib/steps/run_step.d.ts +2 -1
  31. package/lib/steps/run_step.js +9 -4
  32. package/lib/steps/run_steps.d.ts +1 -0
  33. package/lib/steps/run_steps.js +14 -2
  34. package/lib/telemetry/main.d.ts +1 -3
  35. package/lib/telemetry/main.js +12 -7
  36. package/lib/types/options/netlify_plugin_functions_util.d.ts +12 -2
  37. package/lib/types/options/netlify_plugin_git_util.d.ts +2 -2
  38. package/lib/types/step.d.ts +9 -0
  39. package/lib/types/step.js +1 -0
  40. package/lib/types/utils/json_value.d.ts +1 -1
  41. package/lib/utils/omit.d.ts +1 -1
  42. package/lib/utils/package.d.ts +1 -1
  43. package/package.json +7 -8
package/lib/core/build.js CHANGED
@@ -19,10 +19,6 @@ import { doDryRun } from './dry.js';
19
19
  import { warnOnLingeringProcesses } from './lingering.js';
20
20
  import { warnOnMissingSideFiles } from './missing_side_file.js';
21
21
  import { normalizeFlags } from './normalize_flags.js';
22
- const supportedRuntimes = {
23
- next: { package: '@netlify/plugin-nextjs', skipFlag: 'NETLIFY_NEXT_PLUGIN_SKIP' },
24
- gatsby: { package: '@netlify/plugin-gatsby', skipFlag: 'NETLIFY_GATSBY_PLUGIN_SKIP' },
25
- };
26
22
  // Performed on build start. Must be kept small and unlikely to fail since it
27
23
  // does not have proper error handling. Error handling relies on `errorMonitor`
28
24
  // being built, which relies itself on flags being normalized.
@@ -36,7 +32,7 @@ export const startBuild = function (flags) {
36
32
  const errorMonitor = startErrorMonitor({ flags: { debug, systemLogFile, ...flagsA }, logs, bugsnagKey });
37
33
  return { ...flagsA, debug, systemLogFile, errorMonitor, logs, timers };
38
34
  };
39
- const tExecBuild = async function ({ config, defaultConfig, cachedConfig, cachedConfigPath, outputConfigPath, cwd, packagePath, repositoryRoot, apiHost, token, siteId, accountId, context, branch, baseRelDir, env: envOpt, debug, systemLogFile, verbose, nodePath, functionsDistDir, edgeFunctionsDistDir, cacheDir, dry, mode, offline, deployId, buildId, testOpts, errorMonitor, errorParams, logs, timers, buildbotServerSocket, sendStatus, saveConfig, featureFlags, timeline, devCommand, quiet, framework, explicitSecretKeys, enhancedSecretScan, edgeFunctionsBootstrapURL, eventHandlers, }) {
35
+ const tExecBuild = async function ({ config, defaultConfig, cachedConfig, cachedConfigPath, outputConfigPath, cwd, packagePath, repositoryRoot, apiHost, token, siteId, accountId, context, branch, baseRelDir, env: envOpt, debug, systemLogFile, verbose, nodePath, functionsDistDir, edgeFunctionsDistDir, cacheDir, dry, mode, offline, deployId, buildId, testOpts, errorMonitor, errorParams, logs, timers, buildbotServerSocket, sendStatus, saveConfig, featureFlags, timeline, devCommand, quiet, explicitSecretKeys, enhancedSecretScan, edgeFunctionsBootstrapURL, eventHandlers, }) {
40
36
  const configOpts = getConfigOpts({
41
37
  config,
42
38
  defaultConfig,
@@ -71,16 +67,6 @@ const tExecBuild = async function ({ config, defaultConfig, cachedConfig, cached
71
67
  quiet,
72
68
  featureFlags,
73
69
  });
74
- if (featureFlags.build_automatic_runtime && framework) {
75
- const runtime = supportedRuntimes[framework];
76
- if (runtime !== undefined) {
77
- const skip = childEnv[runtime.skipFlag] === 'true';
78
- const installed = netlifyConfig.plugins.some((plugin) => plugin.package === runtime.package);
79
- if (!installed && !skip) {
80
- netlifyConfig.plugins.push({ package: runtime.package });
81
- }
82
- }
83
- }
84
70
  const constants = await getConstants({
85
71
  configPath,
86
72
  buildDir,
@@ -4,6 +4,12 @@ export const removeErrorColors = function (error) {
4
4
  if (!(error instanceof Error)) {
5
5
  return;
6
6
  }
7
- error.message = stripAnsi(error.message);
8
- error.stack = stripAnsi(error.stack);
7
+ // Setting error values might fail if they are getters or are non-writable.
8
+ try {
9
+ error.message = stripAnsi(error.message);
10
+ error.stack = stripAnsi(error.stack);
11
+ }
12
+ catch {
13
+ // continue
14
+ }
9
15
  };
@@ -25,7 +25,13 @@ export const reportBuildError = async function ({ error, errorMonitor, childEnv,
25
25
  await reportError({ errorMonitor, error, logs, testOpts, eventProps });
26
26
  }
27
27
  finally {
28
- error.name = errorName;
28
+ try {
29
+ // Setting error values might fail if they are getters or are non-writable.
30
+ error.name = errorName;
31
+ }
32
+ catch {
33
+ // continue
34
+ }
29
35
  }
30
36
  };
31
37
  // Plugin authors test their plugins as local plugins. Errors there are more
@@ -1,4 +1,4 @@
1
- import { Attributes } from '@opentelemetry/api';
1
+ import { type Attributes } from '@opentelemetry/api';
2
2
  export type BuildError = Omit<BasicErrorInfo, 'errorProps'> & {
3
3
  title: string;
4
4
  pluginInfo?: string;
@@ -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
  };
@@ -1,2 +1,2 @@
1
- export function serializeObject(object: any): any;
2
- export function serializeArray(array: any): any;
1
+ export declare const serializeObject: (object: object) => string;
2
+ export declare const serializeArray: (array: string[]) => string;
@@ -1,6 +1,6 @@
1
- import { dump } from 'js-yaml';
1
+ import { stringify } from 'yaml';
2
2
  export const serializeObject = function (object) {
3
- return dump(object, { noRefs: true, sortKeys: true, lineWidth: Number.POSITIVE_INFINITY }).trimEnd();
3
+ return stringify(object, { sortMapEntries: true }).trimEnd();
4
4
  };
5
5
  export const serializeArray = function (array) {
6
6
  return array.map(addDash).join('\n');
@@ -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) };
@@ -1,4 +1,4 @@
1
- import { PackageJson } from 'read-package-up';
1
+ import { type PackageJson } from 'read-package-up';
2
2
  import { FeatureFlags } from '../core/feature_flags.js';
3
3
  import { SystemLogger } from '../plugins_core/types.js';
4
4
  import { PluginVersion } from './list.js';
@@ -1,5 +1,4 @@
1
1
  import { pluginsUrl, pluginsList as oldPluginsList } from '@netlify/plugins-list';
2
- import got from 'got';
3
2
  import isPlainObj from 'is-plain-obj';
4
3
  import { logPluginsList, logPluginsFetchError } from '../log/messages/plugins.js';
5
4
  import { CONDITIONS } from './plugin_conditions.js';
@@ -28,7 +27,11 @@ export const getPluginsList = async function ({ debug, logs, testOpts: { plugins
28
27
  };
29
28
  const fetchPluginsList = async function ({ logs, pluginsListUrl, }) {
30
29
  try {
31
- const { body } = await got(pluginsListUrl, { responseType: 'json', timeout: { request: PLUGINS_LIST_TIMEOUT } });
30
+ const response = await fetch(pluginsListUrl, { signal: AbortSignal.timeout(PLUGINS_LIST_TIMEOUT) });
31
+ if (!response.ok) {
32
+ throw new Error(`Request failed with a response code: ${response.status.toString()}`);
33
+ }
34
+ const body = await response.json();
32
35
  if (!isValidPluginsList(body)) {
33
36
  throw new Error(`Request succeeded but with an invalid response:\n${JSON.stringify(body, null, 2)}`);
34
37
  }
@@ -1,12 +1,12 @@
1
1
  import { promises as fs } from 'fs';
2
- import { load as loadYaml, JSON_SCHEMA } from 'js-yaml';
2
+ import { parse } from 'yaml';
3
3
  import { addErrorInfo } from '../../error/info.js';
4
4
  import { validateManifest } from './validate.js';
5
5
  // Load "manifest.yml" using its file path
6
6
  export const loadManifest = async function ({ manifestPath, packageName, pluginPackageJson, loadedFrom, origin }) {
7
7
  try {
8
8
  const rawManifest = await loadRawManifest(manifestPath);
9
- const manifest = await parseManifest(rawManifest);
9
+ const manifest = parseManifest(rawManifest);
10
10
  validateManifest(manifest, rawManifest);
11
11
  return manifest;
12
12
  }
@@ -28,9 +28,9 @@ const loadRawManifest = async function (manifestPath) {
28
28
  throw error;
29
29
  }
30
30
  };
31
- const parseManifest = async function (rawManifest) {
31
+ const parseManifest = function (rawManifest) {
32
32
  try {
33
- return await loadYaml(rawManifest, { schema: JSON_SCHEMA, json: true });
33
+ return parse(rawManifest, { logLevel: 'error' });
34
34
  }
35
35
  catch (error) {
36
36
  throw new Error(`Could not parse plugin's "manifest.yml"\n${error.message}`);
@@ -1,4 +1,4 @@
1
- import { PackageJson } from 'read-package-up';
1
+ import { type PackageJson } from 'read-package-up';
2
2
  /**
3
3
  * Load plugin's `manifest.yml`
4
4
  */
@@ -1,4 +1,4 @@
1
- import { PackageJson } from 'read-package-up';
1
+ import { type PackageJson } from 'read-package-up';
2
2
  export declare const getPluginsOptions: ({ timers, ...opts }: {
3
3
  [x: string]: any;
4
4
  timers: any;
@@ -1,4 +1,4 @@
1
- import { PackageJson } from 'read-package-up';
1
+ import { type PackageJson } from 'read-package-up';
2
2
  import { type PluginVersion } from './list.js';
3
3
  type ConditionContext = {
4
4
  nodeVersion: string;
@@ -1,4 +1,4 @@
1
- import { ExecaChildProcess } from 'execa';
1
+ import { type ExecaChildProcess } from 'execa';
2
2
  import { NetlifyConfig } from '../index.js';
3
3
  import { BufferedLogs } from '../log/logger.js';
4
4
  import { PluginsOptions } from './node_version.js';
@@ -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
- import { zipFunctions, FunctionResult } from '@netlify/zip-it-and-ship-it';
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
- import { FunctionConfig, ZipFunctionsOptions } from '@netlify/zip-it-and-ship-it';
1
+ import { type FunctionConfig, type ZipFunctionsOptions } from '@netlify/zip-it-and-ship-it';
2
2
  import type { FeatureFlags } from '../../core/feature_flags.js';
3
3
  type GetZisiParametersType = {
4
4
  branch?: string;
@@ -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
  };
@@ -11,8 +11,6 @@ export declare const trackBuildComplete: ({ deployId, buildId, status, stepsCoun
11
11
  framework: any;
12
12
  testOpts: {
13
13
  telemetryOrigin?: string | undefined;
14
- telemetryTimeout?: {
15
- request: number;
16
- } | undefined;
14
+ telemetryTimeout?: number | undefined;
17
15
  };
18
16
  }) => Promise<void>;
@@ -1,5 +1,4 @@
1
1
  import { platform } from 'process';
2
- import got from 'got';
3
2
  import osName from 'os-name';
4
3
  import { addErrorInfo } from '../error/info.js';
5
4
  import { roundTimerToMillisecs } from '../time/measure.js';
@@ -8,7 +7,7 @@ const DEFAULT_TELEMETRY_TIMEOUT = 1200;
8
7
  const DEFAULT_TELEMETRY_CONFIG = {
9
8
  origin: 'https://api.segment.io/v1',
10
9
  writeKey: 'dWhlM1lYSlpNd1k5Uk9rcjFra2JSOEoybnRjZjl0YTI6',
11
- timeout: { request: DEFAULT_TELEMETRY_TIMEOUT },
10
+ timeout: DEFAULT_TELEMETRY_TIMEOUT,
12
11
  };
13
12
  // Send telemetry request when build completes
14
13
  export const trackBuildComplete = async function ({ deployId, buildId, status, stepsCount, pluginsOptions, durationNs, siteInfo, telemetry, userNodeVersion, framework, testOpts: { telemetryOrigin = DEFAULT_TELEMETRY_CONFIG.origin, telemetryTimeout = DEFAULT_TELEMETRY_CONFIG.timeout }, }) {
@@ -37,12 +36,18 @@ export const trackBuildComplete = async function ({ deployId, buildId, status, s
37
36
  // Send track HTTP request to telemetry.
38
37
  const track = async function (payload, { origin, writeKey, timeout }) {
39
38
  const url = `${origin}/track`;
40
- await got.post(url, {
41
- json: payload,
42
- timeout,
43
- retry: { limit: 0 },
44
- headers: { Authorization: `Basic ${writeKey}` },
39
+ const response = await fetch(url, {
40
+ method: 'POST',
41
+ body: JSON.stringify(payload),
42
+ signal: AbortSignal.timeout(timeout),
43
+ headers: {
44
+ 'Content-Type': 'application/json',
45
+ Authorization: `Basic ${writeKey}`,
46
+ },
45
47
  });
48
+ if (!response.ok) {
49
+ throw new Error(`Response code: ${response.status.toString()}`);
50
+ }
46
51
  };
47
52
  // Retrieve telemetry information
48
53
  // siteInfo can be empty if the build fails during the get config step
@@ -11,18 +11,28 @@ export interface NetlifyPluginFunctionsUtil {
11
11
  * - `extension`: file extension of the Function's main file. For Go Functions, this might be an empty string. For Node.js Functions, this is either `.js` or `.zip`.
12
12
  * - `runtime` `"js" | "go"`: Function's language runtime. TypeScript Functions use the "js" runtime
13
13
  */
14
- list(): Promise<Array<ListedFunction>>;
14
+ list(): Promise<ListedFunction[]>;
15
15
  /**
16
16
  * Same as `list()` except it also returns the files required by the Functions' main files. This is much slower. The object have the following additional member:
17
17
  *
18
18
  * - `srcFile`: absolute path to the file
19
19
  */
20
- listAll(): Promise<Array<ListedFunctionFile>>;
20
+ listAll(): Promise<ListedFunctionFile[]>;
21
21
  /**
22
22
  * Add a Functions file or directory to a build.
23
23
  *
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 {};
@@ -19,7 +19,7 @@ export interface NetlifyPluginGitUtil {
19
19
  /**
20
20
  * Array of commits with details.
21
21
  */
22
- commits: ReadonlyArray<{
22
+ commits: readonly {
23
23
  sha: string;
24
24
  parents: string;
25
25
  author: {
@@ -33,7 +33,7 @@ export interface NetlifyPluginGitUtil {
33
33
  date: string;
34
34
  };
35
35
  message: string;
36
- }>;
36
+ }[];
37
37
  /**
38
38
  * How many lines of code have changed
39
39
  */
@@ -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 {};
@@ -1,3 +1,3 @@
1
1
  export type JSONValue = string | number | boolean | null | {
2
2
  [key: string]: JSONValue;
3
- } | Array<JSONValue>;
3
+ } | JSONValue[];
@@ -1 +1 @@
1
- export declare const omit: <T extends object>(obj: T, keys: Array<keyof T>) => Partial<T>;
1
+ export declare const omit: <T extends object>(obj: T, keys: (keyof T)[]) => Partial<T>;
@@ -1,4 +1,4 @@
1
- import { Options, PackageJson } from 'read-package-up';
1
+ import { type Options, type PackageJson } from 'read-package-up';
2
2
  type PackageResult = {
3
3
  packageJson: PackageJson;
4
4
  packageDir?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/build",
3
- "version": "33.4.6",
3
+ "version": "33.5.0",
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.0",
70
+ "@netlify/blobs": "^10.0.1",
71
71
  "@netlify/cache-utils": "^6.0.3",
72
- "@netlify/config": "^23.0.10",
72
+ "@netlify/config": "^23.0.11",
73
73
  "@netlify/edge-bundler": "14.0.6",
74
- "@netlify/functions-utils": "^6.0.10",
74
+ "@netlify/functions-utils": "^6.0.12",
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.4",
79
+ "@netlify/zip-it-and-ship-it": "12.2.0",
80
80
  "@sindresorhus/slugify": "^2.0.0",
81
81
  "ansi-escapes": "^7.0.0",
82
82
  "chalk": "^5.0.0",
@@ -85,11 +85,9 @@
85
85
  "fdir": "^6.0.1",
86
86
  "figures": "^6.0.0",
87
87
  "filter-obj": "^6.0.0",
88
- "got": "^13.0.0",
89
88
  "hot-shots": "10.2.1",
90
89
  "indent-string": "^5.0.0",
91
90
  "is-plain-obj": "^4.0.0",
92
- "js-yaml": "^4.0.0",
93
91
  "keep-func-props": "^6.0.0",
94
92
  "locate-path": "^7.0.0",
95
93
  "log-process-errors": "^11.0.0",
@@ -121,6 +119,7 @@
121
119
  "ts-node": "^10.9.1",
122
120
  "typescript": "^5.0.0",
123
121
  "uuid": "^11.0.0",
122
+ "yaml": "^2.8.0",
124
123
  "yargs": "^17.6.0"
125
124
  },
126
125
  "devDependencies": {
@@ -157,5 +156,5 @@
157
156
  "engines": {
158
157
  "node": ">=18.14.0"
159
158
  },
160
- "gitHead": "26f76a720b12a59fa65c638d73fddbc2259fa2d8"
159
+ "gitHead": "1c03ad22e24821b3a4803e54e8eeaa5a15c509d6"
161
160
  }