feat: handle 202 queued response and awaiting_approval status in ensurePeered

This commit is contained in:
Jannis Braun
2026-04-20 14:51:59 +02:00
parent 14041e9d11
commit 9877d78a3a
2 changed files with 37 additions and 1 deletions
@@ -31,4 +31,15 @@ describe('EnsurePeeredResult type', () => {
}; };
expect(result.status).toBe('failed'); 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');
}
});
}); });
+26 -1
View File
@@ -10,7 +10,20 @@ import { validateOrigin } from '../routes/federation.js';
export type EnsurePeeredResult = export type EnsurePeeredResult =
| { status: 'active'; peerId: string } | { status: 'active'; peerId: string }
| { status: 'rejected'; error: 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 ───────────────────────────────────────────────── // ─── In-flight deduplication ─────────────────────────────────────────────────
@@ -59,6 +72,8 @@ export async function ensurePeered(origin: string): Promise<EnsurePeeredResult>
// Unreachable peers were previously active — treat as active for peering // Unreachable peers were previously active — treat as active for peering
// (the health check will restore them; don't re-handshake) // (the health check will restore them; don't re-handshake)
return { status: 'active', peerId: existing.id }; return { status: 'active', peerId: existing.id };
case 'awaiting_approval':
return { status: 'pending', error: 'Awaiting admin approval on remote instance' };
case 'pending': case 'pending':
// Fall through to dedup logic below // Fall through to dedup logic below
break; break;
@@ -119,6 +134,7 @@ async function performHandshake(
body: JSON.stringify({ body: JSON.stringify({
sourceOrigin: ourOrigin, sourceOrigin: ourOrigin,
hmacSecret, hmacSecret,
instanceName: getInstanceName(),
}), }),
signal: AbortSignal.timeout(10_000), signal: AbortSignal.timeout(10_000),
}); });
@@ -132,6 +148,15 @@ async function performHandshake(
return { status: 'active', peerId }; 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) // Check for explicit rejection (autoAcceptPeering = 0)
let code: string | undefined; let code: string | undefined;
let errorMessage = `Remote rejected peering (HTTP ${response.status})`; let errorMessage = `Remote rejected peering (HTTP ${response.status})`;