import asyncRetry from 'async-retry'; import Docker from 'dockerode'; import { humanId } from 'human-id'; let docker: Docker | null = null; function getDockerConnection() { if (!docker) { docker = new Docker(); } return docker; } const LOCAL_SERVICES = { server: 3001, clickhouse: 8123, emails: 6260, composition_federation_2: 3069, usage: 4001, schema: 6500, external_composition: 3012, mock_server: 3042, 'otel-collector': 4318, workflows: 3014, } as const; export type KnownServices = keyof typeof LOCAL_SERVICES; export function getCDNPort() { if (process.env.RUN_AGAINST_LOCAL_SERVICES === '1') { return 9000; } return 8083; } export function getAppBaseUrl() { if (process.env.RUN_AGAINST_LOCAL_SERVICES === '1') { return 'localhost:3000'; } return 'localhost:8080'; } export async function getServiceHost( serviceName: KnownServices, servicePort: number, localhost = true, ): Promise { if (process.env.RUN_AGAINST_LOCAL_SERVICES === '1') { return `localhost:${LOCAL_SERVICES[serviceName]}`; } const actualHost = localhost ? 'localhost' : serviceName; const docker = getDockerConnection(); const containers = await docker.listContainers({ filters: JSON.stringify({ label: [`com.docker.compose.service=${serviceName}`], }), }); if (containers.length === 0) { throw new Error(`Failed to locate Docker container for service "${serviceName}"!`); } const container = containers[0]; const ports = container.Ports || []; if (ports.length === 0) { throw new Error( `Container "${container.Id}" for service "${serviceName}" does not expose any ports!`, ); } const publicPort = ports.find(p => p.PublicPort === servicePort); const privatePort = ports.find(p => p.PrivatePort === servicePort); if (!publicPort && !privatePort) { throw new Error( `Container "${container.Id}" for service "${serviceName}" does not expose port "${servicePort}"!`, ); } if (publicPort) { return `${actualHost}:${publicPort.PublicPort}`; } if (privatePort) { console.warn( `Container "${container.Id}" (service: "${serviceName}") expose port "${servicePort}" as "${privatePort.PublicPort}", please consider to update your setup!`, ); return `${actualHost}:${privatePort.PublicPort}`; } return `${actualHost}:${servicePort}`; } export function generateUnique() { return humanId({ separator: '', adjectiveCount: 1, addAdverb: true, capitalize: false, }); } export function assertNonNull( value: T | null, message = 'Expected non-null value.', ): asserts value is T { if (value === null) { throw new Error(message); } } export function assertNonNullish( value: T | null | undefined, message = 'Expected non-null value.', ): asserts value is T { if (value === null) { throw new Error(message); } } export async function pollForEmailVerificationLink(input: string | { email: string; now: number }) { const email = typeof input === 'string' ? input : input.email; const now = new Date(typeof input === 'string' ? Date.now() - 10_000 : input.now).toISOString(); const url = new URL('http://localhost:3014/_history'); url.searchParams.set('after', now); return await asyncRetry( async () => { const emails = await fetch(url.toString()) .then(res => res.json()) .then(emails => emails.filter((e: any) => e.to === email && e.subject === 'Verify your email'), ); if (emails.length === 0) { throw new Error('Could not find email'); } // take the latest one const result = emails[emails.length - 1]; const urlMatch = result.body.match(/href=\"(http:\/\/[^\s"]+)/); if (!urlMatch) throw new Error('No URL found in email'); return new URL(urlMatch[1]); }, { retries: 10, minTimeout: 1000, maxTimeout: 10000, }, ); }