netlify-cli
Version:
Netlify command line tool
194 lines • 8.65 kB
JavaScript
import process from 'process';
import getPort from 'get-port';
import isEmpty from 'lodash/isEmpty.js';
import { supportsBackgroundFunctions } from '../lib/account.js';
import { NETLIFYDEVLOG, chalk, logAndThrowError, log, warn } from './command-helpers.js';
import { loadDotEnvFiles } from './dot-env.js';
// Possible sources of environment variables. For the purpose of printing log messages only. Order does not matter.
const ENV_VAR_SOURCES = {
account: {
name: 'shared',
printFn: chalk.magenta,
},
addons: {
name: 'addon',
printFn: chalk.yellow,
},
configFile: {
name: 'netlify.toml file',
printFn: chalk.green,
},
general: {
name: 'general context',
printFn: chalk.italic,
},
process: {
name: 'process',
printFn: chalk.red,
},
ui: {
name: 'site settings',
printFn: chalk.blue,
},
};
const ERROR_CALL_TO_ACTION = "Double-check your login status with 'netlify status' or contact support with details of your error.";
// @ts-expect-error TS(7031) FIXME: Binding element 'site' implicitly has an 'any' typ... Remove this comment to see the full error message
const validateSiteInfo = ({ site, siteInfo }) => {
if (isEmpty(siteInfo)) {
return logAndThrowError(`Failed retrieving site information for site ${chalk.yellow(site.id)}. ${ERROR_CALL_TO_ACTION}`);
}
};
const getAccounts = async ({ api }) => {
try {
const accounts = await api.listAccountsForUser();
return accounts;
}
catch (error_) {
return logAndThrowError(`Failed retrieving user account: ${error_.message}. ${ERROR_CALL_TO_ACTION}`);
}
};
// @ts-expect-error TS(7031) FIXME: Binding element 'api' implicitly has an 'any' type... Remove this comment to see the full error message
const getAddons = async ({ api, site }) => {
try {
const addons = await api.listServiceInstancesForSite({ siteId: site.id });
return addons;
}
catch (error_) {
return logAndThrowError(`Failed retrieving addons for site ${chalk.yellow(site.id)}: ${error_.message}. ${ERROR_CALL_TO_ACTION}`);
}
};
// @ts-expect-error TS(7031) FIXME: Binding element 'addons' implicitly has an 'any' t... Remove this comment to see the full error message
const getAddonsInformation = ({ addons, siteInfo }) => {
const urls = Object.fromEntries(
// @ts-expect-error TS(7006) FIXME: Parameter 'addon' implicitly has an 'any' type.
addons.map((addon) => [addon.service_slug, `${siteInfo.ssl_url}${addon.service_path}`]));
// @ts-expect-error TS(7006) FIXME: Parameter 'addon' implicitly has an 'any' type.
const env = Object.assign({}, ...addons.map((addon) => addon.env));
return { urls, env };
};
const getSiteAccount = ({ accounts, siteInfo }) => {
const siteAccount = accounts.find((account) => account.slug === siteInfo.account_slug);
if (!siteAccount) {
warn(`Could not find account for site '${siteInfo.name}' with account slug '${siteInfo.account_slug}'`);
return undefined;
}
return siteAccount;
};
// default 10 seconds for synchronous functions
const SYNCHRONOUS_FUNCTION_TIMEOUT = 30;
// default 15 minutes for background functions
const BACKGROUND_FUNCTION_TIMEOUT = 900;
/**
*
* @param {object} config
* @param {boolean} config.offline
* @param {*} config.api
* @param {*} config.site
* @param {*} config.siteInfo
* @returns
*/
// @ts-expect-error TS(7031) FIXME: Binding element 'api' implicitly has an 'any' type... Remove this comment to see the full error message
export const getSiteInformation = async ({ api, offline, site, siteInfo }) => {
if (site.id && !offline) {
validateSiteInfo({ site, siteInfo });
const [accounts, addons] = await Promise.all([getAccounts({ api }), getAddons({ api, site })]);
const { urls: addonsUrls } = getAddonsInformation({ siteInfo, addons });
const account = getSiteAccount({ siteInfo, accounts });
return {
addonsUrls,
siteUrl: siteInfo.ssl_url,
accountId: account?.id,
capabilities: {
backgroundFunctions: supportsBackgroundFunctions(account),
},
timeouts: {
syncFunctions: siteInfo.functions_timeout ?? siteInfo.functions_config?.timeout ?? SYNCHRONOUS_FUNCTION_TIMEOUT,
backgroundFunctions: BACKGROUND_FUNCTION_TIMEOUT,
},
};
}
// best defaults we can have without retrieving site information
return {
addonsUrls: {},
siteUrl: '',
capabilities: {},
timeouts: {
syncFunctions: SYNCHRONOUS_FUNCTION_TIMEOUT,
backgroundFunctions: BACKGROUND_FUNCTION_TIMEOUT,
},
};
};
// @ts-expect-error TS(7006) FIXME: Parameter 'source' implicitly has an 'any' type.
const getEnvSourceName = (source) => {
// @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
const { name = source, printFn = chalk.green } = ENV_VAR_SOURCES[source] || {};
return printFn(name);
};
/**
* @param {{devConfig: any, env: Record<string, { sources: string[], value: string}>, site: any}} param0
* @returns {Promise<Record<string, { sources: string[], value: string}>>}
*/
// @ts-expect-error TS(7031) FIXME: Binding element 'devConfig' implicitly has an 'any... Remove this comment to see the full error message
export const getDotEnvVariables = async ({ devConfig, env, site }) => {
const dotEnvFiles = await loadDotEnvFiles({ envFiles: devConfig.envFiles, projectDir: site.root });
// @ts-expect-error TS(2339) FIXME: Property 'env' does not exist on type '{ warning: ... Remove this comment to see the full error message
dotEnvFiles.forEach(({ env: fileEnv, file }) => {
const newSourceName = `${file} file`;
Object.keys(fileEnv).forEach((key) => {
const sources = key in env ? [newSourceName, ...env[key].sources] : [newSourceName];
if (sources.includes('internal')) {
return;
}
env[key] = {
sources,
value: fileEnv[key],
};
});
});
return env;
};
/**
* Takes a set of environment variables in the format provided by @netlify/config and injects them into `process.env`
* @param {Record<string, { sources: string[], value: string}>} env
* @return {void}
*/
// @ts-expect-error TS(7006) FIXME: Parameter 'env' implicitly has an 'any' type.
export const injectEnvVariables = (env) => {
for (const [key, variable] of Object.entries(env)) {
const existsInProcess = process.env[key] !== undefined;
// @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
const [usedSource, ...overriddenSources] = existsInProcess ? ['process', ...variable.sources] : variable.sources;
const usedSourceName = getEnvSourceName(usedSource);
// @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
const isInternal = variable.sources.includes('internal');
// @ts-expect-error TS(7006) FIXME: Parameter 'source' implicitly has an 'any' type.
overriddenSources.forEach((source) => {
const sourceName = getEnvSourceName(source);
log(chalk.dim(`${NETLIFYDEVLOG} Ignored ${chalk.bold(sourceName)} env var: ${chalk.yellow(key)} (defined in ${usedSourceName})`));
});
if (!existsInProcess || isInternal) {
// Omitting `general` and `internal` env vars to reduce noise in the logs.
if (usedSource !== 'general' && !isInternal) {
log(`${NETLIFYDEVLOG} Injected ${usedSourceName} env var: ${chalk.yellow(key)}`);
}
// @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
process.env[key] = variable.value;
}
}
};
export const acquirePort = async ({ configuredPort, defaultPort, errorMessage, }) => {
const acquiredPort = await getPort({ port: configuredPort || defaultPort });
if (configuredPort && acquiredPort !== configuredPort) {
throw new Error(`${errorMessage}: '${configuredPort}'`);
}
return acquiredPort;
};
// @ts-expect-error TS(7006) FIXME: Parameter 'fn' implicitly has an 'any' type.
export const processOnExit = (fn) => {
const signals = ['SIGINT', 'SIGTERM', 'SIGQUIT', 'SIGHUP', 'exit'];
signals.forEach((signal) => {
process.on(signal, fn);
});
};
export const UNLINKED_SITE_MOCK_ID = 'unlinked';
//# sourceMappingURL=dev.js.map