@netlify/config
Version:
Netlify config module
142 lines (141 loc) • 5.96 kB
JavaScript
import fetch from 'node-fetch';
import { getEnvelope } from '../env/envelope.js';
import { throwUserError } from '../error.js';
import { EXTENSION_API_BASE_URL, EXTENSION_API_STAGING_BASE_URL, NETLIFY_API_BASE_URL, NETLIFY_API_STAGING_BASE_URL, } from '../integrations.js';
import { ERROR_CALL_TO_ACTION } from '../log/messages.js';
/**
* Retrieve Netlify Site information, if available.
* Used to retrieve local build environment variables and UI build settings.
* This is not used in production builds since the buildbot passes this
* information instead.
* Requires knowing the `siteId` and having the access `token`.
* Silently ignore API errors. For example the network connection might be down,
* but local builds should still work regardless.
*/
export const getSiteInfo = async function ({ api, siteId, accountId, mode, context, offline = false, testOpts = {}, siteFeatureFlagPrefix, token, featureFlags = {}, extensionApiBaseUrl, }) {
const { env: testEnv = false } = testOpts;
if (api === undefined || mode === 'buildbot' || testEnv) {
const siteInfo = {};
if (siteId !== undefined)
siteInfo.id = siteId;
if (accountId !== undefined)
siteInfo.account_id = accountId;
const integrations = mode === 'buildbot' && !offline
? await getIntegrations({
siteId,
testOpts,
offline,
accountId,
token,
featureFlags,
extensionApiBaseUrl,
mode,
})
: [];
return { siteInfo, accounts: [], addons: [], integrations };
}
const promises = [
getSite(api, siteId, siteFeatureFlagPrefix),
getAccounts(api),
getAddons(api, siteId),
getIntegrations({ siteId, testOpts, offline, accountId, token, featureFlags, extensionApiBaseUrl, mode }),
];
const [siteInfo, accounts, addons, integrations] = await Promise.all(promises);
if (siteInfo.use_envelope) {
const envelope = await getEnvelope({ api, accountId: siteInfo.account_slug, siteId, context });
siteInfo.build_settings.env = envelope;
}
return { siteInfo, accounts, addons, integrations };
};
const getSite = async function (api, siteId, siteFeatureFlagPrefix) {
if (siteId === undefined) {
return {};
}
try {
const site = await api.getSite({ siteId, feature_flags: siteFeatureFlagPrefix });
return { ...site, id: siteId };
}
catch (error) {
throwUserError(`Failed retrieving site data for site ${siteId}: ${error.message}. ${ERROR_CALL_TO_ACTION}`);
}
};
const getAccounts = async function (api) {
try {
const accounts = await api.listAccountsForUser();
return Array.isArray(accounts) ? accounts : [];
}
catch (error) {
throwUserError(`Failed retrieving user account: ${error.message}. ${ERROR_CALL_TO_ACTION}`);
}
};
const getAddons = async function (api, siteId) {
if (siteId === undefined) {
return [];
}
try {
const addons = await api.listServiceInstancesForSite({ siteId });
return Array.isArray(addons) ? addons : [];
}
catch (error) {
throwUserError(`Failed retrieving addons for site ${siteId}: ${error.message}. ${ERROR_CALL_TO_ACTION}`);
}
};
const getIntegrations = async function ({ siteId, accountId, testOpts, offline, token, featureFlags, extensionApiBaseUrl, mode, }) {
if (!siteId || offline) {
return [];
}
const sendBuildBotTokenToJigsaw = featureFlags?.send_build_bot_token_to_jigsaw;
const { host: originalHost, setBaseUrl } = testOpts;
// TODO(kh): I am adding this purely for local staging development.
// We should remove this once we have fixed https://github.com/netlify/cli/blob/b5a5c7525edd28925c5c2e3e5f0f00c4261eaba5/src/lib/build.ts#L125
let host = originalHost;
// If there is a host, we use it to fetch the integrations
// we check if the host is staging or production and set the host accordingly,
// sadly necessary because of https://github.com/netlify/cli/blob/b5a5c7525edd28925c5c2e3e5f0f00c4261eaba5/src/lib/build.ts#L125
if (originalHost) {
if (originalHost?.includes(NETLIFY_API_STAGING_BASE_URL)) {
host = EXTENSION_API_STAGING_BASE_URL;
}
else if (originalHost?.includes(NETLIFY_API_BASE_URL)) {
host = EXTENSION_API_BASE_URL;
}
else {
host = `http://${originalHost}`;
}
}
const baseUrl = new URL(host ?? extensionApiBaseUrl);
// We only use this for testing
if (host && setBaseUrl) {
setBaseUrl(extensionApiBaseUrl);
}
// if accountId isn't present, use safe v1 endpoint
const url = accountId
? `${baseUrl}team/${accountId}/integrations/installations/meta/${siteId}`
: `${baseUrl}site/${siteId}/integrations/safe`;
try {
const requestOptions = {};
// This is used to identify where the request is coming from
requestOptions.headers = {
'netlify-config-mode': mode,
};
if (sendBuildBotTokenToJigsaw && token) {
requestOptions.headers = {
...requestOptions.headers,
'netlify-sdk-build-bot-token': token,
};
}
const response = await fetch(url, requestOptions);
if (!response.ok) {
throw new Error(`Unexpected status code ${response.status} from fetching extensions`);
}
const bodyText = await response.text();
if (bodyText === '') {
return [];
}
const integrations = await JSON.parse(bodyText);
return Array.isArray(integrations) ? integrations : [];
}
catch (error) {
return throwUserError(`Failed retrieving extensions for site ${siteId}: ${error.message}. ${ERROR_CALL_TO_ACTION}`);
}
};