From d7a432c994d2325cab769f60089cd882dc36677b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Antunes?= Date: Thu, 9 Nov 2023 17:35:51 +0000 Subject: [PATCH] chore(build): add types to errors in build (#5374) * chore(build): add types to errors in build * chore(build): s/type/types * chore(build): fixing some types * chore(build): just moving some things around * chore(build): error types JSDoc * chore(build): further restrict errorProps type * chore(build): simplify plugin parse types * chore(build): fix compilation errors --- packages/build/src/error/{info.js => info.ts} | 0 .../error/parse/{location.js => location.ts} | 19 +- .../src/error/parse/{parse.js => parse.ts} | 18 +- .../src/error/parse/{plugin.js => plugin.ts} | 15 +- .../{serialize_log.js => serialize_log.ts} | 3 + packages/build/src/error/type.js | 202 ---------- packages/build/src/error/types.ts | 375 ++++++++++++++++++ 7 files changed, 412 insertions(+), 220 deletions(-) rename packages/build/src/error/{info.js => info.ts} (100%) rename packages/build/src/error/parse/{location.js => location.ts} (78%) rename packages/build/src/error/parse/{parse.js => parse.ts} (77%) rename packages/build/src/error/parse/{plugin.js => plugin.ts} (74%) rename packages/build/src/error/parse/{serialize_log.js => serialize_log.ts} (93%) delete mode 100644 packages/build/src/error/type.js create mode 100644 packages/build/src/error/types.ts diff --git a/packages/build/src/error/info.js b/packages/build/src/error/info.ts similarity index 100% rename from packages/build/src/error/info.js rename to packages/build/src/error/info.ts diff --git a/packages/build/src/error/parse/location.js b/packages/build/src/error/parse/location.ts similarity index 78% rename from packages/build/src/error/parse/location.js rename to packages/build/src/error/parse/location.ts index 388c63cff8..c5042cb67f 100644 --- a/packages/build/src/error/parse/location.js +++ b/packages/build/src/error/parse/location.ts @@ -1,4 +1,11 @@ import { getBuildCommandDescription, getPluginOrigin } from '../../log/description.js' +import type { + BuildCommandLocation, + FunctionsBundlingLocation, + CoreStepLocation, + PluginLocation, + APILocation, +} from '../types.js' // Retrieve an error's location to print in logs. // Each error type has its own logic (or none if there's no location to print). @@ -17,13 +24,13 @@ export const getLocationInfo = function ({ stack, location, locationType }) { return [locationString, stack].filter(Boolean).join('\n') } -const getBuildCommandLocation = function ({ buildCommand, buildCommandOrigin }) { +const getBuildCommandLocation = function ({ buildCommand, buildCommandOrigin }: BuildCommandLocation) { const description = getBuildCommandDescription(buildCommandOrigin) return `In ${description}: ${buildCommand}` } -const getFunctionsBundlingLocation = function ({ functionName, functionType }) { +const getFunctionsBundlingLocation = function ({ functionName, functionType }: FunctionsBundlingLocation) { if (functionType === 'edge') { return 'While bundling edge function' } @@ -31,17 +38,17 @@ const getFunctionsBundlingLocation = function ({ functionName, functionType }) { return `While bundling function "${functionName}"` } -const getCoreStepLocation = function ({ coreStepName }) { +const getCoreStepLocation = function ({ coreStepName }: CoreStepLocation) { return `During ${coreStepName}` } -const getBuildFailLocation = function ({ event, packageName, loadedFrom, origin }) { +const getBuildFailLocation = function ({ event, packageName, loadedFrom, origin }: PluginLocation) { const eventMessage = getEventMessage(event) const pluginOrigin = getPluginOrigin(loadedFrom, origin) return `${eventMessage} "${packageName}" ${pluginOrigin}` } -const getEventMessage = function (event) { +const getEventMessage = function (event: string) { if (event === 'load') { return `While loading` } @@ -49,7 +56,7 @@ const getEventMessage = function (event) { return `In "${event}" event in` } -const getApiLocation = function ({ endpoint, parameters }) { +const getApiLocation = function ({ endpoint, parameters }: APILocation) { return `While calling the Netlify API endpoint '${endpoint}' with:\n${JSON.stringify(parameters, null, 2)}` } diff --git a/packages/build/src/error/parse/parse.js b/packages/build/src/error/parse/parse.ts similarity index 77% rename from packages/build/src/error/parse/parse.js rename to packages/build/src/error/parse/parse.ts index 37f88dec1f..0e81160b13 100644 --- a/packages/build/src/error/parse/parse.js +++ b/packages/build/src/error/parse/parse.ts @@ -1,6 +1,7 @@ import { serializeObject } from '../../log/serialize.js' import { getErrorInfo } from '../info.js' -import { getTypeInfo } from '../type.js' +import type { BuildError, BasicErrorInfo, ErrorInfo, TitleFunction } from '../types.js' +import { getTypeInfo } from '../types.js' import { getLocationInfo } from './location.js' import { normalizeError } from './normalize.js' @@ -9,14 +10,13 @@ import { getErrorProps } from './properties.js' import { getStackInfo } from './stack.js' // Add additional type-specific error information -export const getFullErrorInfo = function ({ error, colors, debug }) { +export const getFullErrorInfo = function ({ error, colors, debug }): BuildError { const basicErrorInfo = parseErrorInfo(error) const { message, stack, errorProps, errorInfo, - errorInfo: { location = {}, plugin = {}, tsConfig }, severity, title, stackType, @@ -26,11 +26,15 @@ export const getFullErrorInfo = function ({ error, colors, debug }) { errorMetadata, } = basicErrorInfo + const { location = {}, plugin = {}, tsConfig } = errorInfo + const titleA = getTitle(title, errorInfo) const { message: messageA, stack: stackA } = getStackInfo({ message, stack, stackType, rawStack, severity, debug }) - const pluginInfo = getPluginInfo(plugin, location) + // FIXME here location should be PluginLocation type, but I'm affraid to mess up the current + // getPluginInfo behaviour by running a type check + const pluginInfo = getPluginInfo(plugin, location as any) const tsConfigInfo = getTsConfigInfo(tsConfig) const locationInfo = getLocationInfo({ stack: stackA, location, locationType }) const errorPropsA = getErrorProps({ errorProps, showErrorProps, colors }) @@ -48,7 +52,7 @@ export const getFullErrorInfo = function ({ error, colors, debug }) { } // Serialize the `tsConfig` error information -const getTsConfigInfo = function (tsConfig) { +const getTsConfigInfo = function (tsConfig: any) { if (tsConfig === undefined) { return } @@ -57,7 +61,7 @@ const getTsConfigInfo = function (tsConfig) { } // Parse error instance into all the basic properties containing information -export const parseErrorInfo = function (error) { +export const parseErrorInfo = function (error: Error): BasicErrorInfo { const { message, stack, ...errorProps } = normalizeError(error) const [errorInfo, errorPropsA] = getErrorInfo(errorProps) const { errorMetadata } = errorInfo @@ -92,7 +96,7 @@ export const parseErrorInfo = function (error) { } // Retrieve title to print in logs -const getTitle = function (title, errorInfo) { +const getTitle = function (title: TitleFunction | string, errorInfo: ErrorInfo) { if (typeof title !== 'function') { return title } diff --git a/packages/build/src/error/parse/plugin.js b/packages/build/src/error/parse/plugin.ts similarity index 74% rename from packages/build/src/error/parse/plugin.js rename to packages/build/src/error/parse/plugin.ts index a89bac713c..a318342837 100644 --- a/packages/build/src/error/parse/plugin.js +++ b/packages/build/src/error/parse/plugin.ts @@ -24,7 +24,7 @@ const serializeField = function ({ name, getField, pluginPackageJson, packageNam const NAME_PADDING = 16 -const getPackage = function (pluginPackageJson, { packageName }) { +const getPackage = function (_, { packageName }) { return packageName } @@ -36,7 +36,12 @@ const getVersion = function ({ version }) { return version } -export const getHomepage = function (pluginPackageJson = {}, { loadedFrom } = {}) { +type pkgJSONData = { name?: string; bugs?: { url?: string }; repository?: { url?: string } } + +export const getHomepage = function ( + pluginPackageJson: pkgJSONData = {}, + { loadedFrom }: { loadedFrom?: string } = {}, +) { return ( getRepository(pluginPackageJson) || getNpmLink(pluginPackageJson, { loadedFrom }) || @@ -44,11 +49,11 @@ export const getHomepage = function (pluginPackageJson = {}, { loadedFrom } = {} ) } -const getRepository = function ({ repository: { url } = {} }) { +const getRepository = function ({ repository: { url } = {} }: pkgJSONData) { return url } -const getNpmLink = function ({ name }, { loadedFrom }) { +const getNpmLink = function ({ name }: pkgJSONData, { loadedFrom }: { loadedFrom?: string }) { if (!name || loadedFrom === 'local') { return } @@ -56,7 +61,7 @@ const getNpmLink = function ({ name }, { loadedFrom }) { return `https://www.npmjs.com/package/${name}` } -const getIssuesLink = function ({ bugs: { url } = {} }) { +const getIssuesLink = function ({ bugs: { url } = {} }: pkgJSONData) { return url } diff --git a/packages/build/src/error/parse/serialize_log.js b/packages/build/src/error/parse/serialize_log.ts similarity index 93% rename from packages/build/src/error/parse/serialize_log.js rename to packages/build/src/error/parse/serialize_log.ts index d89d891bf9..0fffd8d506 100644 --- a/packages/build/src/error/parse/serialize_log.js +++ b/packages/build/src/error/parse/serialize_log.ts @@ -1,8 +1,11 @@ import { THEME } from '../../log/theme.js' +import type { BuildError } from '../types.js' // Serialize an error object into a title|body string to print in logs export const serializeLogError = function ({ fullErrorInfo: { title, severity, message, pluginInfo, locationInfo, tsConfigInfo, errorProps }, +}: { + fullErrorInfo: BuildError }) { const body = getBody({ message, pluginInfo, locationInfo, tsConfigInfo, errorProps, severity }) return { title, body } diff --git a/packages/build/src/error/type.js b/packages/build/src/error/type.js deleted file mode 100644 index d5601c2a90..0000000000 --- a/packages/build/src/error/type.js +++ /dev/null @@ -1,202 +0,0 @@ -// Retrieve error-type specific information -export const getTypeInfo = function ({ type }) { - const typeA = TYPES[type] === undefined ? DEFAULT_TYPE : type - return { type: typeA, ...TYPES[typeA] } -} - -// List of error types, and their related properties -// Related to build error logs: -// - `showInBuildLog`: `true` when we want this error to show in build logs (defaults to true) -// - `title`: main title shown in build error logs and in the UI (statuses) -// - `locationType`: retrieve a human-friendly location of the error, printed -// in build error logs -// - `showErrorProps`: `true` when the `Error` instance static properties -// should be printed in build error logs. Only useful when the `Error` -// instance was not created by us. -// - `rawStack`: `true` when the stack trace should be cleaned up -// - `stackType`: how the stack trace should appear in build error logs: -// - `none`: not printed -// - `stack`: printed as is -// - `message`: printed as is, but taken from `error.message`. -// Used when `error.stack` is not being correct due to the error being -// passed between different processes. -// - `severity`: error severity (also used by Bugsnag): -// - `success`: build success -// - `none`: not an error, e.g. build cancellation -// - `info`: user error -// - `warning`: community plugin error -// - `error`: system error, including core plugin error -// Related to Bugsnag: -// - `group`: main title shown in Bugsnag. Also used to group errors together -// in Bugsnag, combined with `error.message`. -// Defaults to `title`. -// New error types should be added to Bugsnag since we use it for automated -// monitoring (through its Slack integration). The steps in Bugsnag are: -// - Create a new bookmark. Try to re-use the search filter of an existing -// bookmark with a similar error type, but only changing the `errorClass`. -// Make sure to check the box "Share with my team". -// - Add the `errorClass` to the search filter of either the "All warnings" or -// "All errors" bookmark depending on whether we should get notified on Slack -// for new errors of that type. You must use the bookmark menu action "Update -// with current filters" -const TYPES = { - // Plugin called `utils.build.cancelBuild()` - cancelBuild: { - title: ({ location: { packageName } }) => `Build canceled by ${packageName}`, - stackType: 'stack', - locationType: 'buildFail', - severity: 'none', - }, - - // User configuration error (`@netlify/config`, wrong Node.js version) - resolveConfig: { - title: 'Configuration error', - stackType: 'none', - severity: 'info', - }, - - // Error while installing user packages (missing plugins, local plugins or functions dependencies) - dependencies: { - title: 'Dependencies installation error', - stackType: 'none', - severity: 'info', - }, - - // User misconfigured a plugin - pluginInput: { - title: ({ location: { packageName, input } }) => `Plugin "${packageName}" invalid input "${input}"`, - stackType: 'none', - locationType: 'buildFail', - severity: 'info', - }, - - // User package.json sets an unsupported plugin version - pluginUnsupportedVersion: { - title: 'Unsupported plugin version detected', - stackType: 'none', - severity: 'info', - }, - - // `build.command` non-0 exit code - buildCommand: { - title: '"build.command" failed', - group: ({ location: { buildCommand } }) => buildCommand, - stackType: 'message', - locationType: 'buildCommand', - severity: 'info', - }, - - // User error during Functions bundling - functionsBundling: { - title: ({ location: { functionName, functionType } }) => { - if (functionType === 'edge') { - return 'Bundling of edge function failed' - } - - return `Bundling of function "${functionName}" failed` - }, - group: ({ location: { functionType = 'serverless' } }) => `Bundling of ${functionType} function failed`, - stackType: 'none', - locationType: 'functionsBundling', - severity: 'info', - }, - - secretScanningFoundSecrets: { - title: 'Secrets scanning detected secrets in files during build.', - stackType: 'none', - severity: 'info', - }, - - // Plugin called `utils.build.failBuild()` - failBuild: { - title: ({ location: { packageName } }) => `Plugin "${packageName}" failed`, - stackType: 'stack', - locationType: 'buildFail', - severity: 'info', - }, - - // Plugin called `utils.build.failPlugin()` - failPlugin: { - title: ({ location: { packageName } }) => `Plugin "${packageName}" failed`, - stackType: 'stack', - locationType: 'buildFail', - severity: 'info', - }, - - // Plugin has an invalid shape - pluginValidation: { - title: ({ location: { packageName } }) => `Plugin "${packageName}" internal error`, - stackType: 'stack', - locationType: 'buildFail', - severity: 'warning', - }, - - // Plugin threw an uncaught exception - pluginInternal: { - title: ({ location: { packageName } }) => `Plugin "${packageName}" internal error`, - stackType: 'stack', - showErrorProps: true, - rawStack: true, - locationType: 'buildFail', - severity: 'warning', - }, - - // Bug while orchestrating child processes - ipc: { - title: ({ location: { packageName } }) => `Plugin "${packageName}" internal error`, - stackType: 'none', - locationType: 'buildFail', - severity: 'warning', - }, - - // Core plugin internal error - corePlugin: { - title: ({ location: { packageName } }) => `Plugin "${packageName}" internal error`, - stackType: 'stack', - showErrorProps: true, - rawStack: true, - locationType: 'buildFail', - severity: 'error', - }, - - // Core step internal error - coreStep: { - title: ({ location: { coreStepName } }) => `Internal error during "${coreStepName}"`, - stackType: 'stack', - showErrorProps: true, - rawStack: true, - locationType: 'coreStep', - severity: 'error', - }, - - // Request error when `@netlify/build` was calling Netlify API - api: { - title: ({ location: { endpoint } }) => `API error on "${endpoint}"`, - stackType: 'message', - showErrorProps: true, - locationType: 'api', - severity: 'error', - }, - - // `@netlify/build` threw an uncaught exception - exception: { - title: 'Core internal error', - stackType: 'stack', - showErrorProps: true, - rawStack: true, - severity: 'error', - }, - - // Errors related with the telemetry output - telemetry: { - showInBuildLog: false, - title: 'Telemetry error', - stackType: 'stack', - showErrorProps: true, - rawStack: true, - severity: 'error', - }, -} - -// When no error type matches, it's an uncaught exception, i.e. a bug -const DEFAULT_TYPE = 'exception' diff --git a/packages/build/src/error/types.ts b/packages/build/src/error/types.ts new file mode 100644 index 0000000000..d4cbb31ab3 --- /dev/null +++ b/packages/build/src/error/types.ts @@ -0,0 +1,375 @@ +// We override errorProps and title through getTitle and getErrorProps +export type BuildError = Omit & { + title: string + pluginInfo?: string + locationInfo?: string + errorProps?: string +} + +export type BasicErrorInfo = { + message: string + stack: string + severity: string + type: ErrorTypes + errorInfo: ErrorInfo + errorProps: Record + errorMetadata: any + tsConfigInfo?: any +} & ErrorType + +/** + * Error severity groups the errors emitted by build and used to translate to exit code via SEVERITY_MAP + */ +enum ErrorSeverity { + /** + * build success + */ + success = 'success', + /** + * not an error, e.g. build cancellation + */ + none = 'none', + /** + * user error + */ + info = 'info', + /** + * community plugin error + */ + warning = 'warning', + /** + * system error, including core plugin error + */ + error = 'Error', +} + +/** + * How the stack trace should appear in the build error logs + */ +enum StackType { + /** + * not printed + */ + none = 'none', + /** + * printed as is + */ + stack = 'stack', + /** + * printed as is, but taken from `error.message`. Used when `error.stack` is not being correct due to the error being passed between different processes. + */ + message = 'message', +} + +type GroupFunction = ({ location }: { location: ErrorLocation }) => string +export type TitleFunction = ({ location }: { location: ErrorLocation }) => string + +export type ErrorInfo = { + plugin?: any + tsConfig?: any + location: ErrorLocation +} + +export type BuildCommandLocation = { + buildCommand: string + buildCommandOrigin: string +} + +export type FunctionsBundlingLocation = { + functionName: string + functionType: string +} + +export type CoreStepLocation = { + coreStepName: string +} + +export type PluginLocation = { + event: string + packageName: string + loadedFrom: string + origin: string + input?: string +} + +export type APILocation = { + endpoint: string + parameters?: any +} + +export type ErrorLocation = + | BuildCommandLocation + | FunctionsBundlingLocation + | CoreStepLocation + | PluginLocation + | APILocation + +/** + * Retrieve error-type specific information + */ +export const getTypeInfo = function ({ type }) { + const typeA = TYPES[type] === undefined ? DEFAULT_TYPE : type + return { type: typeA, ...TYPES[typeA] } +} + +/** + * Interface for build error types + */ +export interface ErrorType { + /** + * main title shown in build error logs and in the UI (statuses) + */ + title: TitleFunction | string + /** + * retrieve a human-friendly location of the error, printed + */ + locationType?: string + /** + * `true` when the `Error` instance static properties + */ + showErrorProps?: boolean + /** + * `true` when the stack trace should be cleaned up + */ + rawStack?: boolean + /** + * `true` when we want this error to show in build logs (defaults to true) + */ + showInBuildLog?: boolean + /** + * main title shown in Bugsnag. Also used to group errors together in Bugsnag, combined with `error.message`. Defaults to `title`. + */ + group?: GroupFunction + /** + * error severity (also used by Bugsnag) + */ + severity: keyof typeof ErrorSeverity + /** + * how the stack trace should appear in build error logs + */ + stackType: keyof typeof StackType +} + +const ErrorTypeMap = { + /** + * Plugin called `utils.build.cancelBuild()` + */ + cancelBuild: 'cancelBuild', + resolveConfig: 'resolveConfig', + dependencies: 'dependencies', + pluginInput: 'pluginInput', + pluginUnsupportedVersion: 'pluginUnsupportedVersion', + buildCommand: 'buildCommand', + functionsBundling: 'functionsBundling', + secretScanningFoundSecrets: 'secretScanningFoundSecrets', + failPlugin: 'failPlugin', + failBuild: 'failBuild', + pluginValidation: 'pluginValidation', + pluginInternal: 'pluginInternal', + ipc: 'ipc', + corePlugin: 'corePlugin', + coreStep: 'coreStep', + api: 'api', + exception: 'exception', + telemetry: 'telemetry', +} as const + +type ErrorTypes = keyof typeof ErrorTypeMap + +/** + * List of error types, and their related properties + * New error types should be added to Bugsnag since we use it for automated + * monitoring (through its Slack integration). The steps in Bugsnag are: + * - Create a new bookmark. Try to re-use the search filter of an existing + * bookmark with a similar error type, but only changing the `errorClass`. + * Make sure to check the box "Share with my team". + * - Add the `errorClass` to the search filter of either the "All warnings" or + * "All errors" bookmark depending on whether we should get notified on Slack + * for new errors of that type. You must use the bookmark menu action "Update + * with current filters" + * + */ +const TYPES: { [T in ErrorTypes]: ErrorType } = { + /** + * Plugin called `utils.build.cancelBuild()` + */ + cancelBuild: { + title: ({ location: { packageName } }: { location: PluginLocation }) => `Build canceled by ${packageName}`, + stackType: 'stack', + locationType: 'buildFail', + severity: 'none', + }, + /** + * User configuration error (`@netlify/config`, wrong Node.js version) + */ + resolveConfig: { + title: 'Configuration error', + stackType: 'none', + severity: 'info', + }, + /** + * Error while installing user packages (missing plugins, local plugins or functions dependencies) + */ + dependencies: { + title: 'Dependencies installation error', + stackType: 'none', + severity: 'info', + }, + /** + * User misconfigured a plugin + */ + pluginInput: { + title: ({ location: { packageName, input } }: { location: PluginLocation }) => + `Plugin "${packageName}" invalid input "${input}"`, + stackType: 'none', + locationType: 'buildFail', + severity: 'info', + }, + /** + * User package.json sets an unsupported plugin version + */ + pluginUnsupportedVersion: { + title: 'Unsupported plugin version detected', + stackType: 'none', + severity: 'info', + }, + /** + * `build.command` non-0 exit code + */ + buildCommand: { + title: '"build.command" failed', + group: ({ location: { buildCommand } }: { location: BuildCommandLocation }) => buildCommand, + stackType: 'message', + locationType: 'buildCommand', + severity: 'info', + }, + /** + * User error during Functions bundling + */ + functionsBundling: { + title: ({ location: { functionName, functionType } }: { location: FunctionsBundlingLocation }) => { + if (functionType === 'edge') { + return 'Bundling of edge function failed' + } + + return `Bundling of function "${functionName}" failed` + }, + group: ({ location: { functionType = 'serverless' } }: { location: FunctionsBundlingLocation }) => + `Bundling of ${functionType} function failed`, + stackType: 'none', + locationType: 'functionsBundling', + severity: 'info', + }, + /** + * Error from the secret scanning core step + */ + secretScanningFoundSecrets: { + title: 'Secrets scanning detected secrets in files during build.', + stackType: 'none', + severity: 'info', + }, + /** + * Plugin called `utils.build.failBuild()` + */ + failBuild: { + title: ({ location: { packageName } }: { location: PluginLocation }) => `Plugin "${packageName}" failed`, + stackType: 'stack', + locationType: 'buildFail', + severity: 'info', + }, + /** + * Plugin called `utils.build.failPlugin()` + */ + failPlugin: { + title: ({ location: { packageName } }: { location: PluginLocation }) => `Plugin "${packageName}" failed`, + stackType: 'stack', + locationType: 'buildFail', + severity: 'info', + }, + /** + * Plugin has an invalid shape + */ + pluginValidation: { + title: ({ location: { packageName } }: { location: PluginLocation }) => `Plugin "${packageName}" internal error`, + stackType: 'stack', + locationType: 'buildFail', + severity: 'warning', + }, + /** + * Plugin threw an uncaught exception + */ + pluginInternal: { + title: ({ location: { packageName } }: { location: PluginLocation }) => `Plugin "${packageName}" internal error`, + stackType: 'stack', + showErrorProps: true, + rawStack: true, + locationType: 'buildFail', + severity: 'warning', + }, + /** + * Bug while orchestrating child processes + */ + ipc: { + title: ({ location: { packageName } }: { location: PluginLocation }) => `Plugin "${packageName}" internal error`, + stackType: 'none', + locationType: 'buildFail', + severity: 'warning', + }, + /** + * Core plugin internal error + */ + corePlugin: { + title: ({ location: { packageName } }: { location: PluginLocation }) => `Plugin "${packageName}" internal error`, + stackType: 'stack', + showErrorProps: true, + rawStack: true, + locationType: 'buildFail', + severity: 'error', + }, + /** + * Core step internal error + */ + coreStep: { + title: ({ location: { coreStepName } }: { location: CoreStepLocation }) => + `Internal error during "${coreStepName}"`, + stackType: 'stack', + showErrorProps: true, + rawStack: true, + locationType: 'coreStep', + severity: 'error', + }, + /** + * Request error when `@netlify/build` was calling Netlify API + */ + api: { + title: ({ location: { endpoint } }: { location: APILocation }) => `API error on "${endpoint}"`, + stackType: 'message', + showErrorProps: true, + locationType: 'api', + severity: 'error', + }, + /** + * `@netlify/build` threw an uncaught exception + */ + exception: { + title: 'Core internal error', + stackType: 'stack', + showErrorProps: true, + rawStack: true, + severity: 'error', + }, + /** + * Errors related with the telemetry output + */ + telemetry: { + showInBuildLog: false, + title: 'Telemetry error', + stackType: 'stack', + showErrorProps: true, + rawStack: true, + severity: 'error', + }, +} as const + +// When no error type matches, it's an uncaught exception, i.e. a bug +const DEFAULT_TYPE = 'exception'