birdclaw 0.8.2 → 0.8.3
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 +16 -0
- package/package.json +2 -1
- package/src/cli/command-context.ts +17 -0
- package/src/cli/register-analysis.ts +500 -0
- package/src/cli/register-compose.ts +40 -0
- package/src/cli/register-graph.ts +132 -0
- package/src/cli/register-inbox.ts +41 -0
- package/src/cli/register-storage.ts +106 -0
- package/src/cli.ts +30 -750
- package/src/components/AccountSwitcher.tsx +7 -15
- package/src/components/AvatarChip.tsx +1 -1
- package/src/components/AvatarPreload.ts +149 -0
- package/src/components/MarkdownCitations.tsx +680 -0
- package/src/components/MarkdownViewer.tsx +8 -674
- package/src/components/ProfileAnalysisClient.ts +191 -0
- package/src/components/ProfileAnalysisStream.tsx +16 -185
- package/src/components/ProfilePreview.tsx +2 -0
- package/src/components/links-controller.ts +162 -0
- package/src/components/links-model.ts +198 -0
- package/src/components/network-map-controller.ts +84 -0
- package/src/components/network-map-model.ts +255 -0
- package/src/components/useTimelineRouteData.ts +105 -235
- package/src/lib/analysis-runtime.ts +238 -0
- package/src/lib/api-client.ts +16 -215
- package/src/lib/api-contracts.ts +328 -0
- package/src/lib/archive-import-plan.ts +102 -0
- package/src/lib/archive-import.ts +170 -239
- package/src/lib/authored-live.ts +75 -120
- package/src/lib/backup.ts +335 -424
- package/src/lib/blocks-write.ts +30 -26
- package/src/lib/blocks.ts +18 -20
- package/src/lib/database-metrics.ts +88 -0
- package/src/lib/database-migrations.ts +34 -0
- package/src/lib/database-schema.ts +312 -0
- package/src/lib/database-writer.ts +69 -0
- package/src/lib/db.ts +84 -330
- package/src/lib/dm-read-model.ts +533 -0
- package/src/lib/dms-live.ts +34 -97
- package/src/lib/follow-graph.ts +17 -27
- package/src/lib/import-repository.ts +138 -0
- package/src/lib/inbox.ts +2 -1
- package/src/lib/live-sync-engine.ts +209 -0
- package/src/lib/live-transport-gateway.ts +128 -0
- package/src/lib/mention-threads-live.ts +90 -177
- package/src/lib/mentions-export.ts +1 -1
- package/src/lib/mentions-live.ts +57 -181
- package/src/lib/moderation-target.ts +15 -4
- package/src/lib/moderation-write.ts +1 -1
- package/src/lib/mutes-write.ts +30 -26
- package/src/lib/openai-response-runtime.ts +251 -0
- package/src/lib/paginated-sync.ts +93 -0
- package/src/lib/period-digest.ts +116 -304
- package/src/lib/profile-analysis.ts +36 -110
- package/src/lib/queries.ts +6 -2381
- package/src/lib/query-actions.ts +437 -0
- package/src/lib/query-client.tsx +47 -0
- package/src/lib/query-read-model-shared.ts +52 -0
- package/src/lib/query-read-models.ts +5 -0
- package/src/lib/query-resource.ts +41 -0
- package/src/lib/query-status.ts +164 -0
- package/src/lib/research.ts +1 -1
- package/src/lib/runtime-services.ts +20 -0
- package/src/lib/search-discussion.ts +75 -279
- package/src/lib/server-runtime-services.ts +30 -0
- package/src/lib/sqlite.ts +48 -12
- package/src/lib/streaming-ingestion.ts +240 -0
- package/src/lib/sync-cache.ts +6 -1
- package/src/lib/sync-plan.ts +175 -0
- package/src/lib/timeline-collections-live.ts +83 -257
- package/src/lib/timeline-live.ts +86 -236
- package/src/lib/timeline-read-model.ts +1191 -0
- package/src/lib/tweet-repository.ts +156 -0
- package/src/lib/tweet-search-live.ts +63 -167
- package/src/lib/web-sync.ts +67 -50
- package/src/lib/whois.ts +2 -1
- package/src/routes/__root.tsx +11 -8
- package/src/routes/api/action.tsx +1 -1
- package/src/routes/api/conversation.tsx +1 -1
- package/src/routes/api/query.tsx +32 -26
- package/src/routes/api/status.tsx +6 -4
- package/src/routes/api/sync.tsx +5 -2
- package/src/routes/blocks.tsx +97 -131
- package/src/routes/data-sources.tsx +17 -25
- package/src/routes/dms.tsx +167 -184
- package/src/routes/inbox.tsx +63 -57
- package/src/routes/links.tsx +31 -394
- package/src/routes/network-map.tsx +41 -344
- package/src/routes/rate-limits.tsx +17 -21
- package/src/lib/client-cache.ts +0 -109
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import {
|
|
3
|
+
getAuthenticatedBirdAccountEffect,
|
|
4
|
+
listBookmarkedTweetsViaBirdEffect,
|
|
5
|
+
listDirectMessagesViaBirdEffect,
|
|
6
|
+
listFollowUsersViaBirdEffect,
|
|
7
|
+
listHomeTimelineViaBirdEffect,
|
|
8
|
+
listLikedTweetsViaBirdEffect,
|
|
9
|
+
listMentionsViaBirdEffect,
|
|
10
|
+
listThreadViaBirdEffect,
|
|
11
|
+
searchTweetsViaBirdEffect,
|
|
12
|
+
} from "./bird";
|
|
13
|
+
import {
|
|
14
|
+
getTransportStatus,
|
|
15
|
+
getTweetByIdEffect,
|
|
16
|
+
listBookmarkedTweetsViaXurl,
|
|
17
|
+
listDirectMessageEventsViaXurlEffect,
|
|
18
|
+
listFollowUsersViaXurl,
|
|
19
|
+
listHomeTimelineViaXurlEffect,
|
|
20
|
+
listLikedTweetsViaXurl,
|
|
21
|
+
listMentionsViaXurl,
|
|
22
|
+
listUserTweets,
|
|
23
|
+
lookupAuthenticatedOAuth2UserEffect,
|
|
24
|
+
lookupAuthenticatedUser,
|
|
25
|
+
lookupUsersByHandles,
|
|
26
|
+
searchRecentByConversationIdEffect,
|
|
27
|
+
searchRecentTweetsEffect,
|
|
28
|
+
} from "./xurl";
|
|
29
|
+
|
|
30
|
+
export interface BirdReadTransport {
|
|
31
|
+
getAuthenticatedAccount: typeof getAuthenticatedBirdAccountEffect;
|
|
32
|
+
listBookmarks: typeof listBookmarkedTweetsViaBirdEffect;
|
|
33
|
+
listDirectMessages: typeof listDirectMessagesViaBirdEffect;
|
|
34
|
+
listFollowUsers: typeof listFollowUsersViaBirdEffect;
|
|
35
|
+
listHomeTimeline: typeof listHomeTimelineViaBirdEffect;
|
|
36
|
+
listLikes: typeof listLikedTweetsViaBirdEffect;
|
|
37
|
+
listMentions: typeof listMentionsViaBirdEffect;
|
|
38
|
+
listThread: typeof listThreadViaBirdEffect;
|
|
39
|
+
searchTweets: typeof searchTweetsViaBirdEffect;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface XurlReadTransport {
|
|
43
|
+
getTransportStatus(
|
|
44
|
+
...args: Parameters<typeof getTransportStatus>
|
|
45
|
+
): Effect.Effect<Awaited<ReturnType<typeof getTransportStatus>>, Error>;
|
|
46
|
+
getTweetById: typeof getTweetByIdEffect;
|
|
47
|
+
listBookmarks(
|
|
48
|
+
...args: Parameters<typeof listBookmarkedTweetsViaXurl>
|
|
49
|
+
): Effect.Effect<
|
|
50
|
+
Awaited<ReturnType<typeof listBookmarkedTweetsViaXurl>>,
|
|
51
|
+
Error
|
|
52
|
+
>;
|
|
53
|
+
listDirectMessages: typeof listDirectMessageEventsViaXurlEffect;
|
|
54
|
+
listFollowUsers(
|
|
55
|
+
...args: Parameters<typeof listFollowUsersViaXurl>
|
|
56
|
+
): Effect.Effect<Awaited<ReturnType<typeof listFollowUsersViaXurl>>, Error>;
|
|
57
|
+
listHomeTimeline: typeof listHomeTimelineViaXurlEffect;
|
|
58
|
+
listLikes(
|
|
59
|
+
...args: Parameters<typeof listLikedTweetsViaXurl>
|
|
60
|
+
): Effect.Effect<Awaited<ReturnType<typeof listLikedTweetsViaXurl>>, Error>;
|
|
61
|
+
listMentions(
|
|
62
|
+
...args: Parameters<typeof listMentionsViaXurl>
|
|
63
|
+
): Effect.Effect<Awaited<ReturnType<typeof listMentionsViaXurl>>, Error>;
|
|
64
|
+
listUserTweets(
|
|
65
|
+
...args: Parameters<typeof listUserTweets>
|
|
66
|
+
): Effect.Effect<Awaited<ReturnType<typeof listUserTweets>>, Error>;
|
|
67
|
+
lookupAuthenticatedOAuth2User: typeof lookupAuthenticatedOAuth2UserEffect;
|
|
68
|
+
lookupAuthenticatedUser(
|
|
69
|
+
...args: Parameters<typeof lookupAuthenticatedUser>
|
|
70
|
+
): Effect.Effect<Awaited<ReturnType<typeof lookupAuthenticatedUser>>, Error>;
|
|
71
|
+
lookupUsersByHandles(
|
|
72
|
+
...args: Parameters<typeof lookupUsersByHandles>
|
|
73
|
+
): Effect.Effect<Awaited<ReturnType<typeof lookupUsersByHandles>>, Error>;
|
|
74
|
+
searchConversation: typeof searchRecentByConversationIdEffect;
|
|
75
|
+
searchRecentTweets: typeof searchRecentTweetsEffect;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface LiveTransportGateway {
|
|
79
|
+
bird: BirdReadTransport;
|
|
80
|
+
xurl: XurlReadTransport;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function fromPromise<T>(run: () => PromiseLike<T>): Effect.Effect<T, Error> {
|
|
84
|
+
return Effect.tryPromise({
|
|
85
|
+
try: run,
|
|
86
|
+
catch: (error) =>
|
|
87
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const liveTransportGateway: LiveTransportGateway = {
|
|
92
|
+
bird: {
|
|
93
|
+
getAuthenticatedAccount: () => getAuthenticatedBirdAccountEffect(),
|
|
94
|
+
listBookmarks: (options) => listBookmarkedTweetsViaBirdEffect(options),
|
|
95
|
+
listDirectMessages: (options) => listDirectMessagesViaBirdEffect(options),
|
|
96
|
+
listFollowUsers: (options) => listFollowUsersViaBirdEffect(options),
|
|
97
|
+
listHomeTimeline: (options) => listHomeTimelineViaBirdEffect(options),
|
|
98
|
+
listLikes: (options) => listLikedTweetsViaBirdEffect(options),
|
|
99
|
+
listMentions: (options) => listMentionsViaBirdEffect(options),
|
|
100
|
+
listThread: (options) => listThreadViaBirdEffect(options),
|
|
101
|
+
searchTweets: (query, options) => searchTweetsViaBirdEffect(query, options),
|
|
102
|
+
},
|
|
103
|
+
xurl: {
|
|
104
|
+
getTransportStatus: (...args) =>
|
|
105
|
+
fromPromise(() => getTransportStatus(...args)),
|
|
106
|
+
getTweetById: (id, options) => getTweetByIdEffect(id, options),
|
|
107
|
+
listBookmarks: (...args) =>
|
|
108
|
+
fromPromise(() => listBookmarkedTweetsViaXurl(...args)),
|
|
109
|
+
listDirectMessages: (options) =>
|
|
110
|
+
listDirectMessageEventsViaXurlEffect(options),
|
|
111
|
+
listFollowUsers: (...args) =>
|
|
112
|
+
fromPromise(() => listFollowUsersViaXurl(...args)),
|
|
113
|
+
listHomeTimeline: (options) => listHomeTimelineViaXurlEffect(options),
|
|
114
|
+
listLikes: (...args) => fromPromise(() => listLikedTweetsViaXurl(...args)),
|
|
115
|
+
listMentions: (...args) => fromPromise(() => listMentionsViaXurl(...args)),
|
|
116
|
+
listUserTweets: (...args) => fromPromise(() => listUserTweets(...args)),
|
|
117
|
+
lookupAuthenticatedOAuth2User: (username) =>
|
|
118
|
+
lookupAuthenticatedOAuth2UserEffect(username),
|
|
119
|
+
lookupAuthenticatedUser: (...args) =>
|
|
120
|
+
fromPromise(() => lookupAuthenticatedUser(...args)),
|
|
121
|
+
lookupUsersByHandles: (...args) =>
|
|
122
|
+
fromPromise(() => lookupUsersByHandles(...args)),
|
|
123
|
+
searchConversation: (conversationId, options) =>
|
|
124
|
+
searchRecentByConversationIdEffect(conversationId, options),
|
|
125
|
+
searchRecentTweets: (query, options) =>
|
|
126
|
+
searchRecentTweetsEffect(query, options),
|
|
127
|
+
},
|
|
128
|
+
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Database } from "./sqlite";
|
|
2
2
|
import { Effect } from "effect";
|
|
3
|
-
import {
|
|
3
|
+
import { databaseWriteEffect } from "./database-writer";
|
|
4
4
|
import { getNativeDb } from "./db";
|
|
5
5
|
import { runEffectPromise } from "./effect-runtime";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { liveTransportGateway } from "./live-transport-gateway";
|
|
7
|
+
import { resolveLiveSyncAccount } from "./live-sync-engine";
|
|
8
|
+
import { runSyncPlanEffect } from "./sync-plan";
|
|
8
9
|
import type {
|
|
9
10
|
XurlMentionData,
|
|
10
11
|
XurlMentionsResponse,
|
|
@@ -12,9 +13,7 @@ import type {
|
|
|
12
13
|
XurlMediaItem,
|
|
13
14
|
XurlTweetsResponse,
|
|
14
15
|
} from "./types";
|
|
15
|
-
import {
|
|
16
|
-
import { ensureStubProfileForXUser, upsertProfileFromXUser } from "./x-profile";
|
|
17
|
-
import { getTweetByIdEffect, searchRecentByConversationIdEffect } from "./xurl";
|
|
16
|
+
import { ingestTweetPayload } from "./tweet-repository";
|
|
18
17
|
|
|
19
18
|
const DEFAULT_LIMIT = 30;
|
|
20
19
|
const DEFAULT_DELAY_MS = 1500;
|
|
@@ -107,40 +106,6 @@ function getRemainingThreadTimeoutMs(
|
|
|
107
106
|
}
|
|
108
107
|
return remainingMs;
|
|
109
108
|
}
|
|
110
|
-
function replaceTweetFts(db: Database, tweetId: string, text: string) {
|
|
111
|
-
db.prepare("delete from tweets_fts where tweet_id = ?").run(tweetId);
|
|
112
|
-
db.prepare("insert into tweets_fts (tweet_id, text) values (?, ?)").run(
|
|
113
|
-
tweetId,
|
|
114
|
-
text,
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function resolveAccount(db: Database, accountId?: string) {
|
|
119
|
-
const row = accountId
|
|
120
|
-
? (db
|
|
121
|
-
.prepare("select id, handle from accounts where id = ?")
|
|
122
|
-
.get(accountId) as { id: string; handle: string } | undefined)
|
|
123
|
-
: (db
|
|
124
|
-
.prepare(
|
|
125
|
-
`
|
|
126
|
-
select id, handle
|
|
127
|
-
from accounts
|
|
128
|
-
order by is_default desc, created_at asc
|
|
129
|
-
limit 1
|
|
130
|
-
`,
|
|
131
|
-
)
|
|
132
|
-
.get() as { id: string; handle: string } | undefined);
|
|
133
|
-
|
|
134
|
-
if (!row) {
|
|
135
|
-
throw new Error(`Unknown account: ${accountId ?? "default"}`);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
accountId: row.id,
|
|
140
|
-
handle: row.handle.replace(/^@/, "").toLowerCase(),
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
109
|
function getReplyToId(tweet: XurlMentionData) {
|
|
145
110
|
return tweet.referenced_tweets?.find((entry) => entry.type === "replied_to")
|
|
146
111
|
?.id;
|
|
@@ -354,84 +319,32 @@ function mergeMentionThreadIntoLocalStore({
|
|
|
354
319
|
const usersById = new Map(
|
|
355
320
|
(payload.includes?.users ?? []).map((user) => [user.id, user]),
|
|
356
321
|
);
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
bookmarked = tweets.bookmarked,
|
|
384
|
-
liked = tweets.liked
|
|
385
|
-
`,
|
|
386
|
-
);
|
|
387
|
-
|
|
388
|
-
db.transaction(() => {
|
|
389
|
-
const seenAt = new Date().toISOString();
|
|
390
|
-
for (const tweet of payload.data) {
|
|
391
|
-
const author =
|
|
392
|
-
usersById.get(tweet.author_id) ??
|
|
393
|
-
({
|
|
394
|
-
id: tweet.author_id,
|
|
395
|
-
username: `user_${tweet.author_id}`,
|
|
396
|
-
name: `user_${tweet.author_id}`,
|
|
397
|
-
} as const);
|
|
398
|
-
const profile = usersById.has(tweet.author_id)
|
|
399
|
-
? upsertProfileFromXUser(db, author)
|
|
400
|
-
: ensureStubProfileForXUser(db, tweet.author_id);
|
|
401
|
-
const handle = author.username.toLowerCase();
|
|
402
|
-
const kind = mentionIds.has(tweet.id)
|
|
403
|
-
? "mention"
|
|
404
|
-
: handle === accountHandle
|
|
405
|
-
? "home"
|
|
406
|
-
: "thread";
|
|
407
|
-
const replyToId = getReplyToId(tweet);
|
|
408
|
-
upsertTweet.run(
|
|
409
|
-
tweet.id,
|
|
410
|
-
accountId,
|
|
411
|
-
profile.profile.id,
|
|
412
|
-
kind,
|
|
413
|
-
tweet.text,
|
|
414
|
-
tweet.created_at,
|
|
415
|
-
replyToId ? 1 : 0,
|
|
416
|
-
replyToId ?? null,
|
|
417
|
-
Number(tweet.public_metrics?.like_count ?? 0),
|
|
418
|
-
countTweetMedia(tweet),
|
|
419
|
-
JSON.stringify(tweetEntitiesFromXurl(tweet.entities)),
|
|
420
|
-
buildMediaJsonFromIncludes(tweet, payload.includes?.media),
|
|
421
|
-
);
|
|
422
|
-
if (writeThreadContextEdges) {
|
|
423
|
-
upsertTweetAccountEdge(db, {
|
|
424
|
-
accountId,
|
|
425
|
-
tweetId: tweet.id,
|
|
426
|
-
kind: "thread_context",
|
|
427
|
-
source,
|
|
428
|
-
seenAt,
|
|
429
|
-
rawJson: JSON.stringify(tweet),
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
replaceTweetFts(db, tweet.id, tweet.text);
|
|
433
|
-
}
|
|
434
|
-
})();
|
|
322
|
+
const groups = new Map<"mention" | "home" | "thread", typeof payload.data>([
|
|
323
|
+
["mention", []],
|
|
324
|
+
["home", []],
|
|
325
|
+
["thread", []],
|
|
326
|
+
]);
|
|
327
|
+
for (const tweet of payload.data) {
|
|
328
|
+
const handle = usersById.get(tweet.author_id)?.username.toLowerCase();
|
|
329
|
+
const kind = mentionIds.has(tweet.id)
|
|
330
|
+
? "mention"
|
|
331
|
+
: handle === accountHandle
|
|
332
|
+
? "home"
|
|
333
|
+
: "thread";
|
|
334
|
+
groups.get(kind)?.push(tweet);
|
|
335
|
+
}
|
|
336
|
+
for (const [kind, data] of groups) {
|
|
337
|
+
if (data.length === 0) continue;
|
|
338
|
+
ingestTweetPayload(db, {
|
|
339
|
+
accountId,
|
|
340
|
+
payload: { ...payload, data },
|
|
341
|
+
kind,
|
|
342
|
+
edgeKind: writeThreadContextEdges ? "thread_context" : undefined,
|
|
343
|
+
markRepliesAsReplied: true,
|
|
344
|
+
replaceSecondaryKind: true,
|
|
345
|
+
source,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
435
348
|
}
|
|
436
349
|
|
|
437
350
|
function fetchConversationViaRecentSearchEffect({
|
|
@@ -448,39 +361,29 @@ function fetchConversationViaRecentSearchEffect({
|
|
|
448
361
|
deadlineMs: number;
|
|
449
362
|
}) {
|
|
450
363
|
return Effect.gen(function* () {
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
paginationToken: nextToken,
|
|
461
|
-
timeoutMs: yield* trySync(() =>
|
|
462
|
-
getRemainingThreadTimeoutMs(deadlineMs, timeoutMs),
|
|
364
|
+
const result = yield* runSyncPlanEffect({
|
|
365
|
+
fetchPage: ({ cursor }) =>
|
|
366
|
+
trySync(() => getRemainingThreadTimeoutMs(deadlineMs, timeoutMs)).pipe(
|
|
367
|
+
Effect.flatMap((remainingTimeoutMs) =>
|
|
368
|
+
liveTransportGateway.xurl.searchConversation(conversationId, {
|
|
369
|
+
maxResults: MAX_XURL_SEARCH_RESULTS,
|
|
370
|
+
paginationToken: cursor,
|
|
371
|
+
timeoutMs: remainingTimeoutMs,
|
|
372
|
+
}),
|
|
463
373
|
),
|
|
464
|
-
|
|
465
|
-
)
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
} while (
|
|
473
|
-
(all || maxPages !== undefined) &&
|
|
474
|
-
nextToken &&
|
|
475
|
-
(maxPages === undefined || pageCount < maxPages)
|
|
476
|
-
);
|
|
477
|
-
|
|
478
|
-
const payload = mergePayloads(pages);
|
|
374
|
+
),
|
|
375
|
+
getNextCursor: (page) =>
|
|
376
|
+
typeof page.meta?.next_token === "string"
|
|
377
|
+
? page.meta.next_token
|
|
378
|
+
: undefined,
|
|
379
|
+
maxPages: all || maxPages !== undefined ? maxPages : 1,
|
|
380
|
+
});
|
|
381
|
+
const payload = mergePayloads(result.pages);
|
|
479
382
|
const paginationRequested = all || maxPages !== undefined;
|
|
480
383
|
return {
|
|
481
384
|
payload,
|
|
482
|
-
pages:
|
|
483
|
-
truncated: paginationRequested && Boolean(
|
|
385
|
+
pages: result.pages.length,
|
|
386
|
+
truncated: paginationRequested && Boolean(result.nextCursor),
|
|
484
387
|
generalReadTweets: payload.data.length,
|
|
485
388
|
};
|
|
486
389
|
});
|
|
@@ -512,11 +415,14 @@ function fetchParentChainViaXurlEffect({
|
|
|
512
415
|
let shouldUseRawAnchor = Boolean(rawAnchorPayload);
|
|
513
416
|
|
|
514
417
|
if (!nextParentId) {
|
|
515
|
-
const anchorPayload = yield*
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
418
|
+
const anchorPayload = yield* liveTransportGateway.xurl.getTweetById(
|
|
419
|
+
mention.id,
|
|
420
|
+
{
|
|
421
|
+
timeoutMs: yield* trySync(() =>
|
|
422
|
+
getRemainingThreadTimeoutMs(deadlineMs, timeoutMs),
|
|
423
|
+
),
|
|
424
|
+
},
|
|
425
|
+
);
|
|
520
426
|
pages.push(anchorPayload);
|
|
521
427
|
generalReadTweets += anchorPayload.data.length;
|
|
522
428
|
const anchorTweet = anchorPayload.data[0];
|
|
@@ -548,11 +454,14 @@ function fetchParentChainViaXurlEffect({
|
|
|
548
454
|
}
|
|
549
455
|
|
|
550
456
|
fallbackDepth += 1;
|
|
551
|
-
const parentPayload = yield*
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
457
|
+
const parentPayload = yield* liveTransportGateway.xurl.getTweetById(
|
|
458
|
+
nextParentId,
|
|
459
|
+
{
|
|
460
|
+
timeoutMs: yield* trySync(() =>
|
|
461
|
+
getRemainingThreadTimeoutMs(deadlineMs, timeoutMs),
|
|
462
|
+
),
|
|
463
|
+
},
|
|
464
|
+
);
|
|
556
465
|
pages.push(parentPayload);
|
|
557
466
|
generalReadTweets += parentPayload.data.length;
|
|
558
467
|
const parentTweet = parentPayload.data[0];
|
|
@@ -743,7 +652,9 @@ export function syncMentionThreadsEffect({
|
|
|
743
652
|
parseNonNegativeInteger(maxPages, "--max-pages"),
|
|
744
653
|
);
|
|
745
654
|
const db = yield* trySync(() => getNativeDb());
|
|
746
|
-
const resolvedAccount = yield* trySync(() =>
|
|
655
|
+
const resolvedAccount = yield* trySync(() =>
|
|
656
|
+
resolveLiveSyncAccount(db, account),
|
|
657
|
+
);
|
|
747
658
|
const mentions = yield* trySync(() =>
|
|
748
659
|
tweetIds
|
|
749
660
|
? listMentionsByIds(
|
|
@@ -779,22 +690,24 @@ export function syncMentionThreadsEffect({
|
|
|
779
690
|
}
|
|
780
691
|
const fetchEffect: Effect.Effect<ThreadFetchResult, unknown, never> =
|
|
781
692
|
parsedMode === "bird"
|
|
782
|
-
?
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
payload
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
693
|
+
? liveTransportGateway.bird
|
|
694
|
+
.listThread({
|
|
695
|
+
tweetId: mention.id,
|
|
696
|
+
all,
|
|
697
|
+
maxPages: parsedMaxPages,
|
|
698
|
+
timeoutMs: parsedTimeoutMs,
|
|
699
|
+
})
|
|
700
|
+
.pipe(
|
|
701
|
+
Effect.map((payload) => ({
|
|
702
|
+
strategy: "bird" as const,
|
|
703
|
+
payload,
|
|
704
|
+
pages: undefined,
|
|
705
|
+
fallbackDepth: undefined,
|
|
706
|
+
generalReadTweets: 0,
|
|
707
|
+
truncated: undefined,
|
|
708
|
+
warnings: [] as string[],
|
|
709
|
+
})),
|
|
710
|
+
)
|
|
798
711
|
: fetchThreadContextViaXurlEffect({
|
|
799
712
|
mention,
|
|
800
713
|
all,
|
|
@@ -804,11 +717,11 @@ export function syncMentionThreadsEffect({
|
|
|
804
717
|
});
|
|
805
718
|
const fetched = yield* fetchEffect.pipe(
|
|
806
719
|
Effect.flatMap((fetchResult) =>
|
|
807
|
-
|
|
720
|
+
databaseWriteEffect((writeDb) =>
|
|
808
721
|
mergeMentionThreadIntoLocalStore({
|
|
809
|
-
db,
|
|
722
|
+
db: writeDb,
|
|
810
723
|
accountId: resolvedAccount.accountId,
|
|
811
|
-
accountHandle: resolvedAccount.
|
|
724
|
+
accountHandle: resolvedAccount.username.toLowerCase(),
|
|
812
725
|
mentionIds: mentionIdSet,
|
|
813
726
|
payload: fetchResult.payload,
|
|
814
727
|
source: parsedMode,
|