From f31e586e852e50ddea456e1c3dc818250c818e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lohrer?= Date: Sat, 18 Apr 2026 05:39:51 +0200 Subject: [PATCH] publish(task 16): check-subcommand (pre-flight-validation) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit runCheck(config) prüft vor jedem publish-run: - bunker-signer erreichbar und pubkey matcht AUTHOR_PUBKEY_HEX - kind:10002 outbox-liste enthält mindestens 1 write-relay - kind:10063 blossom-liste nicht leer, alle server antworten auf HEAD / (405 wird toleriert — blossom-server erlauben oft kein HEAD) liefert { ok, issues }. printCheckResult() druckt ✓ oder ✗ + liste. Co-Authored-By: Claude Opus 4.6 (1M context) --- publish/src/subcommands/check.ts | 65 ++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 publish/src/subcommands/check.ts diff --git a/publish/src/subcommands/check.ts b/publish/src/subcommands/check.ts new file mode 100644 index 0000000..3c5f77f --- /dev/null +++ b/publish/src/subcommands/check.ts @@ -0,0 +1,65 @@ +import type { Config } from '../core/config.ts' +import { createBunkerSigner } from '../core/signer.ts' +import { loadOutbox } from '../core/outbox.ts' +import { loadBlossomServers } from '../core/blossom-list.ts' + +export interface CheckResult { + ok: boolean + issues: string[] +} + +export async function runCheck(config: Config): Promise { + const issues: string[] = [] + + try { + const signer = await createBunkerSigner(config.bunkerUrl) + const pk = await signer.getPublicKey() + if (pk !== config.authorPubkeyHex) { + issues.push( + `bunker-pubkey (${pk}) matcht AUTHOR_PUBKEY_HEX (${config.authorPubkeyHex}) nicht`, + ) + } + } catch (err) { + issues.push(`bunker-ping fehlgeschlagen: ${err instanceof Error ? err.message : err}`) + } + + try { + const outbox = await loadOutbox(config.bootstrapRelay, config.authorPubkeyHex) + if (outbox.write.length === 0) { + issues.push('kind:10002 hat keine write-relays — publiziere zuerst ein gültiges Event') + } + } catch (err) { + issues.push(`kind:10002 laden: ${err instanceof Error ? err.message : err}`) + } + + try { + const servers = await loadBlossomServers(config.bootstrapRelay, config.authorPubkeyHex) + if (servers.length === 0) { + issues.push('kind:10063 hat keine server — publiziere zuerst ein gültiges Event') + } else { + for (const server of servers) { + try { + const resp = await fetch(server + '/', { method: 'HEAD' }) + if (!resp.ok && resp.status !== 405) { + issues.push(`blossom-server ${server}: HTTP ${resp.status}`) + } + } catch (err) { + issues.push(`blossom-server ${server}: ${err instanceof Error ? err.message : err}`) + } + } + } + } catch (err) { + issues.push(`kind:10063 laden: ${err instanceof Error ? err.message : err}`) + } + + return { ok: issues.length === 0, issues } +} + +export function printCheckResult(result: CheckResult): void { + if (result.ok) { + console.log('✓ pre-flight ok') + return + } + console.error('✗ pre-flight issues:') + for (const i of result.issues) console.error(` - ${i}`) +}