BlueSky & more on desktop
lazurite.stormlightlabs.org/
tauri
rust
typescript
bluesky
appview
atproto
solid
1import type { ListNotificationsResponse, NotificationView } from "$/lib/types";
2import { invoke } from "@tauri-apps/api/core";
3
4function asRecord(value: unknown): Record<string, unknown> | null {
5 if (!value || typeof value !== "object" || Array.isArray(value)) {
6 return null;
7 }
8
9 return value as Record<string, unknown>;
10}
11
12function isNotificationView(value: unknown): value is NotificationView {
13 const record = asRecord(value);
14 const author = asRecord(record?.author);
15 const notificationRecord = asRecord(record?.record);
16
17 return !!record
18 && !!author
19 && !!notificationRecord
20 && typeof record.uri === "string"
21 && typeof record.cid === "string"
22 && typeof author.did === "string"
23 && typeof author.handle === "string"
24 && typeof record.reason === "string"
25 && typeof record.isRead === "boolean"
26 && typeof record.indexedAt === "string";
27}
28
29export function parseListNotificationsResponse(value: unknown): ListNotificationsResponse {
30 const record = asRecord(value);
31 const notifications = record?.notifications;
32 const seenAt = record?.seenAt;
33
34 if (!record || !Array.isArray(notifications) || !notifications.every((item) => isNotificationView(item))) {
35 throw new Error("notifications response payload is invalid");
36 }
37
38 if (record.cursor !== undefined && record.cursor !== null && typeof record.cursor !== "string") {
39 throw new Error("notifications response cursor is invalid");
40 }
41
42 if (seenAt !== undefined && seenAt !== null && typeof seenAt !== "string") {
43 throw new Error("notifications response seenAt is invalid");
44 }
45
46 return {
47 cursor: (record.cursor as string | null | undefined) ?? null,
48 notifications,
49 seenAt: (seenAt as string | null | undefined) ?? null,
50 };
51}
52
53export function listNotifications(cursor?: string | null) {
54 return invoke("list_notifications", { cursor: cursor ?? null }).then(parseListNotificationsResponse);
55}
56
57export function updateSeen() {
58 return invoke<void>("update_seen");
59}
60
61export function getUnreadCount() {
62 return invoke<number>("get_unread_count");
63}