@netlify/build 29.0.0-rc → 29.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin.js +5 -0
- package/lib/core/bin.js +66 -0
- package/lib/core/build.js +356 -0
- package/lib/core/config.js +121 -0
- package/lib/core/constants.js +116 -0
- package/lib/core/dev.js +27 -0
- package/lib/core/dry.js +21 -0
- package/lib/core/feature_flags.js +21 -0
- package/lib/core/flags.js +201 -0
- package/lib/core/lingering.js +68 -0
- package/lib/core/main.js +110 -0
- package/lib/core/missing_side_file.js +17 -0
- package/lib/core/normalize_flags.js +59 -0
- package/lib/core/severity.js +21 -0
- package/lib/core/types.js +8 -0
- package/lib/core/user_node_version.js +32 -0
- package/lib/env/changes.js +43 -0
- package/lib/env/main.js +14 -0
- package/lib/env/metadata.js +68 -0
- package/lib/error/api.js +37 -0
- package/lib/error/build.js +36 -0
- package/{src → lib}/error/cancel.js +5 -6
- package/lib/error/colors.js +9 -0
- package/lib/error/handle.js +46 -0
- package/lib/error/info.js +37 -0
- package/lib/error/monitor/location.js +16 -0
- package/lib/error/monitor/normalize.js +86 -0
- package/lib/error/monitor/print.js +20 -0
- package/lib/error/monitor/report.js +120 -0
- package/lib/error/monitor/start.js +61 -0
- package/lib/error/parse/clean_stack.js +70 -0
- package/lib/error/parse/location.js +50 -0
- package/lib/error/parse/normalize.js +24 -0
- package/lib/error/parse/parse.js +67 -0
- package/lib/error/parse/plugin.js +55 -0
- package/lib/error/parse/properties.js +16 -0
- package/lib/error/parse/serialize_log.js +34 -0
- package/lib/error/parse/serialize_status.js +18 -0
- package/lib/error/parse/stack.js +34 -0
- package/lib/error/report.js +27 -0
- package/lib/error/type.js +177 -0
- package/lib/install/functions.js +20 -0
- package/lib/install/local.js +45 -0
- package/lib/install/main.js +67 -0
- package/lib/install/missing.js +54 -0
- package/lib/log/colors.js +28 -0
- package/lib/log/description.js +21 -0
- package/lib/log/header.js +14 -0
- package/lib/log/header_func.js +13 -0
- package/lib/log/logger.js +140 -0
- package/lib/log/messages/compatibility.js +146 -0
- package/lib/log/messages/config.js +91 -0
- package/lib/log/messages/core.js +51 -0
- package/lib/log/messages/core_steps.js +75 -0
- package/lib/log/messages/dry.js +41 -0
- package/lib/log/messages/install.js +25 -0
- package/lib/log/messages/ipc.js +29 -0
- package/lib/log/messages/mutations.js +62 -0
- package/{src → lib}/log/messages/plugins.js +18 -32
- package/lib/log/messages/status.js +14 -0
- package/lib/log/messages/steps.js +18 -0
- package/lib/log/old_version.js +32 -0
- package/lib/log/serialize.js +10 -0
- package/lib/log/stream.js +68 -0
- package/lib/log/theme.js +27 -0
- package/lib/plugins/child/diff.js +46 -0
- package/lib/plugins/child/error.js +26 -0
- package/lib/plugins/child/lazy.js +15 -0
- package/lib/plugins/child/load.js +22 -0
- package/lib/plugins/child/logic.js +57 -0
- package/lib/plugins/child/main.js +37 -0
- package/lib/plugins/child/run.js +19 -0
- package/lib/plugins/child/status.js +63 -0
- package/lib/plugins/child/typescript.js +28 -0
- package/lib/plugins/child/utils.js +42 -0
- package/lib/plugins/child/validate.js +31 -0
- package/lib/plugins/compatibility.js +104 -0
- package/{src → lib}/plugins/error.js +31 -35
- package/{src → lib}/plugins/events.js +7 -12
- package/lib/plugins/expected_version.js +81 -0
- package/lib/plugins/internal.js +10 -0
- package/lib/plugins/ipc.js +120 -0
- package/lib/plugins/list.js +73 -0
- package/lib/plugins/load.js +50 -0
- package/lib/plugins/manifest/check.js +85 -0
- package/lib/plugins/manifest/load.js +38 -0
- package/lib/plugins/manifest/main.js +19 -0
- package/lib/plugins/manifest/path.js +24 -0
- package/lib/plugins/manifest/validate.js +91 -0
- package/lib/plugins/node_version.js +35 -0
- package/lib/plugins/options.js +70 -0
- package/lib/plugins/pinned_version.js +83 -0
- package/lib/plugins/resolve.js +110 -0
- package/lib/plugins/spawn.js +58 -0
- package/lib/plugins_core/add.js +35 -0
- package/lib/plugins_core/build_command.js +50 -0
- package/lib/plugins_core/deploy/buildbot_client.js +87 -0
- package/lib/plugins_core/deploy/index.js +49 -0
- package/{src → lib}/plugins_core/deploy/manifest.yml +0 -0
- package/lib/plugins_core/edge_functions/index.js +76 -0
- package/{src → lib}/plugins_core/edge_functions/lib/error.js +13 -17
- package/lib/plugins_core/edge_functions/validate_manifest/validate_edge_functions_manifest.js +21 -0
- package/lib/plugins_core/functions/error.js +123 -0
- package/lib/plugins_core/functions/feature_flags.js +6 -0
- package/lib/plugins_core/functions/index.js +114 -0
- package/lib/plugins_core/functions/utils.js +45 -0
- package/lib/plugins_core/functions/zisi.js +39 -0
- package/{src → lib}/plugins_core/functions_install/index.js +8 -11
- package/{src → lib}/plugins_core/functions_install/manifest.yml +0 -0
- package/lib/plugins_core/list.js +20 -0
- package/lib/report/statsd.js +31 -0
- package/lib/status/add.js +30 -0
- package/lib/status/colors.js +18 -0
- package/lib/status/load_error.js +10 -0
- package/lib/status/report.js +83 -0
- package/lib/status/success.js +14 -0
- package/lib/steps/core_step.js +59 -0
- package/lib/steps/error.js +65 -0
- package/lib/steps/get.js +43 -0
- package/lib/steps/plugin.js +55 -0
- package/lib/steps/return.js +25 -0
- package/lib/steps/run_core_steps.js +117 -0
- package/lib/steps/run_step.js +190 -0
- package/lib/steps/run_steps.js +96 -0
- package/lib/steps/update_config.js +66 -0
- package/lib/telemetry/main.js +97 -0
- package/lib/time/aggregate.js +109 -0
- package/lib/time/main.js +31 -0
- package/lib/time/measure.js +16 -0
- package/lib/time/report.js +24 -0
- package/lib/utils/errors.js +13 -0
- package/lib/utils/json.js +15 -0
- package/lib/utils/omit.js +3 -0
- package/lib/utils/package.js +24 -0
- package/lib/utils/remove_falsy.js +8 -0
- package/lib/utils/resolve.js +41 -0
- package/lib/utils/runtime.js +5 -0
- package/lib/utils/semver.js +28 -0
- package/package.json +41 -24
- package/types/config/netlify_config.d.ts +4 -4
- package/types/netlify_plugin_constants.d.ts +8 -8
- package/src/core/bin.js +0 -83
- package/src/core/build.js +0 -554
- package/src/core/config.js +0 -186
- package/src/core/constants.js +0 -156
- package/src/core/dev.js +0 -31
- package/src/core/dry.js +0 -39
- package/src/core/feature_flags.js +0 -22
- package/src/core/flags.js +0 -204
- package/src/core/lingering.js +0 -85
- package/src/core/main.js +0 -165
- package/src/core/missing_side_file.js +0 -29
- package/src/core/normalize_flags.js +0 -70
- package/src/core/severity.js +0 -22
- package/src/core/user_node_version.js +0 -41
- package/src/env/changes.js +0 -52
- package/src/env/main.js +0 -19
- package/src/env/metadata.js +0 -81
- package/src/error/api.js +0 -46
- package/src/error/build.js +0 -50
- package/src/error/colors.js +0 -11
- package/src/error/handle.js +0 -57
- package/src/error/info.js +0 -46
- package/src/error/monitor/location.js +0 -21
- package/src/error/monitor/normalize.js +0 -96
- package/src/error/monitor/print.js +0 -42
- package/src/error/monitor/report.js +0 -138
- package/src/error/monitor/start.js +0 -69
- package/src/error/parse/clean_stack.js +0 -87
- package/src/error/parse/location.js +0 -62
- package/src/error/parse/normalize.js +0 -29
- package/src/error/parse/parse.js +0 -97
- package/src/error/parse/plugin.js +0 -70
- package/src/error/parse/properties.js +0 -23
- package/src/error/parse/serialize_log.js +0 -42
- package/src/error/parse/serialize_status.js +0 -23
- package/src/error/parse/stack.js +0 -43
- package/src/error/type.js +0 -189
- package/src/install/functions.js +0 -28
- package/src/install/local.js +0 -62
- package/src/install/main.js +0 -81
- package/src/install/missing.js +0 -67
- package/src/log/colors.js +0 -34
- package/src/log/description.js +0 -26
- package/src/log/header.js +0 -16
- package/src/log/header_func.js +0 -17
- package/src/log/logger.js +0 -161
- package/src/log/messages/compatibility.js +0 -164
- package/src/log/messages/config.js +0 -107
- package/src/log/messages/core.js +0 -70
- package/src/log/messages/core_steps.js +0 -104
- package/src/log/messages/dry.js +0 -63
- package/src/log/messages/install.js +0 -20
- package/src/log/messages/ipc.js +0 -38
- package/src/log/messages/mutations.js +0 -82
- package/src/log/messages/status.js +0 -16
- package/src/log/messages/steps.js +0 -22
- package/src/log/old_version.js +0 -41
- package/src/log/serialize.js +0 -13
- package/src/log/stream.js +0 -85
- package/src/log/theme.js +0 -26
- package/src/plugins/child/diff.js +0 -55
- package/src/plugins/child/error.js +0 -32
- package/src/plugins/child/lazy.js +0 -18
- package/src/plugins/child/load.js +0 -29
- package/src/plugins/child/logic.js +0 -57
- package/src/plugins/child/main.js +0 -51
- package/src/plugins/child/run.js +0 -28
- package/src/plugins/child/status.js +0 -74
- package/src/plugins/child/typescript.js +0 -45
- package/src/plugins/child/utils.js +0 -56
- package/src/plugins/child/validate.js +0 -34
- package/src/plugins/compatibility.js +0 -128
- package/src/plugins/expected_version.js +0 -119
- package/src/plugins/ipc.js +0 -145
- package/src/plugins/list.js +0 -86
- package/src/plugins/load.js +0 -70
- package/src/plugins/manifest/check.js +0 -106
- package/src/plugins/manifest/load.js +0 -41
- package/src/plugins/manifest/main.js +0 -22
- package/src/plugins/manifest/path.js +0 -31
- package/src/plugins/manifest/validate.js +0 -108
- package/src/plugins/node_version.js +0 -50
- package/src/plugins/options.js +0 -88
- package/src/plugins/pinned_version.js +0 -131
- package/src/plugins/resolve.js +0 -152
- package/src/plugins/spawn.js +0 -66
- package/src/plugins_core/add.js +0 -49
- package/src/plugins_core/build_command.js +0 -75
- package/src/plugins_core/deploy/buildbot_client.js +0 -102
- package/src/plugins_core/deploy/index.js +0 -73
- package/src/plugins_core/edge_functions/index.js +0 -123
- package/src/plugins_core/edge_functions/lib/internal_manifest.js +0 -54
- package/src/plugins_core/edge_functions/validate_manifest/validate_edge_functions_manifest.js +0 -89
- package/src/plugins_core/functions/error.js +0 -163
- package/src/plugins_core/functions/feature_flags.js +0 -6
- package/src/plugins_core/functions/index.js +0 -160
- package/src/plugins_core/functions/utils.js +0 -66
- package/src/plugins_core/functions/zisi.js +0 -53
- package/src/plugins_core/list.js +0 -27
- package/src/status/add.js +0 -36
- package/src/status/colors.js +0 -23
- package/src/status/load_error.js +0 -11
- package/src/status/report.js +0 -137
- package/src/status/success.js +0 -18
- package/src/steps/core_step.js +0 -92
- package/src/steps/error.js +0 -102
- package/src/steps/get.js +0 -51
- package/src/steps/plugin.js +0 -85
- package/src/steps/return.js +0 -52
- package/src/steps/run_core_steps.js +0 -200
- package/src/steps/run_step.js +0 -304
- package/src/steps/run_steps.js +0 -179
- package/src/steps/update_config.js +0 -93
- package/src/telemetry/main.js +0 -136
- package/src/time/aggregate.js +0 -146
- package/src/time/main.js +0 -48
- package/src/time/measure.js +0 -22
- package/src/time/report.js +0 -59
- package/src/utils/errors.js +0 -12
- package/src/utils/json.js +0 -19
- package/src/utils/omit.js +0 -6
- package/src/utils/package.js +0 -23
- package/src/utils/remove_falsy.js +0 -10
- package/src/utils/resolve.js +0 -46
- package/src/utils/semver.js +0 -34
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import isPlainObj from 'is-plain-obj';
|
|
2
|
+
import mapObj from 'map-obj';
|
|
3
|
+
import { addErrorInfo } from '../../error/info.js';
|
|
4
|
+
// Report status information to the UI
|
|
5
|
+
export const show = function (runState, showArgs) {
|
|
6
|
+
validateShowArgs(showArgs);
|
|
7
|
+
const { title, summary, text, extraData } = removeEmptyStrings(showArgs);
|
|
8
|
+
runState.status = { state: 'success', title, summary, text, extraData };
|
|
9
|
+
};
|
|
10
|
+
// Validate arguments of `utils.status.show()`
|
|
11
|
+
const validateShowArgs = function (showArgs) {
|
|
12
|
+
try {
|
|
13
|
+
validateShowArgsObject(showArgs);
|
|
14
|
+
const { title, summary, text, extraData, ...otherArgs } = showArgs;
|
|
15
|
+
validateShowArgsKeys(otherArgs);
|
|
16
|
+
Object.entries({ title, summary, text }).forEach(validateStringArg);
|
|
17
|
+
validateShowArgsSummary(summary);
|
|
18
|
+
validateShowArgsExtraData(extraData);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
error.message = `utils.status.show() ${error.message}`;
|
|
22
|
+
addErrorInfo(error, { type: 'pluginValidation' });
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const validateShowArgsObject = function (showArgs) {
|
|
27
|
+
if (showArgs === undefined) {
|
|
28
|
+
throw new Error('requires an argument');
|
|
29
|
+
}
|
|
30
|
+
if (!isPlainObj(showArgs)) {
|
|
31
|
+
throw new Error('argument must be a plain object');
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const validateShowArgsKeys = function (otherArgs) {
|
|
35
|
+
const otherKeys = Object.keys(otherArgs).map((arg) => `"${arg}"`);
|
|
36
|
+
if (otherKeys.length !== 0) {
|
|
37
|
+
throw new Error(`must only contain "title", "summary" or "text" properties, not ${otherKeys.join(', ')}`);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const validateStringArg = function ([key, value]) {
|
|
41
|
+
if (value !== undefined && typeof value !== 'string') {
|
|
42
|
+
throw new Error(`"${key}" property must be a string`);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const validateShowArgsSummary = function (summary) {
|
|
46
|
+
if (summary === undefined || summary.trim() === '') {
|
|
47
|
+
throw new Error('requires specifying a "summary" property');
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const validateShowArgsExtraData = function (extraData) {
|
|
51
|
+
if (extraData !== undefined && Array.isArray(extraData) === false) {
|
|
52
|
+
throw new TypeError('provided extra data must be an array');
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const removeEmptyStrings = function (showArgs) {
|
|
56
|
+
return mapObj(showArgs, removeEmptyString);
|
|
57
|
+
};
|
|
58
|
+
const removeEmptyString = function (key, value) {
|
|
59
|
+
if (typeof value === 'string' && value.trim() === '') {
|
|
60
|
+
return [key];
|
|
61
|
+
}
|
|
62
|
+
return [key, value];
|
|
63
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { extname } from 'path';
|
|
2
|
+
import { register } from 'ts-node';
|
|
3
|
+
import { addErrorInfo } from '../../error/info.js';
|
|
4
|
+
// Allow local plugins to be written with TypeScript.
|
|
5
|
+
// Local plugins cannot be transpiled by the build command since they can be run
|
|
6
|
+
// before it. Therefore, we type-check and transpile them automatically using
|
|
7
|
+
// `ts-node`.
|
|
8
|
+
export const registerTypeScript = function (pluginPath) {
|
|
9
|
+
if (!isTypeScriptPlugin(pluginPath)) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
return register();
|
|
13
|
+
};
|
|
14
|
+
// On TypeScript errors, adds information about the `ts-node` configuration,
|
|
15
|
+
// which includes the resolved `tsconfig.json`.
|
|
16
|
+
export const addTsErrorInfo = function (error, tsNodeService) {
|
|
17
|
+
if (tsNodeService === undefined) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const { config: { raw: { compilerOptions }, }, options: realTsNodeOptions, } = tsNodeService;
|
|
21
|
+
// filter out functions as they cannot be serialized
|
|
22
|
+
const tsNodeOptions = Object.fromEntries(Object.entries(realTsNodeOptions).filter(([, val]) => typeof val !== 'function'));
|
|
23
|
+
addErrorInfo(error, { tsConfig: { compilerOptions, tsNodeOptions } });
|
|
24
|
+
};
|
|
25
|
+
const isTypeScriptPlugin = function (pluginPath) {
|
|
26
|
+
return TYPESCRIPT_EXTENSIONS.has(extname(pluginPath));
|
|
27
|
+
};
|
|
28
|
+
const TYPESCRIPT_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts']);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { bindOpts as cacheBindOpts } from '@netlify/cache-utils';
|
|
2
|
+
import { add as functionsAdd, list as functionsList, listAll as functionsListAll } from '@netlify/functions-utils';
|
|
3
|
+
import { getGitUtils } from '@netlify/git-utils';
|
|
4
|
+
import { run, runCommand } from '@netlify/run-utils';
|
|
5
|
+
import { failBuild, failPlugin, cancelBuild, failPluginWithWarning } from '../error.js';
|
|
6
|
+
import { isSoftFailEvent } from '../events.js';
|
|
7
|
+
import { addLazyProp } from './lazy.js';
|
|
8
|
+
import { show } from './status.js';
|
|
9
|
+
// Retrieve the `utils` argument.
|
|
10
|
+
export const getUtils = function ({ event, constants: { FUNCTIONS_SRC, INTERNAL_FUNCTIONS_SRC, CACHE_DIR }, runState, }) {
|
|
11
|
+
run.command = runCommand;
|
|
12
|
+
const build = getBuildUtils(event);
|
|
13
|
+
const cache = getCacheUtils(CACHE_DIR);
|
|
14
|
+
const functions = getFunctionsUtils(FUNCTIONS_SRC, INTERNAL_FUNCTIONS_SRC);
|
|
15
|
+
const status = getStatusUtils(runState);
|
|
16
|
+
const utils = { build, cache, run, functions, status };
|
|
17
|
+
addLazyProp(utils, 'git', () => getGitUtils());
|
|
18
|
+
return utils;
|
|
19
|
+
};
|
|
20
|
+
const getBuildUtils = function (event) {
|
|
21
|
+
if (isSoftFailEvent(event)) {
|
|
22
|
+
return {
|
|
23
|
+
failPlugin,
|
|
24
|
+
failBuild: failPluginWithWarning.bind(null, 'failBuild', event),
|
|
25
|
+
cancelBuild: failPluginWithWarning.bind(null, 'cancelBuild', event),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return { failBuild, failPlugin, cancelBuild };
|
|
29
|
+
};
|
|
30
|
+
const getCacheUtils = function (CACHE_DIR) {
|
|
31
|
+
return cacheBindOpts({ cacheDir: CACHE_DIR });
|
|
32
|
+
};
|
|
33
|
+
const getFunctionsUtils = function (FUNCTIONS_SRC, INTERNAL_FUNCTIONS_SRC) {
|
|
34
|
+
const functionsDirectories = [INTERNAL_FUNCTIONS_SRC, FUNCTIONS_SRC].filter(Boolean);
|
|
35
|
+
const add = (src) => functionsAdd(src, INTERNAL_FUNCTIONS_SRC, { fail: failBuild });
|
|
36
|
+
const list = functionsList.bind(null, functionsDirectories, { fail: failBuild });
|
|
37
|
+
const listAll = functionsListAll.bind(null, functionsDirectories, { fail: failBuild });
|
|
38
|
+
return { add, list, listAll };
|
|
39
|
+
};
|
|
40
|
+
const getStatusUtils = function (runState) {
|
|
41
|
+
return { show: show.bind(undefined, runState) };
|
|
42
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { addErrorInfo } from '../../error/info.js';
|
|
2
|
+
import { serializeArray } from '../../log/serialize.js';
|
|
3
|
+
import { DEV_EVENTS, EVENTS } from '../events.js';
|
|
4
|
+
// Validate the shape of a plugin return value
|
|
5
|
+
export const validatePlugin = function (logic) {
|
|
6
|
+
try {
|
|
7
|
+
// This validation must work with the return value of `import()` which has
|
|
8
|
+
// a `Module` prototype, not `Object`
|
|
9
|
+
if (typeof logic !== 'object' || logic === null) {
|
|
10
|
+
throw new Error('Plugin must be an object or a function');
|
|
11
|
+
}
|
|
12
|
+
Object.entries(logic).forEach(([propName, value]) => {
|
|
13
|
+
validateEventHandler(value, propName);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
addErrorInfo(error, { type: 'pluginValidation' });
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
// All other properties are event handlers
|
|
22
|
+
const validateEventHandler = function (value, propName) {
|
|
23
|
+
if (!EVENTS.includes(propName) && !DEV_EVENTS.includes(propName)) {
|
|
24
|
+
throw new Error(`Invalid event '${propName}'.
|
|
25
|
+
Please use a valid event name. One of:
|
|
26
|
+
${serializeArray(EVENTS)}`);
|
|
27
|
+
}
|
|
28
|
+
if (typeof value !== 'function') {
|
|
29
|
+
throw new TypeError(`Invalid event handler '${propName}': must be a function`);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import pEvery from 'p-every';
|
|
2
|
+
import pLocate from 'p-locate';
|
|
3
|
+
import semver from 'semver';
|
|
4
|
+
import { importJsonFile } from '../utils/json.js';
|
|
5
|
+
import { resolvePath } from '../utils/resolve.js';
|
|
6
|
+
// Retrieve the `expectedVersion` of a plugin:
|
|
7
|
+
// - This is the version which should be run
|
|
8
|
+
// - This takes version pinning into account
|
|
9
|
+
// - If this does not match the currently cached version, it is installed first
|
|
10
|
+
// This is also used to retrieve the `compatibleVersion` of a plugin
|
|
11
|
+
// - This is the most recent version compatible with this site
|
|
12
|
+
// - This is the same logic except it does not use version pinning
|
|
13
|
+
// - This is only used to print a warning message when the `compatibleVersion`
|
|
14
|
+
// is older than the currently used version.
|
|
15
|
+
export const getExpectedVersion = async function ({ versions, nodeVersion, packageJson, buildDir, pinnedVersion }) {
|
|
16
|
+
const { version, conditions } = await getCompatibleEntry({
|
|
17
|
+
versions,
|
|
18
|
+
nodeVersion,
|
|
19
|
+
packageJson,
|
|
20
|
+
buildDir,
|
|
21
|
+
pinnedVersion,
|
|
22
|
+
});
|
|
23
|
+
const compatWarning = getCompatWarning(conditions);
|
|
24
|
+
return { version, compatWarning };
|
|
25
|
+
};
|
|
26
|
+
// This function finds the right `compatibility` entry to use with the plugin.
|
|
27
|
+
// - `compatibitlity` entries are meant for backward compatibility
|
|
28
|
+
// Plugins should define each major version in `compatibility`.
|
|
29
|
+
// - The entries are sorted from most to least recent version.
|
|
30
|
+
// - After their first successful run, plugins are pinned by their major
|
|
31
|
+
// version which is passed as `pinnedVersion` to the next builds.
|
|
32
|
+
// When the plugin does not have a `pinnedVersion`, we use the most recent
|
|
33
|
+
// `compatibility` entry with a successful condition.
|
|
34
|
+
// When the plugin has a `pinnedVersion`, we do not use the `compatibility`
|
|
35
|
+
// conditions. Instead, we just use the most recent entry with a `version`
|
|
36
|
+
// matching `pinnedVersion`.
|
|
37
|
+
// When no `compatibility` entry matches, we use:
|
|
38
|
+
// - If there is a `pinnedVersion`, use it unless `latestVersion` matches it
|
|
39
|
+
// - Otherwise, use `latestVersion`
|
|
40
|
+
const getCompatibleEntry = async function ({ versions, nodeVersion, packageJson, buildDir, pinnedVersion }) {
|
|
41
|
+
if (pinnedVersion !== undefined) {
|
|
42
|
+
const matchingVersion = versions.find(({ version }) => semver.satisfies(version, pinnedVersion, { includePrerelease: true }));
|
|
43
|
+
return matchingVersion || { version: pinnedVersion };
|
|
44
|
+
}
|
|
45
|
+
const versionsWithConditions = versions.filter(hasConditions);
|
|
46
|
+
const compatibleEntry = await pLocate(versionsWithConditions, ({ conditions }) => matchesCompatField({ conditions, nodeVersion, packageJson, buildDir }));
|
|
47
|
+
return compatibleEntry || { version: versions[0].version };
|
|
48
|
+
};
|
|
49
|
+
// Ignore entries without conditions. Those are used to specify breaking
|
|
50
|
+
// changes, i.e. meant to be used for version pinning instead.
|
|
51
|
+
const hasConditions = function ({ conditions }) {
|
|
52
|
+
return conditions.length !== 0;
|
|
53
|
+
};
|
|
54
|
+
const matchesCompatField = async function ({ conditions, nodeVersion, packageJson, buildDir }) {
|
|
55
|
+
return await pEvery(conditions, ({ type, condition }) => CONDITIONS[type].test(condition, { nodeVersion, packageJson, buildDir }));
|
|
56
|
+
};
|
|
57
|
+
// Retrieve warning message shown when using an older version with `compatibility`
|
|
58
|
+
const getCompatWarning = function (conditions = []) {
|
|
59
|
+
return conditions.map(getConditionWarning).join(', ');
|
|
60
|
+
};
|
|
61
|
+
const getConditionWarning = function ({ type, condition }) {
|
|
62
|
+
return CONDITIONS[type].warning(condition);
|
|
63
|
+
};
|
|
64
|
+
// Plugins can use `compatibility.{version}.nodeVersion: 'allowedNodeVersion'`
|
|
65
|
+
// to deliver different plugin versions based on the Node.js version
|
|
66
|
+
const nodeVersionTest = function (allowedNodeVersion, { nodeVersion }) {
|
|
67
|
+
return semver.satisfies(nodeVersion, allowedNodeVersion);
|
|
68
|
+
};
|
|
69
|
+
const nodeVersionWarning = function (allowedNodeVersion) {
|
|
70
|
+
return `Node.js ${allowedNodeVersion}`;
|
|
71
|
+
};
|
|
72
|
+
const siteDependenciesTest = async function (allowedSiteDependencies, { packageJson: { devDependencies, dependencies }, buildDir }) {
|
|
73
|
+
const siteDependencies = { ...devDependencies, ...dependencies };
|
|
74
|
+
return await pEvery(Object.entries(allowedSiteDependencies), ([dependencyName, allowedVersion]) => siteDependencyTest({ dependencyName, allowedVersion, siteDependencies, buildDir }));
|
|
75
|
+
};
|
|
76
|
+
const siteDependencyTest = async function ({ dependencyName, allowedVersion, siteDependencies, buildDir }) {
|
|
77
|
+
const siteDependency = siteDependencies[dependencyName];
|
|
78
|
+
if (typeof siteDependency !== 'string') {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
// if this is a valid version we can apply the rule directly
|
|
82
|
+
if (semver.clean(siteDependency) !== null) {
|
|
83
|
+
return semver.satisfies(siteDependency, allowedVersion);
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
// if this is a range we need to get the exact version
|
|
87
|
+
const packageJsonPath = await resolvePath(`${dependencyName}/package.json`, buildDir);
|
|
88
|
+
const { version } = await importJsonFile(packageJsonPath);
|
|
89
|
+
return semver.satisfies(version, allowedVersion);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const siteDependenciesWarning = function (allowedSiteDependencies) {
|
|
96
|
+
return Object.entries(allowedSiteDependencies).map(siteDependencyWarning).join(',');
|
|
97
|
+
};
|
|
98
|
+
const siteDependencyWarning = function ([dependencyName, allowedVersion]) {
|
|
99
|
+
return `${dependencyName}@${allowedVersion}`;
|
|
100
|
+
};
|
|
101
|
+
export const CONDITIONS = {
|
|
102
|
+
nodeVersion: { test: nodeVersionTest, warning: nodeVersionWarning },
|
|
103
|
+
siteDependencies: { test: siteDependenciesTest, warning: siteDependenciesWarning },
|
|
104
|
+
};
|
|
@@ -1,50 +1,46 @@
|
|
|
1
|
-
import { addErrorInfo } from '../error/info.js'
|
|
2
|
-
import { logFailPluginWarning } from '../log/messages/plugins.js'
|
|
3
|
-
|
|
1
|
+
import { addErrorInfo } from '../error/info.js';
|
|
2
|
+
import { logFailPluginWarning } from '../log/messages/plugins.js';
|
|
4
3
|
// Stop build.
|
|
5
4
|
// As opposed to throwing an error directly or to uncaught exceptions, this is
|
|
6
5
|
// displayed as a user error, not an implementation error.
|
|
7
6
|
export const failBuild = function (message, opts) {
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
7
|
+
throw normalizeError('failBuild', failBuild, message, opts);
|
|
8
|
+
};
|
|
11
9
|
// Stop plugin. Same as `failBuild` but only stops plugin not whole build
|
|
12
10
|
export const failPlugin = function (message, opts) {
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
11
|
+
throw normalizeError('failPlugin', failPlugin, message, opts);
|
|
12
|
+
};
|
|
16
13
|
// Cancel build. Same as `failBuild` except it marks the build as "canceled".
|
|
17
14
|
export const cancelBuild = function (message, opts) {
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
15
|
+
throw normalizeError('cancelBuild', cancelBuild, message, opts);
|
|
16
|
+
};
|
|
21
17
|
// `onSuccess`, `onEnd` and `onError` cannot cancel the build since they are run
|
|
22
18
|
// or might be run after deployment. When calling `failBuild()` or
|
|
23
19
|
// `cancelBuild()`, `failPlugin()` is run instead and a warning is printed.
|
|
24
20
|
export const failPluginWithWarning = function (methodName, event, message, opts) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
21
|
+
logFailPluginWarning(methodName, event);
|
|
22
|
+
failPlugin(message, opts);
|
|
23
|
+
};
|
|
29
24
|
// An `error` option can be passed to keep the original error message and
|
|
30
25
|
// stack trace. An additional `message` string is always required.
|
|
31
|
-
const normalizeError = function (type, func, message, { error } = {}) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
26
|
+
const normalizeError = function (type, func, message, { error, errorMetadata } = {}) {
|
|
27
|
+
const errorA = getError(error, message, func);
|
|
28
|
+
addErrorInfo(errorA, { type, errorMetadata });
|
|
29
|
+
return errorA;
|
|
30
|
+
};
|
|
37
31
|
const getError = function (error, message, func) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
32
|
+
if (error instanceof Error) {
|
|
33
|
+
// This might fail if `name` is a getter or is non-writable.
|
|
34
|
+
try {
|
|
35
|
+
error.message = `${message}\n${error.message}`;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// continue regardless error
|
|
39
|
+
}
|
|
40
|
+
return error;
|
|
41
|
+
}
|
|
42
|
+
const errorA = new Error(message);
|
|
43
|
+
// Do not include function itself in the stack trace
|
|
44
|
+
Error.captureStackTrace(errorA, func);
|
|
45
|
+
return errorA;
|
|
46
|
+
};
|
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
export { DEV_EVENTS, EVENTS } from '@netlify/config'
|
|
2
|
-
|
|
1
|
+
export { DEV_EVENTS, EVENTS } from '@netlify/config';
|
|
3
2
|
const isAmongEvents = function (events, event) {
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
|
|
3
|
+
return events.includes(event);
|
|
4
|
+
};
|
|
7
5
|
// Check if failure of the event should not make the build fail
|
|
8
|
-
export const isSoftFailEvent = isAmongEvents.bind(null, ['onSuccess', 'onError', 'onEnd'])
|
|
9
|
-
|
|
6
|
+
export const isSoftFailEvent = isAmongEvents.bind(null, ['onSuccess', 'onError', 'onEnd']);
|
|
10
7
|
// Check if the event is triggered even when the build fails
|
|
11
|
-
export const runsAlsoOnBuildFailure = isAmongEvents.bind(null, ['onError', 'onEnd'])
|
|
12
|
-
|
|
8
|
+
export const runsAlsoOnBuildFailure = isAmongEvents.bind(null, ['onError', 'onEnd']);
|
|
13
9
|
// Check if the event is only triggered when the build fails
|
|
14
|
-
export const runsOnlyOnBuildFailure = isAmongEvents.bind(null, ['onError'])
|
|
15
|
-
|
|
10
|
+
export const runsOnlyOnBuildFailure = isAmongEvents.bind(null, ['onError']);
|
|
16
11
|
// Check if the event is happening after deploy
|
|
17
|
-
export const runsAfterDeploy = isAmongEvents.bind(null, ['onSuccess', 'onEnd'])
|
|
12
|
+
export const runsAfterDeploy = isAmongEvents.bind(null, ['onSuccess', 'onEnd']);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import semver from 'semver';
|
|
2
|
+
import { addErrorInfo } from '../error/info.js';
|
|
3
|
+
import { importJsonFile } from '../utils/json.js';
|
|
4
|
+
import { resolvePath } from '../utils/resolve.js';
|
|
5
|
+
import { getExpectedVersion } from './compatibility.js';
|
|
6
|
+
import { getPluginsList } from './list.js';
|
|
7
|
+
// When using plugins in our official list, those are installed in .netlify/plugins/
|
|
8
|
+
// We ensure that the last version that's been approved is always the one being used.
|
|
9
|
+
// We also ensure that the plugin is our official list.
|
|
10
|
+
export const addExpectedVersions = async function ({ pluginsOptions, autoPluginsDir, packageJson, debug, logs, buildDir, testOpts, featureFlags, }) {
|
|
11
|
+
if (!pluginsOptions.some(needsExpectedVersion)) {
|
|
12
|
+
return pluginsOptions;
|
|
13
|
+
}
|
|
14
|
+
const pluginsList = await getPluginsList({ debug, logs, testOpts });
|
|
15
|
+
return await Promise.all(pluginsOptions.map((pluginOptions) => addExpectedVersion({ pluginsList, autoPluginsDir, packageJson, pluginOptions, buildDir, featureFlags })));
|
|
16
|
+
};
|
|
17
|
+
// Any `pluginOptions` with `expectedVersion` set will be automatically installed
|
|
18
|
+
const addExpectedVersion = async function ({ pluginsList, autoPluginsDir, packageJson, pluginOptions, pluginOptions: { packageName, pluginPath, loadedFrom, nodeVersion, pinnedVersion }, buildDir, featureFlags, }) {
|
|
19
|
+
if (!needsExpectedVersion(pluginOptions)) {
|
|
20
|
+
return pluginOptions;
|
|
21
|
+
}
|
|
22
|
+
if (pluginsList[packageName] === undefined) {
|
|
23
|
+
validateUnlistedPlugin(packageName, loadedFrom);
|
|
24
|
+
return pluginOptions;
|
|
25
|
+
}
|
|
26
|
+
const unfilteredVersions = pluginsList[packageName];
|
|
27
|
+
const versions = filterVersions(unfilteredVersions, featureFlags);
|
|
28
|
+
const [{ version: latestVersion, migrationGuide }] = versions;
|
|
29
|
+
const [{ version: expectedVersion }, { version: compatibleVersion, compatWarning }] = await Promise.all([
|
|
30
|
+
getExpectedVersion({ versions, nodeVersion, packageJson, buildDir, pinnedVersion }),
|
|
31
|
+
getExpectedVersion({ versions, nodeVersion, packageJson, buildDir }),
|
|
32
|
+
]);
|
|
33
|
+
const isMissing = await isMissingVersion({ autoPluginsDir, packageName, pluginPath, loadedFrom, expectedVersion });
|
|
34
|
+
return {
|
|
35
|
+
...pluginOptions,
|
|
36
|
+
latestVersion,
|
|
37
|
+
expectedVersion,
|
|
38
|
+
compatibleVersion,
|
|
39
|
+
migrationGuide,
|
|
40
|
+
compatWarning,
|
|
41
|
+
isMissing,
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
// Feature flagged versions are removed unless the feature flag is present.
|
|
45
|
+
// - This is done before conditions are applied since, unlike conditions,
|
|
46
|
+
// users cannot always choose to enable a feature flag.
|
|
47
|
+
const filterVersions = function (unfilteredVersions, featureFlags) {
|
|
48
|
+
return unfilteredVersions.filter(({ featureFlag }) => featureFlag === undefined || featureFlags[featureFlag]);
|
|
49
|
+
};
|
|
50
|
+
// Checks whether plugin should be installed due to the wrong version being used
|
|
51
|
+
// (either outdated, or mismatching compatibility requirements)
|
|
52
|
+
const isMissingVersion = async function ({ autoPluginsDir, packageName, pluginPath, loadedFrom, expectedVersion }) {
|
|
53
|
+
return (
|
|
54
|
+
// We always respect the versions specified in `package.json`, as opposed
|
|
55
|
+
// to auto-installed plugins
|
|
56
|
+
loadedFrom !== 'package.json' &&
|
|
57
|
+
// Plugin was not previously installed
|
|
58
|
+
(pluginPath === undefined ||
|
|
59
|
+
// Plugin was previously installed but a different version should be used
|
|
60
|
+
!semver.satisfies(await getAutoPluginVersion(packageName, autoPluginsDir), expectedVersion)));
|
|
61
|
+
};
|
|
62
|
+
const getAutoPluginVersion = async function (packageName, autoPluginsDir) {
|
|
63
|
+
const packageJsonPath = await resolvePath(`${packageName}/package.json`, autoPluginsDir);
|
|
64
|
+
const { version } = await importJsonFile(packageJsonPath);
|
|
65
|
+
return version;
|
|
66
|
+
};
|
|
67
|
+
const needsExpectedVersion = function ({ loadedFrom }) {
|
|
68
|
+
return loadedFrom === 'auto_install' || loadedFrom === 'package.json';
|
|
69
|
+
};
|
|
70
|
+
// Plugins that are not in our official list can only be specified in
|
|
71
|
+
// `netlify.toml` providing they are also installed in the site's package.json.
|
|
72
|
+
// Otherwise, the build should fail.
|
|
73
|
+
const validateUnlistedPlugin = function (packageName, loadedFrom) {
|
|
74
|
+
if (loadedFrom === 'package.json') {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const error = new Error(`Plugins must be installed either in the Netlify App or in "package.json".
|
|
78
|
+
Please run "npm install -D ${packageName}" or "yarn add -D ${packageName}".`);
|
|
79
|
+
addErrorInfo(error, { type: 'resolveConfig' });
|
|
80
|
+
throw error;
|
|
81
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const NETLIFY_MAINTAINED_PLUGINS = new Set([
|
|
2
|
+
'netlify_plugin_gatsby_cache',
|
|
3
|
+
'netlify_plugin_sitemap',
|
|
4
|
+
'netlify_plugin_debug_cache',
|
|
5
|
+
'netlify_plugin_is_website_vulnerable',
|
|
6
|
+
'netlify_plugin_lighthouse',
|
|
7
|
+
'netlify_plugin_nextjs',
|
|
8
|
+
'netlify_plugin_gatsby',
|
|
9
|
+
]);
|
|
10
|
+
export const isNetlifyMaintainedPlugin = (pluginPackage) => NETLIFY_MAINTAINED_PLUGINS.has(pluginPackage);
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import process from 'process';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import { pEvent } from 'p-event';
|
|
4
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
5
|
+
import { jsonToError, errorToJson } from '../error/build.js';
|
|
6
|
+
import { addErrorInfo } from '../error/info.js';
|
|
7
|
+
import { logSendingEventToChild, logSentEventToChild, logReceivedEventFromChild, logSendingEventToParent, } from '../log/messages/ipc.js';
|
|
8
|
+
// Send event from child to parent process then wait for response
|
|
9
|
+
// We need to fire them in parallel because `process.send()` can be slow
|
|
10
|
+
// to await, i.e. child might send response before parent start listening for it
|
|
11
|
+
export const callChild = async function ({ childProcess, eventName, payload, logs, verbose }) {
|
|
12
|
+
const callId = uuidv4();
|
|
13
|
+
const [response] = await Promise.all([
|
|
14
|
+
getEventFromChild(childProcess, callId),
|
|
15
|
+
sendEventToChild({ childProcess, callId, eventName, payload, logs, verbose }),
|
|
16
|
+
]);
|
|
17
|
+
logReceivedEventFromChild(logs, verbose);
|
|
18
|
+
return response;
|
|
19
|
+
};
|
|
20
|
+
// Receive event from child to parent process
|
|
21
|
+
// Wait for either:
|
|
22
|
+
// - `message` event with a specific `callId`
|
|
23
|
+
// - `message` event with an `error` `callId` indicating an exception in the
|
|
24
|
+
// child process
|
|
25
|
+
// - child process `exit`
|
|
26
|
+
// In the later two cases, we propagate the error.
|
|
27
|
+
// We need to make `p-event` listeners are properly cleaned up too.
|
|
28
|
+
export const getEventFromChild = async function (childProcess, callId) {
|
|
29
|
+
if (childProcessHasExited(childProcess)) {
|
|
30
|
+
throw getChildExitError('Could not receive event from child process because it already exited.');
|
|
31
|
+
}
|
|
32
|
+
const messagePromise = pEvent(childProcess, 'message', { filter: ([actualCallId]) => actualCallId === callId });
|
|
33
|
+
const errorPromise = pEvent(childProcess, 'message', { filter: ([actualCallId]) => actualCallId === 'error' });
|
|
34
|
+
const exitPromise = pEvent(childProcess, 'exit', { multiArgs: true });
|
|
35
|
+
try {
|
|
36
|
+
return await Promise.race([getMessage(messagePromise), getError(errorPromise), getExit(exitPromise)]);
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
messagePromise.cancel();
|
|
40
|
+
errorPromise.cancel();
|
|
41
|
+
exitPromise.cancel();
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const childProcessHasExited = function (childProcess) {
|
|
45
|
+
return !childProcess.connected || childProcess.signalCode !== null || childProcess.exitCode !== null;
|
|
46
|
+
};
|
|
47
|
+
const getMessage = async function (messagePromise) {
|
|
48
|
+
const [, response] = await messagePromise;
|
|
49
|
+
return response;
|
|
50
|
+
};
|
|
51
|
+
const getError = async function (errorPromise) {
|
|
52
|
+
const [, error] = await errorPromise;
|
|
53
|
+
throw jsonToError(error);
|
|
54
|
+
};
|
|
55
|
+
const getExit = async function (exitPromise) {
|
|
56
|
+
const [exitCode, signal] = await exitPromise;
|
|
57
|
+
throw getChildExitError(`Plugin exited with exit code ${exitCode} and signal ${signal}.`);
|
|
58
|
+
};
|
|
59
|
+
// Plugins should not terminate processes explicitly:
|
|
60
|
+
// - It prevents specifying error messages to the end users
|
|
61
|
+
// - It makes it impossible to distinguish between bugs (such as infinite loops) and user errors
|
|
62
|
+
// - It complicates child process orchestration. For example if an async operation
|
|
63
|
+
// of a previous event handler is still running, it would be aborted if another
|
|
64
|
+
// is terminating the process.
|
|
65
|
+
const getChildExitError = function (message) {
|
|
66
|
+
const error = new Error(`${message}\n${EXIT_WARNING}`);
|
|
67
|
+
addErrorInfo(error, { type: 'ipc' });
|
|
68
|
+
return error;
|
|
69
|
+
};
|
|
70
|
+
const EXIT_WARNING = `The plugin might have exited due to a bug terminating the process, such as an infinite loop.
|
|
71
|
+
The plugin might also have explicitly terminated the process, for example with process.exit().
|
|
72
|
+
Plugin methods should instead:
|
|
73
|
+
- on success: return
|
|
74
|
+
- on failure: call utils.build.failPlugin() or utils.build.failBuild()`;
|
|
75
|
+
// Send event from parent to child process
|
|
76
|
+
const sendEventToChild = async function ({ childProcess, callId, eventName, payload, logs, verbose }) {
|
|
77
|
+
logSendingEventToChild(logs, verbose);
|
|
78
|
+
const payloadA = serializePayload(payload);
|
|
79
|
+
await promisify(childProcess.send.bind(childProcess))([callId, eventName, payloadA]);
|
|
80
|
+
logSentEventToChild(logs, verbose);
|
|
81
|
+
};
|
|
82
|
+
// Respond to events from parent to child process.
|
|
83
|
+
// This runs forever until `childProcess.kill()` is called.
|
|
84
|
+
// We need to use `new Promise()` and callbacks because this runs forever.
|
|
85
|
+
export const getEventsFromParent = function (callback) {
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
process.on('message', async (message) => {
|
|
88
|
+
try {
|
|
89
|
+
const [callId, eventName, payload] = message;
|
|
90
|
+
const payloadA = parsePayload(payload);
|
|
91
|
+
return await callback(callId, eventName, payloadA);
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
reject(error);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
// Send event from child to parent process
|
|
100
|
+
export const sendEventToParent = async function (callId, payload, verbose, error) {
|
|
101
|
+
logSendingEventToParent(verbose, error);
|
|
102
|
+
await promisify(process.send.bind(process))([callId, payload]);
|
|
103
|
+
};
|
|
104
|
+
// Error static properties are not serializable through `child_process`
|
|
105
|
+
// (which uses `v8.serialize()` under the hood) so we need to convert from/to
|
|
106
|
+
// plain objects.
|
|
107
|
+
const serializePayload = function ({ error = {}, error: { name } = {}, ...payload }) {
|
|
108
|
+
if (name === undefined) {
|
|
109
|
+
return payload;
|
|
110
|
+
}
|
|
111
|
+
const errorA = errorToJson(error);
|
|
112
|
+
return { ...payload, error: errorA };
|
|
113
|
+
};
|
|
114
|
+
const parsePayload = function ({ error = {}, error: { name } = {}, ...payload }) {
|
|
115
|
+
if (name === undefined) {
|
|
116
|
+
return payload;
|
|
117
|
+
}
|
|
118
|
+
const errorA = jsonToError(error);
|
|
119
|
+
return { ...payload, error: errorA };
|
|
120
|
+
};
|