2026-03-11 09:03:44 +00:00
import asyncRetry from 'async-retry' ;
2022-12-28 09:37:23 +00:00
import Docker from 'dockerode' ;
2023-02-10 10:11:23 +00:00
import { humanId } from 'human-id' ;
2022-12-28 09:37:23 +00:00
let docker : Docker | null = null ;
function getDockerConnection() {
if ( ! docker ) {
docker = new Docker ( ) ;
}
return docker ;
}
2024-07-15 11:21:23 +00:00
const LOCAL_SERVICES = {
server : 3001 ,
clickhouse : 8123 ,
emails : 6260 ,
composition_federation_2 : 3069 ,
usage : 4001 ,
schema : 6500 ,
external_composition : 3012 ,
2024-11-08 22:06:42 +00:00
mock_server : 3042 ,
2025-11-27 14:36:09 +00:00
'otel-collector' : 4318 ,
2026-01-12 12:13:23 +00:00
workflows : 3014 ,
2024-07-15 11:21:23 +00:00
} 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 < string > {
if ( process . env . RUN_AGAINST_LOCAL_SERVICES === '1' ) {
return ` localhost: ${ LOCAL_SERVICES [ serviceName ] } ` ;
}
const actualHost = localhost ? 'localhost' : serviceName ;
2022-12-28 09:37:23 +00:00
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 ) {
2024-07-15 11:21:23 +00:00
return ` ${ actualHost } : ${ publicPort . PublicPort } ` ;
2022-12-28 09:37:23 +00:00
}
if ( privatePort ) {
console . warn (
` Container " ${ container . Id } " (service: " ${ serviceName } ") expose port " ${ servicePort } " as " ${ privatePort . PublicPort } ", please consider to update your setup! ` ,
) ;
2024-07-15 11:21:23 +00:00
return ` ${ actualHost } : ${ privatePort . PublicPort } ` ;
2022-12-28 09:37:23 +00:00
}
2024-07-15 11:21:23 +00:00
return ` ${ actualHost } : ${ servicePort } ` ;
2022-12-28 09:37:23 +00:00
}
export function generateUnique() {
return humanId ( {
separator : '' ,
2023-12-05 10:54:03 +00:00
adjectiveCount : 1 ,
2022-12-28 09:37:23 +00:00
addAdverb : true ,
capitalize : false ,
} ) ;
}
2025-10-14 12:01:51 +00:00
export function assertNonNull < T > (
value : T | null ,
message = 'Expected non-null value.' ,
) : asserts value is T {
if ( value === null ) {
throw new Error ( message ) ;
}
}
2025-11-10 08:27:37 +00:00
export function assertNonNullish < T > (
value : T | null | undefined ,
message = 'Expected non-null value.' ,
) : asserts value is T {
if ( value === null ) {
throw new Error ( message ) ;
}
}
2026-03-11 09:03:44 +00:00
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 ,
} ,
) ;
}