import { RNX_CHANGELOG_API_URL, RNX_CHANGELOG_URL } from '../src/runtime-delivery' import type { ChangelogEntry } from '../../../scripts/changelog/types' function isChangelogEntry(value: unknown): value is ChangelogEntry { if (!value || typeof value !== 'object') return false const sections = Reflect.get(value, 'sections') return ( typeof Reflect.get(value, 'title') === 'string' && Array.isArray(sections) && sections.every( (section) => section && typeof section === 'object' && typeof Reflect.get(section, 'title') === 'string' && Array.isArray(Reflect.get(section, 'items')) && Reflect.get(section, 'items').every( (item: unknown) => item && typeof item === 'object' && typeof Reflect.get(item, 'summary') === 'string' && typeof Reflect.get(item, 'hash') === 'string', ), ) ) } export async function fetchRuntimeReleaseNotes( version: string, fetchImpl: typeof fetch = fetch, ): Promise { try { const url = new URL(RNX_CHANGELOG_API_URL) url.searchParams.set('version', version) const response = await fetchImpl(url, { headers: { accept: 'application/json' }, signal: AbortSignal.timeout(5000), }) if (!response.ok) return null const payload: unknown = await response.json() if (!payload || typeof payload !== 'object') return null const entries = Reflect.get(payload, 'entries') if (!Array.isArray(entries) || !isChangelogEntry(entries[0])) return null return entries[0] } catch { return null } } export function formatRuntimeReleaseNotes( version: string, entry: ChangelogEntry | null, ): string { const lines = [`what's new in rnx engine v${version}:`] if (!entry || entry.sections.length === 0) { lines.push(` release notes are not available yet`) } else { for (const section of entry.sections) { lines.push(` ${section.title}:`) for (const item of section.items) { lines.push(` • ${item.summary}`) } } } lines.push(` full changelog: ${RNX_CHANGELOG_URL}`) return lines.join('\n') }