BlueSky & more on desktop
lazurite.stormlightlabs.org/
tauri
rust
typescript
bluesky
appview
atproto
solid
1export type Maybe<T> = T | null | undefined;
2
3export type ModerationLabel = { src?: string; uri?: string; val?: string; [key: string]: unknown };
4
5export type ModerationUiBadge = {
6 label: string;
7 source: string;
8 description?: string | null;
9 tone?: "alert" | "inform" | "label" | string;
10};
11
12export type ModerationUiDecision = {
13 filter: boolean;
14 blur: "none" | "content" | "media" | string;
15 alert: boolean;
16 inform: boolean;
17 noOverride: boolean;
18 badges?: ModerationUiBadge[] | null;
19};
20
21export type ModerationLabelVisibility = "ignore" | "warn" | "hide";
22
23export type ModerationContext =
24 | "contentList"
25 | "contentView"
26 | "contentMedia"
27 | "avatar"
28 | "profileList"
29 | "profileView";
30
31export type ModerationLabelPolicyLocale = { lang: string; name: string; description: string };
32
33export type ModerationLabelPolicyDefinition = {
34 identifier: string;
35 adultOnly: boolean;
36 defaultSetting?: string | null;
37 severity: string;
38 blurs: string;
39 displayName?: string | null;
40 description?: string | null;
41 locales: ModerationLabelPolicyLocale[];
42};
43
44export type ModerationLabelerPolicyDefinition = {
45 labelerDid: string;
46 labelerHandle?: string | null;
47 labelerDisplayName?: string | null;
48 reasonTypes?: string[] | null;
49 subjectTypes?: string[] | null;
50 subjectCollections?: string[] | null;
51 definitions: ModerationLabelPolicyDefinition[];
52};
53
54export type StoredModerationPrefs = {
55 adultContentEnabled: boolean;
56 subscribedLabelers: string[];
57 labelPreferences: Record<string, Record<string, ModerationLabelVisibility | string>>;
58};
59
60export type DistributionChannel = "github" | "mac_app_store" | "microsoft_store";
61
62export type ReportSubjectInput = { type: "repo"; did: string } | { type: "record"; uri: string; cid: string };
63
64export type ModerationReasonType =
65 | "com.atproto.moderation.defs#reasonSpam"
66 | "com.atproto.moderation.defs#reasonViolation"
67 | "com.atproto.moderation.defs#reasonMisleading"
68 | "com.atproto.moderation.defs#reasonSexual"
69 | "com.atproto.moderation.defs#reasonRude"
70 | "com.atproto.moderation.defs#reasonOther";
71
72export type AccountSummary = { did: string; handle: string; pdsUrl: string; active: boolean; avatar?: string | null };
73
74export type ActiveSession = { did: string; handle: string };
75
76export type AppBootstrap = { activeSession: ActiveSession | null; accountList: AccountSummary[] };
77
78export type ActorSuggestion = { did: string; handle: string; displayName?: string | null; avatar?: string | null };
79
80export type LoginSuggestion = ActorSuggestion;
81
82type SavedFeedKind = "timeline" | "feed" | "list";
83
84export type SavedFeedItem = { id: string; type: SavedFeedKind; value: string; pinned: boolean };
85
86export type FeedViewPrefItem = {
87 feed: string;
88 hideReplies: boolean;
89 hideRepliesByUnfollowed: boolean;
90 hideRepliesByLikeCount: number | null;
91 hideReposts: boolean;
92 hideQuotePosts: boolean;
93};
94
95export type FeedViewPrefs = Array<FeedViewPrefItem>;
96
97export type UserPreferences = { savedFeeds: SavedFeedItem[]; feedViewPrefs: FeedViewPrefs };
98
99type AuthorViewerState = { following?: string | null };
100
101export type ProfileViewBasic = {
102 did: string;
103 handle: string;
104 displayName?: string | null;
105 avatar?: string | null;
106 description?: string | null;
107 labels?: ModerationLabel[] | null;
108 viewer?: AuthorViewerState | null;
109};
110
111type ProfileViewerState = {
112 blockedBy?: boolean | null;
113 followedBy?: string | null;
114 following?: string | null;
115 muted?: boolean | null;
116};
117
118export type ProfileUnavailableReason = "notFound" | "suspended" | "deactivated" | "unavailable";
119
120export type ProfileViewDetailed = ProfileViewBasic & {
121 banner?: string | null;
122 createdAt?: string | null;
123 description?: string | null;
124 descriptionFacets?: RichTextFacet[] | null;
125 followersCount?: number | null;
126 followsCount?: number | null;
127 indexedAt?: string | null;
128 pinnedPost?: { cid?: string | null; uri: string } | null;
129 postsCount?: number | null;
130 pronouns?: string | null;
131 viewer?: ProfileViewerState | null;
132 website?: string | null;
133};
134
135type ProfileLookupAvailable = { status: "available"; profile: ProfileViewDetailed };
136
137export type ProfileLookupUnavailable = {
138 status: "unavailable";
139 requestedActor: string;
140 did?: string | null;
141 handle?: string | null;
142 reason: ProfileUnavailableReason;
143 message: string;
144};
145
146export type ProfileLookupResult = ProfileLookupAvailable | ProfileLookupUnavailable;
147
148export type ActorListResponse = { cursor?: string | null; actors: ProfileViewBasic[] };
149
150export type FlaggedFollow = { did: string; followUri: string; handle: string; status: number; statusLabel: string };
151
152export type FollowBatchResult = { deleted: number; failed: string[] };
153
154export type FollowHygieneProgress = { batchSize: number; current: number; total: number };
155
156export type FeedGeneratorView = {
157 uri: string;
158 did: string;
159 displayName: string;
160 avatar?: string | null;
161 description?: string | null;
162 creator?: ProfileViewBasic | null;
163};
164
165export type FeedGeneratorsResponse = { feeds: FeedGeneratorView[] };
166
167export type ViewerState = {
168 bookmarked?: boolean | null;
169 embeddingDisabled?: boolean | null;
170 like?: string | null;
171 pinned?: boolean | null;
172 replyDisabled?: boolean | null;
173 repost?: string | null;
174 threadMuted?: boolean | null;
175};
176
177export type PostRecord = {
178 $type?: string;
179 createdAt?: string;
180 embed?: Record<string, unknown> | null;
181 facets?: RichTextFacet[] | null;
182 text?: string;
183 [key: string]: unknown;
184};
185
186type RichTextByteSlice = { byteEnd: number; byteStart: number };
187
188type RichTextLinkFacet = { $type: "app.bsky.richtext.facet#link"; uri: string };
189
190type RichTextMentionFacet = { $type: "app.bsky.richtext.facet#mention"; did: string };
191
192type RichTextTagFacet = { $type: "app.bsky.richtext.facet#tag"; tag: string };
193
194export type RichTextFacetFeature = RichTextLinkFacet | RichTextMentionFacet | RichTextTagFacet;
195
196export type RichTextFacet = { features: RichTextFacetFeature[]; index: RichTextByteSlice };
197
198type ImageEmbed = { alt?: string; aspectRatio?: { height: number; width: number }; fullsize?: string; thumb?: string };
199
200export type ImagesEmbedView = { $type: "app.bsky.embed.images#view"; images: Array<ImageEmbed> };
201
202type ExternalEmbedView = {
203 $type: "app.bsky.embed.external#view";
204 external: { description?: string; thumb?: string; title?: string; uri?: string };
205};
206
207type VideoEmbedView = {
208 $type: "app.bsky.embed.video#view";
209 alt?: string;
210 aspectRatio?: { height: number; width: number };
211 playlist?: string;
212 thumbnail?: string;
213};
214
215type EmbeddedRecordViewRecord = {
216 $type?: "app.bsky.embed.record#viewRecord";
217 author?: ProfileViewBasic;
218 cid?: string;
219 embeds?: EmbedView[];
220 indexedAt?: string;
221 labels?: ModerationLabel[] | null;
222 uri?: string;
223 value?: Record<string, unknown>;
224};
225
226type EmbeddedRecordViewBlocked = {
227 $type?: "app.bsky.embed.record#viewBlocked";
228 author?: ProfileViewBasic;
229 blocked?: boolean;
230 uri?: string;
231};
232
233type EmbeddedRecordViewDetached = { $type?: "app.bsky.embed.record#viewDetached"; detached?: boolean; uri?: string };
234
235type EmbeddedRecordViewNotFound = { $type?: "app.bsky.embed.record#viewNotFound"; notFound?: boolean; uri?: string };
236
237type EmbeddedGeneratorView = {
238 $type: "app.bsky.feed.defs#generatorView";
239 creator?: ProfileViewBasic;
240 description?: string;
241 displayName?: string;
242 uri?: string;
243};
244
245type EmbeddedListView = {
246 $type: "app.bsky.graph.defs#listView";
247 creator?: ProfileViewBasic;
248 description?: string;
249 name?: string;
250 uri?: string;
251};
252
253type EmbeddedLabelerView = { $type: "app.bsky.labeler.defs#labelerView"; creator?: ProfileViewBasic; uri?: string };
254
255type EmbeddedStarterPackView = {
256 $type: "app.bsky.graph.defs#starterPackViewBasic";
257 creator?: ProfileViewBasic;
258 record?: Record<string, unknown>;
259 uri?: string;
260};
261
262type EmbeddedUnknownRecord = { $type?: string; [key: string]: unknown };
263
264export type EmbeddedRecordView =
265 | EmbeddedGeneratorView
266 | EmbeddedLabelerView
267 | EmbeddedListView
268 | EmbeddedRecordViewBlocked
269 | EmbeddedRecordViewDetached
270 | EmbeddedRecordViewNotFound
271 | EmbeddedRecordViewRecord
272 | EmbeddedStarterPackView
273 | EmbeddedUnknownRecord;
274
275type RecordEmbedView = { $type: "app.bsky.embed.record#view"; record: EmbeddedRecordView };
276
277type RecordWithMediaEmbedView = {
278 $type: "app.bsky.embed.recordWithMedia#view";
279 media?: ExternalEmbedView | ImagesEmbedView | VideoEmbedView | EmbeddedUnknownRecord;
280 record?: RecordEmbedView;
281};
282
283export type EmbedView =
284 | ExternalEmbedView
285 | ImagesEmbedView
286 | RecordEmbedView
287 | RecordWithMediaEmbedView
288 | VideoEmbedView;
289
290export type PostView = {
291 author: ProfileViewBasic;
292 cid: string;
293 embed?: EmbedView | null;
294 indexedAt: string;
295 labels?: ModerationLabel[] | null;
296 likeCount?: number | null;
297 quoteCount?: number | null;
298 record: PostRecord | Record<string, unknown>;
299 replyCount?: number | null;
300 repostCount?: number | null;
301 uri: string;
302 viewer?: ViewerState | null;
303};
304
305export type NotFoundPost = { $type: "app.bsky.feed.defs#notFoundPost"; notFound: boolean; uri: string };
306
307export type BlockedPost = {
308 $type: "app.bsky.feed.defs#blockedPost";
309 blocked: boolean;
310 uri: string;
311 author?: ProfileViewBasic;
312};
313
314export type FeedReplyNode = ({ $type: "app.bsky.feed.defs#postView" } & PostView) | NotFoundPost | BlockedPost;
315
316type FeedReplyRef = { grandparentAuthor?: ProfileViewBasic | null; parent: FeedReplyNode; root: FeedReplyNode };
317
318type FeedReasonRepost = {
319 $type: "app.bsky.feed.defs#reasonRepost";
320 by: ProfileViewBasic;
321 cid?: string | null;
322 indexedAt: string;
323 uri?: string | null;
324};
325
326type FeedReasonPin = { $type: "app.bsky.feed.defs#reasonPin" };
327
328export type FeedViewPost = {
329 feedContext?: string | null;
330 post: PostView;
331 reason?: FeedReasonPin | FeedReasonRepost | null;
332 reply?: FeedReplyRef | null;
333 reqId?: string | null;
334};
335
336export type FeedResponse = { cursor?: string | null; feed: FeedViewPost[] };
337
338export type ThreadViewPost = {
339 $type: "app.bsky.feed.defs#threadViewPost";
340 parent?: ThreadNode | null;
341 post: PostView;
342 replies?: ThreadNode[] | null;
343};
344
345export type ThreadNode = ThreadViewPost | NotFoundPost | BlockedPost;
346
347export type ThreadResponse = { thread: ThreadNode };
348
349export type NotificationReason =
350 | "like"
351 | "repost"
352 | "follow"
353 | "mention"
354 | "reply"
355 | "quote"
356 | "starterpack-joined"
357 | "verified"
358 | "unverified"
359 | string;
360
361export type NotificationView = {
362 uri: string;
363 cid: string;
364 author: ProfileViewBasic;
365 labels?: ModerationLabel[] | null;
366 reason: NotificationReason;
367 reasonSubject?: string | null;
368 record: Record<string, unknown>;
369 isRead: boolean;
370 indexedAt: string;
371};
372
373export type ListNotificationsResponse = {
374 cursor?: string | null;
375 notifications: NotificationView[];
376 seenAt?: string | null;
377};
378
379export type StrongRefInput = { cid: string; uri: string };
380
381export type ReplyRefInput = { parent: StrongRefInput; root: StrongRefInput };
382
383export type EmbedInput = { type: "record"; record: StrongRefInput };
384
385export type CreateRecordResult = { cid: string; uri: string };
386
387export type AppSettings = {
388 theme: string;
389 timelineRefreshSecs: number;
390 notificationsDesktop: boolean;
391 notificationsBadge: boolean;
392 notificationsSound: boolean;
393 embeddingsEnabled: boolean;
394 constellationUrl: string;
395 spacedustUrl: string;
396 spacedustInstant: boolean;
397 spacedustEnabled: boolean;
398 globalShortcut: string;
399 downloadDirectory: string;
400};
401
402export type CacheSize = { feedsBytes: number; embeddingsBytes: number; ftsBytes: number; totalBytes: number };
403
404export type LogEntry = { timestamp: string | null; level: string; target: string | null; message: string };
405
406export type CacheClearScope = "all" | "feeds" | "embeddings" | "fts";
407
408export type ExportFormat = "json" | "csv";
409
410export type LogLevelFilter = "all" | "info" | "warn" | "error";
411
412export type RefreshInterval = 30 | 60 | 120 | 300 | 0;
413
414export type Theme = "light" | "dark" | "auto";
415
416type MessageViewSender = { did: string };
417
418export type MessageView = {
419 $type?: "chat.bsky.convo.defs#messageView";
420 id: string;
421 text: string;
422 sender: MessageViewSender;
423 sentAt: string;
424 rev: string;
425};
426
427export type DeletedMessageView = {
428 $type?: "chat.bsky.convo.defs#deletedMessageView";
429 id: string;
430 rev: string;
431 sender: MessageViewSender;
432 sentAt: string;
433};
434
435type ConvoLastMessage = MessageView | DeletedMessageView;
436
437export type ConvoView = {
438 id: string;
439 members: ProfileViewBasic[];
440 lastMessage?: ConvoLastMessage | null;
441 unreadCount: number;
442 muted: boolean;
443 rev: string;
444 status?: string | null;
445};
446
447export type ListConvosResponse = { convos: ConvoView[]; cursor?: string | null };
448
449export type GetConvoForMembersResponse = { convo: ConvoView };
450
451export type GetMessagesResponse = { messages: Array<MessageView | DeletedMessageView>; cursor?: string | null };
452
453export type Draft = {
454 id: string;
455 accountDid: string;
456 text: string;
457 replyParentUri: string | null;
458 replyParentCid: string | null;
459 replyRootUri: string | null;
460 replyRootCid: string | null;
461 quoteUri: string | null;
462 quoteCid: string | null;
463 title: string | null;
464 createdAt: string;
465 updatedAt: string;
466};
467
468export type DraftInput = {
469 id?: string | null;
470 text: string;
471 replyParentUri?: string | null;
472 replyParentCid?: string | null;
473 replyRootUri?: string | null;
474 replyRootCid?: string | null;
475 quoteUri?: string | null;
476 quoteCid?: string | null;
477 title?: string | null;
478};