birdclaw 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -1
- package/README.md +108 -7
- package/package.json +24 -23
- package/playwright.config.ts +1 -0
- package/public/favicon.ico +0 -0
- package/public/logo192.png +0 -0
- package/public/logo512.png +0 -0
- package/public/manifest.json +2 -2
- package/src/cli.ts +563 -18
- package/src/components/AppNav.tsx +66 -29
- package/src/components/AvatarChip.tsx +10 -5
- package/src/components/ConversationThread.tsx +125 -0
- package/src/components/DmWorkspace.tsx +96 -98
- package/src/components/EmbeddedTweetCard.tsx +20 -14
- package/src/components/InboxCard.tsx +92 -90
- package/src/components/LinkPreviewCard.tsx +270 -0
- package/src/components/ProfilePreview.tsx +8 -3
- package/src/components/SavedTimelineView.tsx +48 -38
- package/src/components/TimelineCard.tsx +228 -84
- package/src/components/TweetRichText.tsx +6 -2
- package/src/lib/archive-import.ts +1567 -65
- package/src/lib/authored-live.ts +1074 -0
- package/src/lib/backup.ts +318 -14
- package/src/lib/bird-actions.ts +1 -10
- package/src/lib/bird-command.ts +57 -0
- package/src/lib/bird.ts +89 -5
- package/src/lib/config.ts +1 -1
- package/src/lib/db.ts +282 -4
- package/src/lib/follow-graph.ts +1053 -0
- package/src/lib/link-index.ts +629 -0
- package/src/lib/link-insights.ts +834 -0
- package/src/lib/link-preview-metadata.ts +334 -0
- package/src/lib/media-fetch.ts +787 -0
- package/src/lib/media-includes.ts +165 -0
- package/src/lib/mention-threads-live.ts +535 -43
- package/src/lib/mentions-live.ts +623 -19
- package/src/lib/moderation-target.ts +6 -0
- package/src/lib/profile-hydration.ts +1 -1
- package/src/lib/profile-resolver.ts +115 -1
- package/src/lib/queries.ts +233 -7
- package/src/lib/seed.ts +127 -8
- package/src/lib/timeline-collections-live.ts +145 -22
- package/src/lib/timeline-live.ts +10 -15
- package/src/lib/tweet-account-edges.ts +9 -2
- package/src/lib/tweet-render.ts +97 -0
- package/src/lib/types.ts +219 -2
- package/src/lib/ui.ts +375 -147
- package/src/lib/url-expansion-store.ts +110 -0
- package/src/lib/url-expansion.ts +33 -8
- package/src/lib/x-profile.ts +7 -2
- package/src/lib/xurl.ts +296 -12
- package/src/routeTree.gen.ts +105 -0
- package/src/routes/__root.tsx +7 -3
- package/src/routes/api/conversation.tsx +34 -0
- package/src/routes/api/link-insights.tsx +79 -0
- package/src/routes/api/link-preview.tsx +43 -0
- package/src/routes/api/profile-hydrate.tsx +51 -0
- package/src/routes/blocks.tsx +111 -86
- package/src/routes/dms.tsx +90 -78
- package/src/routes/inbox.tsx +98 -86
- package/src/routes/index.tsx +63 -50
- package/src/routes/links.tsx +883 -0
- package/src/routes/mentions.tsx +63 -50
- package/src/styles.css +106 -43
package/src/lib/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ResourceKind = "home" | "mentions" | "dms";
|
|
1
|
+
export type ResourceKind = "home" | "mentions" | "authored" | "dms";
|
|
2
2
|
export type InboxKind = "mixed" | "mentions" | "dms";
|
|
3
3
|
|
|
4
4
|
export type ReplyFilter = "all" | "replied" | "unreplied";
|
|
@@ -88,6 +88,8 @@ export interface TweetUrlEntity {
|
|
|
88
88
|
end: number;
|
|
89
89
|
title?: string;
|
|
90
90
|
description?: string | null;
|
|
91
|
+
imageUrl?: string | null;
|
|
92
|
+
siteName?: string | null;
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
export interface TweetHashtagEntity {
|
|
@@ -109,17 +111,29 @@ export interface TweetMediaItem {
|
|
|
109
111
|
width?: number;
|
|
110
112
|
height?: number;
|
|
111
113
|
thumbnailUrl?: string;
|
|
114
|
+
durationMs?: number;
|
|
115
|
+
variants?: Array<{
|
|
116
|
+
url: string;
|
|
117
|
+
contentType?: string;
|
|
118
|
+
bitRate?: number;
|
|
119
|
+
}>;
|
|
112
120
|
}
|
|
113
121
|
|
|
114
122
|
export interface EmbeddedTweet {
|
|
115
123
|
id: string;
|
|
116
124
|
text: string;
|
|
117
125
|
createdAt: string;
|
|
126
|
+
replyToId?: string | null;
|
|
118
127
|
author: ProfileRecord;
|
|
119
128
|
entities: TweetEntities;
|
|
120
129
|
media: TweetMediaItem[];
|
|
121
130
|
}
|
|
122
131
|
|
|
132
|
+
export interface TweetConversationResponse {
|
|
133
|
+
anchorId: string;
|
|
134
|
+
items: EmbeddedTweet[];
|
|
135
|
+
}
|
|
136
|
+
|
|
123
137
|
export interface BlockItem {
|
|
124
138
|
accountId: string;
|
|
125
139
|
accountHandle: string;
|
|
@@ -143,10 +157,11 @@ export interface TimelineItem {
|
|
|
143
157
|
id: string;
|
|
144
158
|
accountId: string;
|
|
145
159
|
accountHandle: string;
|
|
146
|
-
kind: "home" | "mention" | "like" | "bookmark";
|
|
160
|
+
kind: "home" | "mention" | "authored" | "like" | "bookmark";
|
|
147
161
|
text: string;
|
|
148
162
|
searchSnippet?: string;
|
|
149
163
|
createdAt: string;
|
|
164
|
+
replyToId?: string | null;
|
|
150
165
|
isReplied: boolean;
|
|
151
166
|
likeCount: number;
|
|
152
167
|
mediaCount: number;
|
|
@@ -183,6 +198,122 @@ export interface UrlExpansionItem {
|
|
|
183
198
|
updatedAt: string;
|
|
184
199
|
}
|
|
185
200
|
|
|
201
|
+
export interface LinkOccurrenceItem {
|
|
202
|
+
sourceKind: "dm" | "tweet";
|
|
203
|
+
sourceId: string;
|
|
204
|
+
sourcePosition: number;
|
|
205
|
+
shortUrl: string;
|
|
206
|
+
accountId?: string | null;
|
|
207
|
+
conversationId?: string | null;
|
|
208
|
+
direction?: string | null;
|
|
209
|
+
createdAt: string;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export interface LinkIndexItem {
|
|
213
|
+
shortUrl: string;
|
|
214
|
+
expandedUrl: string;
|
|
215
|
+
finalUrl: string;
|
|
216
|
+
status: "hit" | "miss" | "error";
|
|
217
|
+
expandedTweetId?: string | null;
|
|
218
|
+
expandedHandle?: string | null;
|
|
219
|
+
title?: string | null;
|
|
220
|
+
description?: string | null;
|
|
221
|
+
imageUrl?: string | null;
|
|
222
|
+
siteName?: string | null;
|
|
223
|
+
error?: string | null;
|
|
224
|
+
source: string;
|
|
225
|
+
updatedAt: string;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export interface LinkSearchItem {
|
|
229
|
+
occurrence: LinkOccurrenceItem;
|
|
230
|
+
expansion: LinkIndexItem;
|
|
231
|
+
sourceText: string;
|
|
232
|
+
sourceAuthor?: ProfileRecord | null;
|
|
233
|
+
participant?: ProfileRecord | null;
|
|
234
|
+
linkedTweet?: TimelineItem | null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export type LinkInsightKind = "links" | "videos";
|
|
238
|
+
export type LinkInsightRange = "today" | "week" | "month" | "year" | "all";
|
|
239
|
+
export type LinkInsightSort = "rank" | "recent" | "comments";
|
|
240
|
+
export type LinkInsightSource = "all" | "tweet" | "dm";
|
|
241
|
+
|
|
242
|
+
export interface LinkInsightMention {
|
|
243
|
+
id: string;
|
|
244
|
+
sourceKind: "dm" | "tweet";
|
|
245
|
+
sourceId: string;
|
|
246
|
+
sourceUrl?: string | null;
|
|
247
|
+
sourceLabel: string;
|
|
248
|
+
shortUrl: string;
|
|
249
|
+
conversationId?: string | null;
|
|
250
|
+
createdAt: string;
|
|
251
|
+
text: string;
|
|
252
|
+
rawText: string;
|
|
253
|
+
commentText: string;
|
|
254
|
+
sharedContentText?: string | null;
|
|
255
|
+
hasComment: boolean;
|
|
256
|
+
isPureShare: boolean;
|
|
257
|
+
timelineTweetId?: string | null;
|
|
258
|
+
contentTweetId?: string | null;
|
|
259
|
+
contentTweetUrl?: string | null;
|
|
260
|
+
contentAuthor?: ProfileRecord | null;
|
|
261
|
+
media: TweetMediaItem[];
|
|
262
|
+
direction?: string | null;
|
|
263
|
+
accountHandle?: string | null;
|
|
264
|
+
sharedBy?: ProfileRecord | null;
|
|
265
|
+
participant?: ProfileRecord | null;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export interface LinkInsightItem {
|
|
269
|
+
id: string;
|
|
270
|
+
kind: LinkInsightKind;
|
|
271
|
+
url: string;
|
|
272
|
+
canonicalKey: string;
|
|
273
|
+
displayUrl: string;
|
|
274
|
+
host: string;
|
|
275
|
+
title?: string | null;
|
|
276
|
+
description?: string | null;
|
|
277
|
+
shareCount: number;
|
|
278
|
+
uniqueSharers: number;
|
|
279
|
+
totalInfluence: number;
|
|
280
|
+
mentionCount: number;
|
|
281
|
+
commentCount: number;
|
|
282
|
+
pureShareCount: number;
|
|
283
|
+
hiddenMentionCount: number;
|
|
284
|
+
firstSeenAt: string;
|
|
285
|
+
lastSeenAt: string;
|
|
286
|
+
topSharer?: ProfileRecord | null;
|
|
287
|
+
sharers: ProfileRecord[];
|
|
288
|
+
mentions: LinkInsightMention[];
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export interface LinkInsightQuery {
|
|
292
|
+
kind?: LinkInsightKind;
|
|
293
|
+
range?: LinkInsightRange;
|
|
294
|
+
sort?: LinkInsightSort;
|
|
295
|
+
source?: LinkInsightSource;
|
|
296
|
+
since?: string;
|
|
297
|
+
until?: string;
|
|
298
|
+
limit?: number;
|
|
299
|
+
commentsLimit?: number;
|
|
300
|
+
now?: Date;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export interface LinkInsightResponse {
|
|
304
|
+
kind: LinkInsightKind;
|
|
305
|
+
range: LinkInsightRange;
|
|
306
|
+
sort: LinkInsightSort;
|
|
307
|
+
source: LinkInsightSource;
|
|
308
|
+
since: string | null;
|
|
309
|
+
until: string | null;
|
|
310
|
+
items: LinkInsightItem[];
|
|
311
|
+
stats: {
|
|
312
|
+
occurrences: number;
|
|
313
|
+
groups: number;
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
186
317
|
export interface DmSearchMatchItem {
|
|
187
318
|
message: DmMessageItem;
|
|
188
319
|
before: DmMessageItem[];
|
|
@@ -327,6 +458,8 @@ export interface XurlPublicMetrics {
|
|
|
327
458
|
impression_count?: number;
|
|
328
459
|
followers_count?: number;
|
|
329
460
|
following_count?: number;
|
|
461
|
+
tweet_count?: number;
|
|
462
|
+
listed_count?: number;
|
|
330
463
|
}
|
|
331
464
|
|
|
332
465
|
export interface XurlMentionUser {
|
|
@@ -343,6 +476,7 @@ export interface XurlMentionUser {
|
|
|
343
476
|
affiliation?: Record<string, unknown>;
|
|
344
477
|
public_metrics?: XurlPublicMetrics;
|
|
345
478
|
created_at?: string;
|
|
479
|
+
protected?: boolean;
|
|
346
480
|
}
|
|
347
481
|
|
|
348
482
|
export interface XurlMentionData {
|
|
@@ -351,6 +485,8 @@ export interface XurlMentionData {
|
|
|
351
485
|
text: string;
|
|
352
486
|
created_at: string;
|
|
353
487
|
conversation_id?: string;
|
|
488
|
+
in_reply_to_user_id?: string;
|
|
489
|
+
attachments?: XurlTweetAttachments;
|
|
354
490
|
entities?: Record<string, unknown>;
|
|
355
491
|
referenced_tweets?: XurlReferencedTweet[];
|
|
356
492
|
public_metrics?: XurlPublicMetrics;
|
|
@@ -364,9 +500,12 @@ export interface XurlReferencedTweet {
|
|
|
364
500
|
|
|
365
501
|
export interface XurlUserTweet {
|
|
366
502
|
id: string;
|
|
503
|
+
author_id?: string;
|
|
367
504
|
text: string;
|
|
368
505
|
created_at: string;
|
|
369
506
|
conversation_id?: string;
|
|
507
|
+
attachments?: XurlTweetAttachments;
|
|
508
|
+
entities?: Record<string, unknown>;
|
|
370
509
|
referenced_tweets?: XurlReferencedTweet[];
|
|
371
510
|
public_metrics?: XurlPublicMetrics;
|
|
372
511
|
edit_history_tweet_ids?: string[];
|
|
@@ -378,12 +517,50 @@ export interface XurlTweetData {
|
|
|
378
517
|
text: string;
|
|
379
518
|
created_at: string;
|
|
380
519
|
conversation_id?: string;
|
|
520
|
+
in_reply_to_user_id?: string;
|
|
521
|
+
attachments?: XurlTweetAttachments;
|
|
381
522
|
entities?: Record<string, unknown>;
|
|
382
523
|
referenced_tweets?: XurlReferencedTweet[];
|
|
383
524
|
public_metrics?: XurlPublicMetrics;
|
|
384
525
|
edit_history_tweet_ids?: string[];
|
|
385
526
|
}
|
|
386
527
|
|
|
528
|
+
export interface XurlTweetAttachments {
|
|
529
|
+
media_keys?: string[];
|
|
530
|
+
poll_ids?: string[];
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
export interface XurlMediaItem {
|
|
534
|
+
media_key: string;
|
|
535
|
+
type: "photo" | "video" | "animated_gif" | string;
|
|
536
|
+
url?: string;
|
|
537
|
+
preview_image_url?: string;
|
|
538
|
+
duration_ms?: number;
|
|
539
|
+
width?: number;
|
|
540
|
+
height?: number;
|
|
541
|
+
alt_text?: string;
|
|
542
|
+
public_metrics?: XurlPublicMetrics;
|
|
543
|
+
variants?: Array<{
|
|
544
|
+
url: string;
|
|
545
|
+
content_type: string;
|
|
546
|
+
bit_rate?: number;
|
|
547
|
+
}>;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
export type XurlMedia = XurlMediaItem;
|
|
551
|
+
|
|
552
|
+
export interface XurlTweetIncludes {
|
|
553
|
+
users?: XurlMentionUser[];
|
|
554
|
+
tweets?: XurlTweetData[];
|
|
555
|
+
media?: XurlMedia[];
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
export interface XurlUserTweetsResponse {
|
|
559
|
+
items: XurlUserTweet[];
|
|
560
|
+
nextToken: string | null;
|
|
561
|
+
includes?: XurlTweetIncludes;
|
|
562
|
+
}
|
|
563
|
+
|
|
387
564
|
export interface ProfileReplyItem {
|
|
388
565
|
id: string;
|
|
389
566
|
text: string;
|
|
@@ -413,6 +590,7 @@ export interface XurlMentionsResponse {
|
|
|
413
590
|
data: XurlMentionData[];
|
|
414
591
|
includes?: {
|
|
415
592
|
users?: XurlMentionUser[];
|
|
593
|
+
media?: XurlMediaItem[];
|
|
416
594
|
};
|
|
417
595
|
meta?: Record<string, unknown>;
|
|
418
596
|
}
|
|
@@ -421,6 +599,45 @@ export interface XurlTweetsResponse {
|
|
|
421
599
|
data: XurlTweetData[];
|
|
422
600
|
includes?: {
|
|
423
601
|
users?: XurlMentionUser[];
|
|
602
|
+
media?: XurlMediaItem[];
|
|
424
603
|
};
|
|
425
604
|
meta?: Record<string, unknown>;
|
|
426
605
|
}
|
|
606
|
+
|
|
607
|
+
export type FollowDirection = "followers" | "following";
|
|
608
|
+
|
|
609
|
+
export interface XurlFollowUsersResponse {
|
|
610
|
+
data: XurlMentionUser[];
|
|
611
|
+
meta?: Record<string, unknown>;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
export interface FollowGraphProfile {
|
|
615
|
+
id: string;
|
|
616
|
+
externalUserId: string;
|
|
617
|
+
handle: string;
|
|
618
|
+
displayName: string;
|
|
619
|
+
bio: string;
|
|
620
|
+
followersCount: number;
|
|
621
|
+
publicMetrics: XurlPublicMetrics;
|
|
622
|
+
avatarUrl?: string;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
export type FollowEventKind = "started" | "ended";
|
|
626
|
+
|
|
627
|
+
export interface FollowGraphEvent {
|
|
628
|
+
eventAt: string;
|
|
629
|
+
direction: FollowDirection;
|
|
630
|
+
kind: FollowEventKind;
|
|
631
|
+
snapshotId: string;
|
|
632
|
+
profile: FollowGraphProfile;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
export interface FollowGraphSummary {
|
|
636
|
+
accountId: string;
|
|
637
|
+
followers: number;
|
|
638
|
+
following: number;
|
|
639
|
+
mutuals: number;
|
|
640
|
+
nonMutualFollowing: number;
|
|
641
|
+
lastCompleteSnapshots: Partial<Record<FollowDirection, string>>;
|
|
642
|
+
lastIncompleteSnapshots: Partial<Record<FollowDirection, string>>;
|
|
643
|
+
}
|