import { APIClient } from '@heroku-cli/command'; import type { ExtendedAddon, ExtendedAddonAttachment } from '../../types/pg/platform-api.js'; import type { ConnectionDetails } from '../../types/pg/tunnel.js'; import { fetchBastionConfig } from './bastion.js'; import { getConfig } from './config-vars.js'; export default class DatabaseResolver { private readonly heroku; private readonly getConfigFn; private readonly fetchBastionConfigFn; private readonly addonAttachmentResolver; private readonly addonHeaders; private readonly attachmentHeaders; constructor(heroku: APIClient, getConfigFn?: typeof getConfig, fetchBastionConfigFn?: typeof fetchBastionConfig); /** * Parses a PostgreSQL connection string (or a local database name) into a ConnectionDetails object. * * @param connStringOrDbName - PostgreSQL connection string or local database name * @returns Connection details object with parsed connection information */ static parsePostgresConnectionString(connStringOrDbName: string): ConnectionDetails; /** * Return all Heroku Postgres databases on the Legacy tiers for a given app. * * @param app - The name of the app to get the databases for * @returns Promise resolving to all Heroku Postgres databases * @throws {Error} When no legacy database add-on exists on the app */ getAllLegacyDatabases(app: string): Promise>; /** * Resolves an arbitrary legacy database add-on based on the provided app name. * * @param app - The name of the app to get the arbitrary legacy database for * @returns Promise resolving to the arbitrary legacy database add-on * @throws {Error} When no legacy database add-on exists on the app */ getArbitraryLegacyDB(app: string): Promise; /** * Resolves a database attachment based on the provided database identifier * (attachment name, id, or config var name) and namespace (credential). * * @param appId - The ID of the app to get the attachment for * @param attachmentId - The database identifier (defaults to 'DATABASE_URL') * @param namespace - Optional namespace/credential for the attachment * @returns Promise resolving to the database attachment * @throws {Error} When no databases exist or when database identifier is unknown * @throws {AmbiguousError} When multiple matching attachments are found */ getAttachment(appId: string, attachmentId?: string, namespace?: string): Promise; /** * Returns the connection details for a database attachment according to the app config vars. * * @param attachment - The attachment to get the connection details for * @param config - The record of app config vars with their values * @returns Connection details with attachment information */ getConnectionDetails(attachment: ExtendedAddonAttachment, config?: Record): ConnectionDetails; /** * Returns the connection details for a database attachment resolved through the identifiers passed as * arguments: appId, attachmentId and namespace (credential). * * @param appId - The ID of the app containing the database * @param attachmentId - Optional database identifier (defaults to 'DATABASE_URL') * @param namespace - Optional namespace/credential for the attachment * @returns Promise resolving to connection details with attachment information */ getDatabase(appId: string, attachmentId?: string, namespace?: string): Promise; /** * Helper function that attempts to find all Heroku Postgres attachments on a given app. * * @param app - The name of the app to get the attachments for * @returns Promise resolving to an array of all Heroku Postgres attachments on the app */ private allLegacyDatabaseAttachments; /** * Fetches all Heroku PostgreSQL add-on attachments for a given app. * * This is used internally by the `getAttachment` function to get all valid Heroku PostgreSQL add-on attachments * to generate a list of possible valid attachments when the user passes a database name that doesn't match any * attachments. * * @param appId - The ID of the app to get the attachments for * @returns Promise resolving to array of PostgreSQL add-on attachments */ private allPostgresAttachments; /** * Helper function that groups Heroku Postgres attachments by addon. * * @param attachments - The attachments to group by addon * @returns A record of addon IDs with their attachment names */ private getAttachmentNamesByAddon; /** * Helper function that attempts to find a single addon attachment matching the given database identifier * by comparing the identifier to the config var names of all attachments on the app * (attachment name, id, or config var name). * * This is used internally by the `getAttachment` function to handle the lookup of addon attachments. * It returns either an array with a single match or an empty array if no matches are found. * * @param attachments - Array of attachments for the specified app ID * @param appId - The ID of the app to search for attachments * @param attachmentId - The database identifier to match * @returns Promise resolving to either a single match or no matches */ private getAttachmentsViaConfigVarNames; /** * Helper function that attempts to find a single addon attachment matching the given database identifier * via the add-on attachments resolver * (attachment name, id, or config var name). * * This is used internally by the `getAttachment` function to handle the lookup of addon attachments. * It returns either a single match, multiple matches (for ambiguous cases), or null if no matches are found. * * The AddonAttachmentResolver uses the Platform API add-on attachment resolver endpoint to get the attachment. * * @param appId - The ID of the app to search for attachments * @param attachmentId - The database identifier to match * @param namespace - Optional namespace/credential filter * @returns Promise resolving to either a single match, multiple matches with error, or no matches with error */ private getAttachmentsViaResolver; }