diff --git a/apps/edr-freight-api/src/config/ensure-postgres-schemas.ts b/apps/edr-freight-api/src/config/ensure-postgres-schemas.ts index 99fbcab61..0f359a942 100644 --- a/apps/edr-freight-api/src/config/ensure-postgres-schemas.ts +++ b/apps/edr-freight-api/src/config/ensure-postgres-schemas.ts @@ -10,6 +10,13 @@ export const APPLICATION_SCHEMAS = [ export const APPLICATION_SEARCH_PATH = APPLICATION_SCHEMAS.join(","); +/** + * Extensions the migrations call into but never create themselves — both the IAM + * package's migrations and the freight baseline default columns to + * `uuid_generate_v4()` / `gen_random_uuid()`. + */ +export const APPLICATION_EXTENSIONS = ["uuid-ossp", "pgcrypto"] as const; + /** * TypeORM creates the migrations table before any migration runs. If `public` was * dropped, current_schema() is null and CREATE TABLE migrations fails. @@ -42,6 +49,20 @@ export async function ensurePostgresSchemas( } } + // Best effort: creating an extension needs elevated rights the app user may not + // have. On an established database they are already installed and this is a + // no-op, so a failure here is only fatal for a brand-new database — where the + // first migration will fail loudly on the missing function anyway. + for (const extension of APPLICATION_EXTENSIONS) { + try { + await bootstrap.query(`CREATE EXTENSION IF NOT EXISTS "${extension}"`); + } catch (err) { + console.warn( + `could not ensure extension "${extension}": ${(err as Error).message}`, + ); + } + } + await bootstrap.query( `SET search_path TO ${APPLICATION_SEARCH_PATH}`, );