feat(frontend): watches, webhooks and alerts panels read humanly, with chat picker, url filter, test send and delivery log

This commit is contained in:
hh committed 2026-10-19 02:57:27 +00:00
1 parent 6a4fd6ad47
commit ea3a7c0a61
19 files changed
+3699 -458

No files matched your search

+210
View File
@@ -0,0 +1,210 @@
import { request } from "#lib/api/client.js";
import { accounts } from "#lib/stores/accounts.svelte.js";
export type WatchKind =
| "keyword"
| "new_message"
| "message_deleted"
| "message_edited"
| "peer_online";
export interface WatchParams {
chat_id?: number;
pattern?: string;
peer_id?: number;
regex?: boolean;
sender_id?: number;
}
export type StoredParams = WatchParams & { keyword?: string };
export interface ChatRef {
has_avatar: boolean;
id: number;
kind: "private" | "group" | "channel";
title: string | null;
}
export interface PersonRef {
has_avatar: boolean;
id: number;
name: string | null;
}
export interface Watch {
account_id: number;
alert_count: number;
chat: ChatRef | null;
created_at: string;
enabled: boolean;
id: number;
kind: WatchKind;
last_alert_at: string | null;
name: string | null;
params: StoredParams;
person: PersonRef | null;
updated_at: string;
}
export interface WatchDraft {
enabled: boolean;
kind: WatchKind;
name: string | null;
params: WatchParams;
}
export type AlertEvent =
| "message"
| "edit"
| "transcript"
| "delete"
| "online";
export interface AlertMessage {
date: string | null;
deleted: boolean;
edited: boolean;
id: number;
sender: PersonRef | null;
text: string | null;
}
export interface AlertItem {
account_id: number;
away_since: string | null;
chat: ChatRef | null;
event: AlertEvent;
id: number;
message: AlertMessage | null;
path: string;
peer: PersonRef | null;
seen: boolean;
ts: string;
watch: {
id: number;
kind: WatchKind;
name: string | null;
params: StoredParams;
};
}
export interface AlertPage {
items: AlertItem[];
next_before: number | null;
unseen: number;
}
export interface LiveAlertEvent {
alert: AlertItem | null;
type: "alert";
unseen: number;
}
export interface Webhook {
account_id: number;
created_at: string;
enabled: boolean;
id: number;
last_delivery: Delivery | null;
secret: string;
updated_at: string;
url: string;
watch_ids: number[] | null;
}
export interface WebhookDraft {
enabled: boolean;
url: string;
watch_ids: number[] | null;
}
export interface Delivery {
alert_id: number | null;
attempts: number;
created_at: string;
event: "alert" | "test";
finished_at: string | null;
id: number;
last_error: string | null;
next_attempt_at: string;
response_code: number | null;
status: "pending" | "sending" | "delivered" | "failed";
webhook_id: number;
}
export function listWatches(): Promise<Watch[]> {
return request<Watch[]>("/watches", { account: true });
}
export function createWatch(draft: WatchDraft): Promise<Watch> {
return request<Watch>("/watches", {
body: { account_id: accounts.selectedId, ...draft },
method: "POST",
});
}
export function updateWatch(id: number, draft: WatchDraft): Promise<Watch> {
return request<Watch>(`/watches/${id}`, { body: draft, method: "PUT" });
}
export function deleteWatch(id: number): Promise<void> {
return request<void>(`/watches/${id}`, { method: "DELETE" });
}
export function listAlerts(
options: { before?: number; limit?: number; seen?: boolean } = {}
): Promise<AlertPage> {
return request<AlertPage>("/alerts", { account: true, query: options });
}
export async function unseenAlerts(): Promise<number> {
const { unseen } = await request<{ unseen: number }>("/alerts/unseen", {
account: true,
});
return unseen;
}
export function markAlertSeen(id: number): Promise<void> {
return request<void>(`/alerts/${id}/seen`, { method: "POST" });
}
export function markAllAlertsSeen(upTo?: number): Promise<{ marked: number }> {
return request<{ marked: number }>("/alerts/seen", {
body: { account_id: accounts.selectedId, up_to: upTo ?? null },
method: "POST",
});
}
export function listWebhooks(): Promise<Webhook[]> {
return request<Webhook[]>("/webhooks", { account: true });
}
export function createWebhook(draft: WebhookDraft): Promise<Webhook> {
return request<Webhook>("/webhooks", {
body: { account_id: accounts.selectedId, ...draft },
method: "POST",
});
}
export function updateWebhook(
id: number,
draft: WebhookDraft
): Promise<Webhook> {
return request<Webhook>(`/webhooks/${id}`, { body: draft, method: "PUT" });
}
export function deleteWebhook(id: number): Promise<void> {
return request<void>(`/webhooks/${id}`, { method: "DELETE" });
}
export function rotateWebhookSecret(id: number): Promise<Webhook> {
return request<Webhook>(`/webhooks/${id}/secret`, { method: "POST" });
}
export function testWebhook(id: number): Promise<Delivery> {
return request<Delivery>(`/webhooks/${id}/test`, { method: "POST" });
}
export function listDeliveries(id: number): Promise<Delivery[]> {
return request<Delivery[]>(`/webhooks/${id}/deliveries`);
}