Files
WeHub Mirror 6bf8bebf51
CI / Test and Build (push) Failing after 1s
CI / Migrate Dev DB (push) Has been skipped
CI / Migrate DB (push) Has been skipped
CodeQL / Analyze actions (push) Has been cancelled
CodeQL / Analyze javascript-typescript (push) Has been cancelled
CI / Detect Version (push) Has been cancelled
CI / Detect Desktop Changes (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/cron.Dockerfile, ubuntu-latest, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build AMD64 (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/cron.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/db.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/pii.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/realtime.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-8vcpu-ubuntu-2404-arm, ./docker/app.Dockerfile, linux-arm64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
Helm Chart / Lint, test, and validate chart (push) Has been cancelled
Helm Chart / Chart version bumped (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
CI / Build Dev ECR (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core) (push) Has been cancelled
CI / Promote Images (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Check Desktop Signing Secrets (push) Has been cancelled
CI / Desktop Release (push) Has been cancelled
CI / Create Desktop Prerelease (push) Has been cancelled
CI / Desktop Prerelease Build (push) Has been cancelled
CI / Publish Desktop Prerelease (push) Has been cancelled
CI / Prune Desktop Prereleases (push) Has been cancelled
Helm Chart / Install on kind and run helm test (push) Has been cancelled
WeHub snapshot of cb28d14c6f2c081de7a0d8729a8c816c9adef67a
2026-08-10 11:17:50 +08:00

113 lines
3.5 KiB
TypeScript

import { readFileSync } from 'node:fs'
import net from 'node:net'
import path from 'node:path'
import tls from 'node:tls'
import { getErrorMessage } from '@sim/utils/errors'
import { sleep } from '@sim/utils/helpers'
import postgres from 'postgres'
import { ROOT } from './env-files.ts'
export interface PgProbeResult {
ok: boolean
error?: string
pgvectorAvailable?: boolean
migrations?: { applied: number | null; journal: number }
}
function journalMigrationCount(): number {
const journalPath = path.join(ROOT, 'packages/db/migrations/meta/_journal.json')
const journal = JSON.parse(readFileSync(journalPath, 'utf8')) as { entries: unknown[] }
return journal.entries.length
}
export async function pgProbe(dsn: string): Promise<PgProbeResult> {
const sql = postgres(dsn, { max: 1, connect_timeout: 5, onnotice: () => {} })
try {
await sql`select 1`
const vector = await sql`select 1 from pg_available_extensions where name = 'vector'`
let applied: number | null = null
try {
const rows = await sql`select count(*)::int as n from drizzle.__drizzle_migrations`
applied = rows[0].n as number
} catch {
applied = null
}
return {
ok: true,
pgvectorAvailable: vector.length > 0,
migrations: { applied, journal: journalMigrationCount() },
}
} catch (error) {
return { ok: false, error: getErrorMessage(error, 'connection failed') }
} finally {
await sql.end({ timeout: 1 })
}
}
export function redisPing(url: string, timeoutMs = 2000): Promise<{ ok: boolean; error?: string }> {
return new Promise((resolve) => {
let parsed: URL
try {
parsed = new URL(url)
} catch {
resolve({ ok: false, error: 'invalid REDIS_URL' })
return
}
const port = Number(parsed.port || 6379)
const secure = parsed.protocol === 'rediss:'
const socket = secure
? tls.connect({
host: parsed.hostname,
port,
servername: process.env.REDIS_TLS_SERVERNAME || parsed.hostname,
})
: net.connect({ host: parsed.hostname, port })
let buffer = ''
const done = (result: { ok: boolean; error?: string }) => {
socket.destroy()
resolve(result)
}
socket.setTimeout(timeoutMs, () => done({ ok: false, error: 'timeout' }))
socket.once('error', (error) => done({ ok: false, error: getErrorMessage(error) }))
socket.once(secure ? 'secureConnect' : 'connect', () => {
const auth = parsed.password
? `AUTH ${parsed.username || ''} ${parsed.password}\r\n`.replace('AUTH ', 'AUTH ')
: ''
socket.write(`${auth}PING\r\n`)
})
socket.on('data', (chunk) => {
buffer += chunk.toString()
if (buffer.includes('+PONG')) done({ ok: true })
else if (
buffer.includes('-ERR') ||
buffer.includes('-NOAUTH') ||
buffer.includes('-WRONGPASS')
)
done({ ok: false, error: buffer.split('\r\n')[0] })
})
})
}
export async function httpHealth(url: string, timeoutMs = 3000): Promise<boolean> {
try {
const res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) })
return res.ok
} catch {
return false
}
}
/** Polls a probe until it succeeds or the window elapses. */
export async function waitFor(
probe: () => Promise<boolean>,
totalMs: number,
intervalMs = 2000
): Promise<boolean> {
const deadline = Date.now() + totalMs
while (Date.now() < deadline) {
if (await probe()) return true
await sleep(intervalMs)
}
return probe()
}