From 9877d78a3a47b41d01dee406dac7d5b0f195c6b3 Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Mon, 20 Apr 2026 14:51:59 +0200 Subject: [PATCH] feat: handle 202 queued response and awaiting_approval status in ensurePeered --- .../src/utils/federationPeering.test.ts | 11 ++++++++ .../server/src/utils/federationPeering.ts | 27 ++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/packages/server/src/utils/federationPeering.test.ts b/packages/server/src/utils/federationPeering.test.ts index da3216ad..e25d4495 100644 --- a/packages/server/src/utils/federationPeering.test.ts +++ b/packages/server/src/utils/federationPeering.test.ts @@ -31,4 +31,15 @@ describe('EnsurePeeredResult type', () => { }; expect(result.status).toBe('failed'); }); + + it('pending result has error', () => { + const result: EnsurePeeredResult = { + status: 'pending', + error: 'Awaiting admin approval on remote instance', + }; + expect(result.status).toBe('pending'); + if (result.status === 'pending') { + expect(result.error).toContain('admin approval'); + } + }); }); diff --git a/packages/server/src/utils/federationPeering.ts b/packages/server/src/utils/federationPeering.ts index 18807bd6..72d46dc4 100644 --- a/packages/server/src/utils/federationPeering.ts +++ b/packages/server/src/utils/federationPeering.ts @@ -10,7 +10,20 @@ import { validateOrigin } from '../routes/federation.js'; export type EnsurePeeredResult = | { status: 'active'; peerId: string } | { status: 'rejected'; error: string } - | { status: 'failed'; error: string }; + | { status: 'failed'; error: string } + | { status: 'pending'; error: string }; + +// ─── Helpers ───────────────────────────────────────────────────────────────── + +function getInstanceName(): string | undefined { + const db = getDb(); + const row = db + .select({ name: schema.instanceSettings.instanceName }) + .from(schema.instanceSettings) + .where(eq(schema.instanceSettings.id, 1)) + .get(); + return row?.name ?? undefined; +} // ─── In-flight deduplication ───────────────────────────────────────────────── @@ -59,6 +72,8 @@ export async function ensurePeered(origin: string): Promise // Unreachable peers were previously active — treat as active for peering // (the health check will restore them; don't re-handshake) return { status: 'active', peerId: existing.id }; + case 'awaiting_approval': + return { status: 'pending', error: 'Awaiting admin approval on remote instance' }; case 'pending': // Fall through to dedup logic below break; @@ -119,6 +134,7 @@ async function performHandshake( body: JSON.stringify({ sourceOrigin: ourOrigin, hmacSecret, + instanceName: getInstanceName(), }), signal: AbortSignal.timeout(10_000), }); @@ -132,6 +148,15 @@ async function performHandshake( return { status: 'active', peerId }; } + if (response.status === 202) { + // Request queued for admin approval on the remote side + db.update(schema.federationPeers) + .set({ status: 'awaiting_approval' }) + .where(eq(schema.federationPeers.id, peerId)) + .run(); + return { status: 'pending', error: 'Awaiting admin approval on remote instance' }; + } + // Check for explicit rejection (autoAcceptPeering = 0) let code: string | undefined; let errorMessage = `Remote rejected peering (HTTP ${response.status})`;