From 6c6de6c64cbc7f70f2fa642aab2d84da0efbf5c3 Mon Sep 17 00:00:00 2001 From: Philippe Serhal Date: Wed, 7 Oct 2026 16:03:40 -0400 Subject: [PATCH] refactor: remove more dead "addons" code This is very old, unused code for something that no longer exists. --- CLAUDE.md | 3 +- eslint-suppressions.json | 46 +++------ src/commands/dev/dev.ts | 3 +- src/commands/functions/functions-create.ts | 105 +-------------------- src/commands/serve/serve.ts | 3 +- src/lib/edge-functions/registry.ts | 1 - src/utils/addons/prepare.ts | 26 ----- src/utils/dev.ts | 35 +------ src/utils/env/index.ts | 2 - src/utils/parse-raw-flags.ts | 2 +- src/utils/proxy-server.ts | 3 - src/utils/proxy.ts | 36 ------- src/utils/types.ts | 2 +- 13 files changed, 22 insertions(+), 245 deletions(-) delete mode 100644 src/utils/addons/prepare.ts diff --git a/CLAUDE.md b/CLAUDE.md index 8875a43ee3f..04ac6e0ac99 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -129,8 +129,7 @@ Environment variables are loaded from multiple sources with specific precedence: 1. Process environment 2. `.env` files (multiple variants supported) 3. Netlify site settings (shared, project-specific) -4. Addon-provided variables -5. Build-time configuration +4. Build-time configuration #### Function URL Routing diff --git a/eslint-suppressions.json b/eslint-suppressions.json index e9630309b09..753b3245b9c 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -266,12 +266,6 @@ } }, "src/commands/functions/functions-create.ts": { - "@typescript-eslint/await-thenable": { - "count": 1 - }, - "@typescript-eslint/no-confusing-void-expression": { - "count": 1 - }, "@typescript-eslint/no-floating-promises": { "count": 1 }, @@ -285,13 +279,13 @@ "count": 36 }, "@typescript-eslint/no-unsafe-assignment": { - "count": 64 + "count": 38 }, "@typescript-eslint/no-unsafe-call": { - "count": 11 + "count": 8 }, "@typescript-eslint/no-unsafe-member-access": { - "count": 59 + "count": 47 }, "@typescript-eslint/no-unsafe-return": { "count": 11 @@ -303,7 +297,7 @@ "count": 6 }, "@typescript-eslint/restrict-template-expressions": { - "count": 29 + "count": 24 }, "n/no-process-exit": { "count": 2 @@ -809,20 +803,6 @@ "count": 2 } }, - "src/utils/addons/prepare.ts": { - "@typescript-eslint/no-unsafe-assignment": { - "count": 4 - }, - "@typescript-eslint/no-unsafe-call": { - "count": 3 - }, - "@typescript-eslint/no-unsafe-member-access": { - "count": 4 - }, - "@typescript-eslint/no-unsafe-return": { - "count": 3 - } - }, "src/utils/agent-detection.ts": { "@typescript-eslint/prefer-nullish-coalescing": { "count": 1 @@ -1004,25 +984,25 @@ }, "src/utils/dev.ts": { "@typescript-eslint/no-unsafe-argument": { - "count": 5 + "count": 3 }, "@typescript-eslint/no-unsafe-assignment": { - "count": 15 + "count": 9 }, "@typescript-eslint/no-unsafe-call": { - "count": 4 + "count": 1 }, "@typescript-eslint/no-unsafe-member-access": { - "count": 16 + "count": 7 }, "@typescript-eslint/no-unsafe-return": { - "count": 5 + "count": 2 }, "@typescript-eslint/prefer-nullish-coalescing": { "count": 2 }, "@typescript-eslint/restrict-template-expressions": { - "count": 6 + "count": 4 } }, "src/utils/dot-env.ts": { @@ -1193,16 +1173,16 @@ "count": 7 }, "@typescript-eslint/no-unsafe-argument": { - "count": 38 + "count": 32 }, "@typescript-eslint/no-unsafe-assignment": { - "count": 69 + "count": 61 }, "@typescript-eslint/no-unsafe-call": { "count": 28 }, "@typescript-eslint/no-unsafe-member-access": { - "count": 98 + "count": 96 }, "@typescript-eslint/no-unsafe-return": { "count": 13 diff --git a/src/commands/dev/dev.ts b/src/commands/dev/dev.ts index 0710f238120..cd76007155d 100644 --- a/src/commands/dev/dev.ts +++ b/src/commands/dev/dev.ts @@ -148,7 +148,7 @@ export const dev = async (options: OptionValues, command: BaseCommand) => { env = await getDotEnvVariables({ devConfig, env, site }) - const { accountId, addonsUrls, capabilities, siteUrl, timeouts } = await getSiteInformation({ + const { accountId, capabilities, siteUrl, timeouts } = await getSiteInformation({ // inherited from base command --offline offline: options.offline, @@ -297,7 +297,6 @@ export const dev = async (options: OptionValues, command: BaseCommand) => { const inspectSettings = generateInspectSettings(options.edgeInspect, options.edgeInspectBrk) await startProxyServer({ - addonsUrls, aiGatewayContext, api, blobsContext, diff --git a/src/commands/functions/functions-create.ts b/src/commands/functions/functions-create.ts index 2758c497402..7c80691659a 100644 --- a/src/commands/functions/functions-create.ts +++ b/src/commands/functions/functions-create.ts @@ -6,7 +6,7 @@ import path, { dirname, join, relative } from 'path' import process from 'process' import { fileURLToPath, pathToFileURL } from 'url' -import { confirm, input, search, select, Separator } from '@inquirer/prompts' +import { input, search, select, Separator } from '@inquirer/prompts' import { OptionValues } from 'commander' import { findUp } from 'find-up' import fuzzy from 'fuzzy' @@ -14,9 +14,7 @@ import fetch from 'node-fetch' import { createSpinner } from 'nanospinner' import { fileExistsAsync } from '../../lib/fs.js' -import { getAddons, getCurrentAddon, getSiteData } from '../../utils/addons/prepare.js' import { - APIError, NETLIFYDEVERR, NETLIFYDEVLOG, NETLIFYDEVWARN, @@ -406,10 +404,9 @@ const downloadFromURL = async function (command, options, argumentName, function const fnTemplateFile = path.join(fnFolder, '.netlify-function-template.mjs') if (await fileExistsAsync(fnTemplateFile)) { const { - default: { addons = [], onComplete }, + default: { onComplete }, } = await import(pathToFileURL(fnTemplateFile).href) - await installAddons(command, addons, path.resolve(fnFolder)) await handleOnComplete({ command, onComplete }) // delete await unlink(fnTemplateFile) @@ -504,7 +501,7 @@ const scaffoldFromTemplate = async function (command, options, argumentName, fun } else if (chosenTemplate === 'report') { log(`${NETLIFYDEVLOG} Open in browser: https://github.com/netlify/cli/issues/new`) } else { - const { addons = [], lang, name: templateName, onComplete } = chosenTemplate + const { lang, name: templateName, onComplete } = chosenTemplate const pathToTemplate = path.join(templatesDir, lang, templateName) if (!fs.existsSync(pathToTemplate)) { throw new Error( @@ -551,7 +548,6 @@ const scaffoldFromTemplate = async function (command, options, argumentName, fun await registerEFInToml(name, command.netlify) } - await installAddons(command, addons, path.resolve(functionPath)) await handleOnComplete({ command, onComplete }) log() @@ -561,26 +557,6 @@ const scaffoldFromTemplate = async function (command, options, argumentName, fun const TEMPLATE_PERMISSIONS = 0o777 -// @ts-expect-error TS(7031) FIXME: Binding element 'addonName' implicitly has an 'any... Remove this comment to see the full error message -const createFunctionAddon = async function ({ addonName, addons, api, siteData, siteId }) { - try { - const addon = getCurrentAddon({ addons, addonName }) - if (addon?.id) { - log(`The "${addonName} add-on" already exists for ${siteData.name}`) - return false - } - await api.createServiceInstance({ - siteId, - addon: addonName, - body: { config: {} }, - }) - log(`Add-on "${addonName}" created for ${siteData.name}`) - return true - } catch (error_) { - return logAndThrowError((error_ as APIError).message) - } -} - /** * * @param {object} config @@ -601,81 +577,6 @@ const handleOnComplete = async ({ command, onComplete }) => { await onComplete.call(command) } } -/** - * - * @param {object} config - * @param {*} config.addonCreated - * @param {*} config.addonDidInstall - * @param {import('../base-command.js').default} config.command - * @param {string} config.fnPath - */ -// @ts-expect-error TS(7031) FIXME: Binding element 'addonCreated' implicitly has an '... Remove this comment to see the full error message -const handleAddonDidInstall = async ({ addonCreated, addonDidInstall, command, fnPath }) => { - const { config } = command.netlify - - if (!addonCreated || !addonDidInstall) { - return - } - - const confirmPostInstall = await confirm({ - message: `This template has an optional setup script that runs after addon install. This can be helpful for first time users to try out templates. Run the script?`, - default: false, - }) - - if (!confirmPostInstall) { - return - } - - await injectEnvVariables({ - devConfig: { ...config.dev }, - env: command.netlify.cachedConfig.env, - site: command.netlify.site, - }) - addonDidInstall(fnPath) -} - -/** - * - * @param {import('../base-command.js').default} command - * @param {*} functionAddons - * @param {*} fnPath - * @returns - */ -// @ts-expect-error TS(7006) FIXME: Parameter 'command' implicitly has an 'any' type. -const installAddons = async function (command, functionAddons, fnPath) { - if (functionAddons.length === 0) { - return - } - - const { api, site } = command.netlify - const siteId = site.id - if (!siteId) { - log('No project id found, please run inside a project directory or `netlify link`') - return false - } - log(`${NETLIFYDEVLOG} checking Netlify APIs...`) - - const [siteData, siteAddons] = await Promise.all([getSiteData({ api, siteId }), getAddons({ api, siteId })]) - - // @ts-expect-error TS(7031) FIXME: Binding element 'addonDidInstall' implicitly has a... Remove this comment to see the full error message - const arr = functionAddons.map(async ({ addonDidInstall, addonName }) => { - log(`${NETLIFYDEVLOG} installing addon: ${chalk.yellow.inverse(addonName)}`) - try { - const addonCreated = await createFunctionAddon({ - api, - addons: siteAddons, - siteId, - addonName, - siteData, - }) - - await handleAddonDidInstall({ addonCreated, addonDidInstall, command, fnPath }) - } catch (error_) { - return logAndThrowError(`${NETLIFYDEVERR} Error installing addon: ${error_}`) - } - }) - return Promise.all(arr) -} /** * diff --git a/src/commands/serve/serve.ts b/src/commands/serve/serve.ts index 87d03f78464..bf6cc2a0688 100644 --- a/src/commands/serve/serve.ts +++ b/src/commands/serve/serve.ts @@ -58,7 +58,7 @@ export const serve = async (options: OptionValues, command: BaseCommand) => { env = await getDotEnvVariables({ devConfig, env, site }) - const { accountId, addonsUrls, capabilities, siteUrl, timeouts } = await getSiteInformation({ + const { accountId, capabilities, siteUrl, timeouts } = await getSiteInformation({ // inherited from base command --offline offline: options.offline, api, @@ -190,7 +190,6 @@ export const serve = async (options: OptionValues, command: BaseCommand) => { const inspectSettings = generateInspectSettings(options.edgeInspect, options.edgeInspectBrk) const url = await startProxyServer({ - addonsUrls, blobsContext: runtimeBlobsContext, command, config: mergedConfig, diff --git a/src/lib/edge-functions/registry.ts b/src/lib/edge-functions/registry.ts index 1c06e31cd0f..50aa7987335 100644 --- a/src/lib/edge-functions/registry.ts +++ b/src/lib/edge-functions/registry.ts @@ -389,7 +389,6 @@ export class EdgeFunctionsRegistryImpl implements EdgeFunctionsRegistry { if ( variable.sources.includes('ui') || variable.sources.includes('account') || - variable.sources.includes('addons') || variable.sources.includes('internal') || variable.sources.some((source) => source.startsWith('.env')) ) { diff --git a/src/utils/addons/prepare.ts b/src/utils/addons/prepare.ts deleted file mode 100644 index e64111e818f..00000000000 --- a/src/utils/addons/prepare.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { APIError, logAndThrowError } from '../command-helpers.js' - -// @ts-expect-error TS(7031) FIXME: Binding element 'addonName' implicitly has an 'any... Remove this comment to see the full error message -export const getCurrentAddon = ({ addonName, addons }) => addons.find((addon) => addon.service_slug === addonName) - -// @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 getSiteData = async ({ api, siteId }) => { - let siteData - try { - siteData = await api.getSite({ siteId }) - } catch (error_) { - return logAndThrowError(`Failed getting list of project data: ${(error_ as APIError).message}`) - } - return siteData -} - -// @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 getAddons = async ({ api, siteId }) => { - let addons - try { - addons = await api.listServiceInstancesForSite({ siteId }) - } catch (error_) { - return logAndThrowError(`Failed getting list of addons: ${(error_ as APIError).message}`) - } - return addons -} diff --git a/src/utils/dev.ts b/src/utils/dev.ts index f41b1276b21..7cd816f4d09 100644 --- a/src/utils/dev.ts +++ b/src/utils/dev.ts @@ -16,10 +16,6 @@ const ENV_VAR_SOURCES = { name: 'shared', printFn: chalk.magenta, }, - addons: { - name: 'addon', - printFn: chalk.yellow, - }, configFile: { name: 'netlify.toml file', printFn: chalk.green, @@ -78,31 +74,6 @@ const getAccounts = async ({ api }: { api: NetlifyAPI }) => { } } -// @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_ as APIError).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 }: { accounts: Account[]; siteInfo: SiteInfo }): Account | undefined => { const siteAccount = accounts.find((account) => account.slug === siteInfo.account_slug) if (!siteAccount) { @@ -126,7 +97,6 @@ interface GetSiteInformationOptions { } export interface SiteInformationResult { - addonsUrls: Record siteUrl: string accountId?: string capabilities: { @@ -147,13 +117,11 @@ export const getSiteInformation = async ({ }: GetSiteInformationOptions): Promise => { if (site.id && !offline) { validateSiteInfo({ site, siteInfo }) - const [accounts, addons] = await Promise.all([getAccounts({ api }), getAddons({ api, site })]) + const accounts = await getAccounts({ api }) - const { urls: addonsUrls } = getAddonsInformation({ siteInfo, addons }) const account = getSiteAccount({ siteInfo, accounts }) return { - addonsUrls, siteUrl: siteInfo.ssl_url, accountId: account?.id, capabilities: { @@ -169,7 +137,6 @@ export const getSiteInformation = async ({ // best defaults we can have without retrieving site information return { - addonsUrls: {}, siteUrl: '', capabilities: { aiGatewayDisabled: false, diff --git a/src/utils/env/index.ts b/src/utils/env/index.ts index 8f5dfa22c95..4c82eddba0f 100644 --- a/src/utils/env/index.ts +++ b/src/utils/env/index.ts @@ -289,7 +289,6 @@ export const getEnvelopeEnv = async ({ const generalEnv = filterEnvBySource(env, 'general') const internalEnv = filterEnvBySource(env, 'internal') - const addonsEnv = filterEnvBySource(env, 'addons') const configFileEnv = filterEnvBySource(env, 'configFile') // filter out configFile env vars if a non-configFile scope is passed @@ -299,7 +298,6 @@ export const getEnvelopeEnv = async ({ return { ...generalEnv, ...accountEnv, - ...(includeConfigEnvVars ? addonsEnv : {}), ...siteEnv, ...(includeConfigEnvVars ? configFileEnv : {}), ...internalEnv, diff --git a/src/utils/parse-raw-flags.ts b/src/utils/parse-raw-flags.ts index 838c500be7b..48ea5c88d7a 100644 --- a/src/utils/parse-raw-flags.ts +++ b/src/utils/parse-raw-flags.ts @@ -4,7 +4,7 @@ // // Usage: -// const { flags, raw } = this.parse(addonsCreateCommand) +// const { flags, raw } = this.parse(someCommand) // // flags = {} // const rawFlags = parseRawFlags(raw) // // rawFlags = {stuff: yay!} diff --git a/src/utils/proxy-server.ts b/src/utils/proxy-server.ts index 6dee7c11fcb..2ecf0f2db6c 100644 --- a/src/utils/proxy-server.ts +++ b/src/utils/proxy-server.ts @@ -43,7 +43,6 @@ export const generateInspectSettings = ( export const startProxyServer = async ({ accountId, - addonsUrls, aiGatewayContext, api, blobsContext, @@ -69,7 +68,6 @@ export const startProxyServer = async ({ deployEnvironment, }: { accountId: string | undefined - addonsUrls: $TSFixMe aiGatewayContext?: AIGatewayContext | null api?: NetlifyOptions['api'] blobsContext?: BlobsContextWithEdgeAccess @@ -96,7 +94,6 @@ export const startProxyServer = async ({ deployEnvironment: { key: string; value: string; isSecret: boolean; scopes: string[] }[] }) => { const url = await startProxy({ - addonsUrls, aiGatewayContext, blobsContext, command, diff --git a/src/utils/proxy.ts b/src/utils/proxy.ts index 01d4ea46088..2db347e4b9c 100644 --- a/src/utils/proxy.ts +++ b/src/utils/proxy.ts @@ -140,12 +140,6 @@ function isFunction(functionsPort: boolean | number | undefined, url: string) { return functionsPort && url.match(DEFAULT_FUNCTION_URL_EXPRESSION) } -function getAddonUrl(addonsUrls: Record, req: http.IncomingMessage) { - const matches = req.url?.match(/^\/.netlify\/([^/]+)(\/.*)/) - const addonUrl = matches && addonsUrls[matches[1]] - return addonUrl ? `${addonUrl}${matches[2]}` : null -} - const getStatic = async function (pathname: string, publicFolder: string) { const alternatives = [pathname, ...alternativePathsFor(pathname)].map((filePath) => path.resolve(publicFolder, filePath.slice(1)), @@ -197,14 +191,6 @@ const proxyToExternalUrl = function ({ void handler(req, res, () => {}) } -// @ts-expect-error TS(7031) FIXME: Binding element 'addonUrl' implicitly has an 'any'... Remove this comment to see the full error message -const handleAddonUrl = function ({ addonUrl, req, res }) { - const dest = new URL(addonUrl) - const destURL = stripOrigin(dest) - - proxyToExternalUrl({ req, res, dest, destURL }) -} - const isRedirect = function (match: MatchResult | { status?: number | undefined }): boolean { return 'status' in match && match.status != null && match.status >= 300 && match.status <= 400 } @@ -309,12 +295,6 @@ const serveRedirect = async function ({ return proxy.web(req, res, { target: options.functionsServer }) } - const urlForAddons = getAddonUrl(options.addonsUrls, req) - if (urlForAddons) { - handleAddonUrl({ req, res, addonUrl: urlForAddons }) - return - } - const originalURL = req.url const reqUrl = reqToURL(req, req.url) const isHiddenProxy = @@ -420,12 +400,6 @@ const serveRedirect = async function ({ if (isImageRequest(req)) { return imageProxy(req, res) } - const addonUrl = getAddonUrl(options.addonsUrls, req) - if (addonUrl) { - handleAddonUrl({ req, res, addonUrl }) - return - } - return proxy.web(req, res, { ...options, status: statusValue }) } @@ -751,7 +725,6 @@ const initializeProxy = async function ({ const onRequest = async ( { - addonsUrls, api, edgeFunctionsProxy, env, @@ -806,12 +779,6 @@ const onRequest = async ( return proxy.web(req, res, { headers, target: functionsServer }) } - const addonUrl = getAddonUrl(addonsUrls, req) - if (addonUrl) { - handleAddonUrl({ req, res, addonUrl }) - return - } - if (serverHandler) { try { const requestURL = reqToURL(req, req.url) @@ -857,7 +824,6 @@ const onRequest = async ( const match = await rewriter(req) const options = { match, - addonsUrls, target: `http://${ settings.frameworkHost && isIPv6(settings.frameworkHost) ? `[${settings.frameworkHost}]` : settings.frameworkHost }:${settings.frameworkPort}`, @@ -926,7 +892,6 @@ type EdgeFunctionsProxy = Awaited