feat(web): API client methods for peering subscriptions and notifications

- Drops the web-local ApprovalRequest interface in favor of the
  canonical shared type (Task 2 already established this; Task 10
  reconciles the consumer side).
- Adds five new federation methods wrapping the REST endpoints
  added in Tasks 8 and 9: peeringSubscriptions (GET), cancelPeering
  Subscription (DELETE), peeringNotifications (GET +/- unreadOnly
  filter), markPeeringNotificationRead (POST :id/read), markAll
  PeeringNotificationsRead (POST read-all).
This commit is contained in:
Jannis Braun
2026-04-26 22:32:36 +02:00
parent e82ccbde62
commit 51da827089
+30 -9
View File
@@ -53,9 +53,12 @@ import type {
FederationIdentityDeleteRequest, FederationIdentityDeleteRequest,
FederationIdentityDeleteResponse, FederationIdentityDeleteResponse,
FederationPeer, FederationPeer,
ApprovalRequest,
PeeringSubscription,
PeeringNotification,
} from '@backspace/shared'; } from '@backspace/shared';
export type { FederationPeer }; export type { FederationPeer, ApprovalRequest, PeeringSubscription, PeeringNotification };
export class RateLimitError extends Error { export class RateLimitError extends Error {
readonly retryAfter: number; readonly retryAfter: number;
@@ -66,14 +69,6 @@ export class RateLimitError extends Error {
} }
} }
export interface ApprovalRequest {
id: string;
origin: string;
instanceName: string | null;
requestedAt: number;
expiresAt: number;
}
export class BackspaceApiClient { export class BackspaceApiClient {
readonly auth: { readonly auth: {
register: (data: RegisterRequest) => Promise<AuthResponse>; register: (data: RegisterRequest) => Promise<AuthResponse>;
@@ -230,6 +225,11 @@ export class BackspaceApiClient {
approvalRequests: () => Promise<{ requests: ApprovalRequest[] }>; approvalRequests: () => Promise<{ requests: ApprovalRequest[] }>;
approveRequest: (id: string) => Promise<{ success: boolean; peer?: FederationPeer }>; approveRequest: (id: string) => Promise<{ success: boolean; peer?: FederationPeer }>;
denyRequest: (id: string) => Promise<{ success: boolean }>; denyRequest: (id: string) => Promise<{ success: boolean }>;
peeringSubscriptions: () => Promise<{ subscriptions: PeeringSubscription[] }>;
cancelPeeringSubscription: (id: string) => Promise<{ success: boolean }>;
peeringNotifications: (unreadOnly?: boolean) => Promise<{ notifications: PeeringNotification[] }>;
markPeeringNotificationRead: (id: string) => Promise<{ success: boolean }>;
markAllPeeringNotificationsRead: () => Promise<{ success: boolean; count: number }>;
}; };
readonly admin: { readonly admin: {
@@ -697,6 +697,27 @@ export class BackspaceApiClient {
request<{ success: boolean }>( request<{ success: boolean }>(
'POST', `/federation/approval-requests/${id}/deny` 'POST', `/federation/approval-requests/${id}/deny`
), ),
peeringSubscriptions: () =>
request<{ subscriptions: PeeringSubscription[] }>(
'GET', '/federation/peering-subscriptions'
),
cancelPeeringSubscription: (id: string) =>
request<{ success: boolean }>(
'DELETE', `/federation/peering-subscriptions/${id}`
),
peeringNotifications: (unreadOnly = false) =>
request<{ notifications: PeeringNotification[] }>(
'GET',
`/federation/peering-notifications${unreadOnly ? '?unread=1' : ''}`,
),
markPeeringNotificationRead: (id: string) =>
request<{ success: boolean }>(
'POST', `/federation/peering-notifications/${id}/read`
),
markAllPeeringNotificationsRead: () =>
request<{ success: boolean; count: number }>(
'POST', '/federation/peering-notifications/read-all'
),
}; };
this.admin = { this.admin = {