birdclaw 0.8.1 → 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 +25 -0
- package/package.json +2 -4
- package/scripts/browser-perf.mjs +27 -0
- 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/ConversationThread.tsx +4 -0
- package/src/components/EmbeddedTweetCard.tsx +4 -0
- package/src/components/FloatingPreview.tsx +382 -0
- package/src/components/MarkdownCitations.tsx +680 -0
- package/src/components/MarkdownViewer.tsx +7 -715
- package/src/components/ProfileAnalysisClient.ts +191 -0
- package/src/components/ProfileAnalysisStream.tsx +16 -185
- package/src/components/ProfilePreview.tsx +41 -81
- package/src/components/TimelineCard.tsx +18 -2
- package/src/components/TweetArticleCard.tsx +66 -0
- package/src/components/TweetRichText.tsx +33 -2
- 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/useDebouncedValue.ts +12 -0
- package/src/components/useTimelineRouteData.ts +142 -170
- package/src/lib/analysis-runtime.ts +238 -0
- package/src/lib/api-client.ts +16 -100
- package/src/lib/api-contracts.ts +328 -0
- package/src/lib/archive-finder.ts +38 -0
- package/src/lib/archive-import-plan.ts +102 -0
- package/src/lib/archive-import.ts +170 -239
- package/src/lib/authored-live.ts +77 -182
- package/src/lib/backup.ts +335 -424
- package/src/lib/bird.ts +32 -1
- 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 +141 -334
- 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 -176
- package/src/lib/mentions-export.ts +1 -1
- package/src/lib/mentions-live.ts +57 -225
- 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 +37 -111
- package/src/lib/queries.ts +6 -2380
- 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 +53 -14
- 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 -256
- package/src/lib/timeline-live.ts +86 -235
- package/src/lib/timeline-read-model.ts +1191 -0
- package/src/lib/tweet-render.ts +78 -0
- package/src/lib/tweet-repository.ts +156 -0
- package/src/lib/tweet-search-live.ts +63 -166
- package/src/lib/types.ts +8 -0
- package/src/lib/ui.ts +1 -1
- package/src/lib/web-sync.ts +67 -50
- package/src/lib/whois.ts +2 -1
- package/src/router.tsx +1 -1
- package/src/routes/__root.tsx +11 -21
- 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 -2
- 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 +168 -167
- package/src/routes/inbox.tsx +63 -57
- package/src/routes/links.tsx +31 -329
- package/src/routes/network-map.tsx +41 -344
- package/src/routes/rate-limits.tsx +17 -21
- package/vite.config.ts +0 -2
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
import type { Database } from "./sqlite";
|
|
2
2
|
import { Effect } from "effect";
|
|
3
|
-
import {
|
|
4
|
-
listBookmarkedTweetsViaBirdEffect,
|
|
5
|
-
listLikedTweetsViaBirdEffect,
|
|
6
|
-
} from "./bird";
|
|
7
3
|
import { getNativeDb } from "./db";
|
|
8
|
-
import { runEffectPromise
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
4
|
+
import { runEffectPromise } from "./effect-runtime";
|
|
5
|
+
import { liveTransportGateway } from "./live-transport-gateway";
|
|
6
|
+
import {
|
|
7
|
+
createLiveTransportAdapter,
|
|
8
|
+
normalizeCacheTtlMs,
|
|
9
|
+
resolveLiveSyncAccount,
|
|
10
|
+
runCachedLiveSyncEffect,
|
|
11
|
+
} from "./live-sync-engine";
|
|
11
12
|
import type {
|
|
12
13
|
XurlMentionData,
|
|
13
14
|
XurlMentionsResponse,
|
|
14
15
|
XurlMediaItem,
|
|
15
16
|
XurlMentionUser,
|
|
16
17
|
} from "./types";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
listBookmarkedTweetsViaXurl,
|
|
20
|
-
listLikedTweetsViaXurl,
|
|
21
|
-
lookupUsersByHandles,
|
|
22
|
-
} from "./xurl";
|
|
18
|
+
import { ingestTweetPayload } from "./tweet-repository";
|
|
23
19
|
|
|
24
20
|
export type TimelineCollectionKind = "likes" | "bookmarks";
|
|
25
21
|
export type TimelineCollectionMode = "auto" | "xurl" | "bird";
|
|
@@ -51,13 +47,6 @@ function trySync<T>(try_: () => T) {
|
|
|
51
47
|
});
|
|
52
48
|
}
|
|
53
49
|
|
|
54
|
-
function parseCacheTtlMs(value?: number) {
|
|
55
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
56
|
-
return DEFAULT_COLLECTION_CACHE_TTL_MS;
|
|
57
|
-
}
|
|
58
|
-
return Math.floor(value);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
50
|
function parseMaxPages(value?: number) {
|
|
62
51
|
if (value === undefined) {
|
|
63
52
|
return null;
|
|
@@ -80,57 +69,6 @@ function assertXurlLimit(limit: number) {
|
|
|
80
69
|
}
|
|
81
70
|
}
|
|
82
71
|
|
|
83
|
-
function resolveAccount(db: Database, accountId?: string) {
|
|
84
|
-
const row = accountId
|
|
85
|
-
? (db
|
|
86
|
-
.prepare(
|
|
87
|
-
"select id, handle, external_user_id from accounts where id = ?",
|
|
88
|
-
)
|
|
89
|
-
.get(accountId) as
|
|
90
|
-
| { id: string; handle: string; external_user_id: string | null }
|
|
91
|
-
| undefined)
|
|
92
|
-
: (db
|
|
93
|
-
.prepare(
|
|
94
|
-
`
|
|
95
|
-
select id, handle, external_user_id
|
|
96
|
-
from accounts
|
|
97
|
-
order by is_default desc, created_at asc
|
|
98
|
-
limit 1
|
|
99
|
-
`,
|
|
100
|
-
)
|
|
101
|
-
.get() as
|
|
102
|
-
| { id: string; handle: string; external_user_id: string | null }
|
|
103
|
-
| undefined);
|
|
104
|
-
|
|
105
|
-
if (!row) {
|
|
106
|
-
throw new Error(`Unknown account: ${accountId ?? "default"}`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return {
|
|
110
|
-
accountId: row.id,
|
|
111
|
-
username: row.handle.replace(/^@/, ""),
|
|
112
|
-
externalUserId:
|
|
113
|
-
typeof row.external_user_id === "string" &&
|
|
114
|
-
row.external_user_id.length > 0
|
|
115
|
-
? row.external_user_id
|
|
116
|
-
: undefined,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function replaceTweetFts(db: Database, tweetId: string, text: string) {
|
|
121
|
-
db.prepare("delete from tweets_fts where tweet_id = ?").run(tweetId);
|
|
122
|
-
db.prepare("insert into tweets_fts (tweet_id, text) values (?, ?)").run(
|
|
123
|
-
tweetId,
|
|
124
|
-
text,
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function getReferencedTweetId(tweet: XurlMentionData, type: string) {
|
|
129
|
-
return (
|
|
130
|
-
tweet.referenced_tweets?.find((item) => item.type === type)?.id ?? null
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
72
|
function mergePayloads(pages: XurlMentionsResponse[]): XurlMentionsResponse {
|
|
135
73
|
const tweets: XurlMentionData[] = [];
|
|
136
74
|
const seenTweetIds = new Set<string>();
|
|
@@ -236,95 +174,16 @@ function mergeTimelineCollectionIntoLocalStore(
|
|
|
236
174
|
payload: XurlMentionsResponse,
|
|
237
175
|
source: "xurl" | "bird",
|
|
238
176
|
) {
|
|
239
|
-
const usersById = new Map(
|
|
240
|
-
(payload.includes?.users ?? []).map((user) => [user.id, user]),
|
|
241
|
-
);
|
|
242
177
|
const tweetKind = kind === "likes" ? "like" : "bookmark";
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
on conflict(id) do update set
|
|
253
|
-
account_id = tweets.account_id,
|
|
254
|
-
author_profile_id = excluded.author_profile_id,
|
|
255
|
-
kind = case
|
|
256
|
-
when tweets.kind in ('authored', 'home', 'mention') then tweets.kind
|
|
257
|
-
else excluded.kind
|
|
258
|
-
end,
|
|
259
|
-
text = excluded.text,
|
|
260
|
-
created_at = excluded.created_at,
|
|
261
|
-
like_count = excluded.like_count,
|
|
262
|
-
media_count = max(tweets.media_count, excluded.media_count),
|
|
263
|
-
entities_json = excluded.entities_json,
|
|
264
|
-
media_json = case
|
|
265
|
-
when excluded.media_json not in ('', '[]', 'null') then excluded.media_json
|
|
266
|
-
else tweets.media_json
|
|
267
|
-
end,
|
|
268
|
-
is_replied = max(tweets.is_replied, excluded.is_replied),
|
|
269
|
-
reply_to_id = coalesce(excluded.reply_to_id, tweets.reply_to_id),
|
|
270
|
-
quoted_tweet_id = coalesce(excluded.quoted_tweet_id, tweets.quoted_tweet_id),
|
|
271
|
-
bookmarked = tweets.bookmarked,
|
|
272
|
-
liked = tweets.liked
|
|
273
|
-
`,
|
|
274
|
-
);
|
|
275
|
-
const upsertCollection = db.prepare(`
|
|
276
|
-
insert into tweet_collections (
|
|
277
|
-
account_id, tweet_id, kind, collected_at, source, raw_json, updated_at
|
|
278
|
-
) values (?, ?, ?, null, ?, ?, ?)
|
|
279
|
-
on conflict(account_id, tweet_id, kind) do update set
|
|
280
|
-
source = excluded.source,
|
|
281
|
-
raw_json = excluded.raw_json,
|
|
282
|
-
updated_at = excluded.updated_at
|
|
283
|
-
`);
|
|
284
|
-
|
|
285
|
-
db.transaction(() => {
|
|
286
|
-
const updatedAt = new Date().toISOString();
|
|
287
|
-
for (const tweet of payload.data) {
|
|
288
|
-
const author =
|
|
289
|
-
usersById.get(tweet.author_id) ??
|
|
290
|
-
({
|
|
291
|
-
id: tweet.author_id,
|
|
292
|
-
username: `user_${tweet.author_id}`,
|
|
293
|
-
name: `user_${tweet.author_id}`,
|
|
294
|
-
} as const);
|
|
295
|
-
const profile = usersById.has(tweet.author_id)
|
|
296
|
-
? upsertProfileFromXUser(db, author)
|
|
297
|
-
: ensureStubProfileForXUser(db, tweet.author_id);
|
|
298
|
-
const replyToId = getReferencedTweetId(tweet, "replied_to");
|
|
299
|
-
const quotedTweetId = getReferencedTweetId(tweet, "quoted");
|
|
300
|
-
upsertTweet.run(
|
|
301
|
-
tweet.id,
|
|
302
|
-
accountId,
|
|
303
|
-
profile.profile.id,
|
|
304
|
-
tweetKind,
|
|
305
|
-
tweet.text,
|
|
306
|
-
tweet.created_at,
|
|
307
|
-
replyToId ? 1 : 0,
|
|
308
|
-
replyToId,
|
|
309
|
-
Number(tweet.public_metrics?.like_count ?? 0),
|
|
310
|
-
countTweetMedia(tweet),
|
|
311
|
-
bookmarked,
|
|
312
|
-
liked,
|
|
313
|
-
JSON.stringify(tweet.entities ?? {}),
|
|
314
|
-
buildMediaJsonFromIncludes(tweet, payload.includes?.media),
|
|
315
|
-
quotedTweetId,
|
|
316
|
-
);
|
|
317
|
-
upsertCollection.run(
|
|
318
|
-
accountId,
|
|
319
|
-
tweet.id,
|
|
320
|
-
kind,
|
|
321
|
-
source,
|
|
322
|
-
JSON.stringify(tweet),
|
|
323
|
-
updatedAt,
|
|
324
|
-
);
|
|
325
|
-
replaceTweetFts(db, tweet.id, tweet.text);
|
|
326
|
-
}
|
|
327
|
-
})();
|
|
178
|
+
ingestTweetPayload(db, {
|
|
179
|
+
accountId,
|
|
180
|
+
payload,
|
|
181
|
+
kind: tweetKind,
|
|
182
|
+
collectionKind: kind,
|
|
183
|
+
markRepliesAsReplied: true,
|
|
184
|
+
replaceSecondaryKind: true,
|
|
185
|
+
source,
|
|
186
|
+
});
|
|
328
187
|
}
|
|
329
188
|
|
|
330
189
|
function fetchXurlCollectionEffect({
|
|
@@ -351,9 +210,8 @@ function fetchXurlCollectionEffect({
|
|
|
351
210
|
return Effect.gen(function* () {
|
|
352
211
|
let resolvedUserId = userId;
|
|
353
212
|
if (!resolvedUserId) {
|
|
354
|
-
const [accountUser] =
|
|
355
|
-
lookupUsersByHandles([username])
|
|
356
|
-
);
|
|
213
|
+
const [accountUser] =
|
|
214
|
+
yield* liveTransportGateway.xurl.lookupUsersByHandles([username]);
|
|
357
215
|
if (!accountUser?.id) {
|
|
358
216
|
return yield* Effect.fail(
|
|
359
217
|
new Error(`Could not resolve Twitter user id for @${username}`),
|
|
@@ -367,22 +225,20 @@ function fetchXurlCollectionEffect({
|
|
|
367
225
|
let pageCount = 0;
|
|
368
226
|
let saturatedAtPage: number | undefined;
|
|
369
227
|
do {
|
|
370
|
-
const payload = yield*
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
}),
|
|
385
|
-
);
|
|
228
|
+
const payload = yield* kind === "likes"
|
|
229
|
+
? liveTransportGateway.xurl.listLikes({
|
|
230
|
+
maxResults: limit,
|
|
231
|
+
username,
|
|
232
|
+
userId: resolvedUserId,
|
|
233
|
+
paginationToken: nextToken,
|
|
234
|
+
})
|
|
235
|
+
: liveTransportGateway.xurl.listBookmarks({
|
|
236
|
+
maxResults: limit,
|
|
237
|
+
username,
|
|
238
|
+
userId: resolvedUserId,
|
|
239
|
+
isPaginatedWalk: all,
|
|
240
|
+
paginationToken: nextToken,
|
|
241
|
+
});
|
|
386
242
|
pageCount += 1;
|
|
387
243
|
if (earlyStop) {
|
|
388
244
|
const tweetIds = payload.data.map((tweet) => tweet.id);
|
|
@@ -437,12 +293,12 @@ function fetchBirdCollectionEffect({
|
|
|
437
293
|
maxPages: number | null;
|
|
438
294
|
}) {
|
|
439
295
|
return kind === "likes"
|
|
440
|
-
?
|
|
296
|
+
? liveTransportGateway.bird.listLikes({
|
|
441
297
|
maxResults: limit,
|
|
442
298
|
all,
|
|
443
299
|
maxPages: maxPages ?? undefined,
|
|
444
300
|
})
|
|
445
|
-
:
|
|
301
|
+
: liveTransportGateway.bird.listBookmarks({
|
|
446
302
|
maxResults: limit,
|
|
447
303
|
all,
|
|
448
304
|
maxPages: maxPages ?? undefined,
|
|
@@ -473,31 +329,11 @@ export function syncTimelineCollectionEffect({
|
|
|
473
329
|
}
|
|
474
330
|
|
|
475
331
|
const db = yield* trySync(() => getNativeDb());
|
|
476
|
-
const resolvedAccount = yield* trySync(() =>
|
|
332
|
+
const resolvedAccount = yield* trySync(() =>
|
|
333
|
+
resolveLiveSyncAccount(db, account),
|
|
334
|
+
);
|
|
477
335
|
const cacheMaxPages = mode === "bird" ? parsedMaxPages : xurlMaxPages;
|
|
478
336
|
const cacheKey = `${kind}:${mode}:${resolvedAccount.accountId}:${String(limit)}:${all ? "all" : "single"}:${cacheMaxPages === null ? "all-pages" : String(cacheMaxPages)}${earlyStop ? ":early-stop" : ""}`;
|
|
479
|
-
const ttlMs = parseCacheTtlMs(cacheTtlMs);
|
|
480
|
-
const cached = yield* trySync(() =>
|
|
481
|
-
readSyncCache<XurlMentionsResponse>(cacheKey, db),
|
|
482
|
-
);
|
|
483
|
-
const cacheAgeMs = cached
|
|
484
|
-
? Date.now() - new Date(cached.updatedAt).getTime()
|
|
485
|
-
: Number.POSITIVE_INFINITY;
|
|
486
|
-
|
|
487
|
-
if (!refresh && cached && cacheAgeMs <= ttlMs) {
|
|
488
|
-
const saturatedAtPage = readSaturatedAtPage(cached.value);
|
|
489
|
-
return {
|
|
490
|
-
ok: true,
|
|
491
|
-
source: "cache",
|
|
492
|
-
kind,
|
|
493
|
-
accountId: resolvedAccount.accountId,
|
|
494
|
-
count: cached.value.data.length,
|
|
495
|
-
payload: cached.value,
|
|
496
|
-
...(saturatedAtPage === undefined
|
|
497
|
-
? {}
|
|
498
|
-
: { saturated_at_page: saturatedAtPage }),
|
|
499
|
-
};
|
|
500
|
-
}
|
|
501
337
|
|
|
502
338
|
if (shouldApplyEarlyStopCap) {
|
|
503
339
|
console.error(
|
|
@@ -505,60 +341,51 @@ export function syncTimelineCollectionEffect({
|
|
|
505
341
|
);
|
|
506
342
|
}
|
|
507
343
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
} else {
|
|
542
|
-
payload = yield* fetchBirdCollectionEffect({
|
|
543
|
-
kind,
|
|
544
|
-
limit,
|
|
545
|
-
all,
|
|
546
|
-
maxPages: parsedMaxPages,
|
|
547
|
-
});
|
|
548
|
-
source = "bird";
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
yield* trySync(() =>
|
|
553
|
-
mergeTimelineCollectionIntoLocalStore(
|
|
554
|
-
db,
|
|
555
|
-
resolvedAccount.accountId,
|
|
556
|
-
kind,
|
|
557
|
-
payload,
|
|
558
|
-
source,
|
|
344
|
+
const xurlFetch = fetchXurlCollectionEffect({
|
|
345
|
+
db,
|
|
346
|
+
kind,
|
|
347
|
+
accountId: resolvedAccount.accountId,
|
|
348
|
+
username: resolvedAccount.username,
|
|
349
|
+
userId: resolvedAccount.externalUserId,
|
|
350
|
+
limit,
|
|
351
|
+
all,
|
|
352
|
+
maxPages: xurlMaxPages,
|
|
353
|
+
earlyStop,
|
|
354
|
+
});
|
|
355
|
+
const birdFetch = fetchBirdCollectionEffect({
|
|
356
|
+
kind,
|
|
357
|
+
limit,
|
|
358
|
+
all,
|
|
359
|
+
maxPages: parsedMaxPages,
|
|
360
|
+
});
|
|
361
|
+
const transports =
|
|
362
|
+
mode === "bird"
|
|
363
|
+
? [createLiveTransportAdapter("bird", birdFetch)]
|
|
364
|
+
: mode === "xurl"
|
|
365
|
+
? [createLiveTransportAdapter("xurl", xurlFetch)]
|
|
366
|
+
: [
|
|
367
|
+
createLiveTransportAdapter("xurl", xurlFetch),
|
|
368
|
+
createLiveTransportAdapter("bird", birdFetch),
|
|
369
|
+
];
|
|
370
|
+
const syncResult = yield* runCachedLiveSyncEffect({
|
|
371
|
+
db,
|
|
372
|
+
cacheKey,
|
|
373
|
+
refresh,
|
|
374
|
+
cacheTtlMs: normalizeCacheTtlMs(
|
|
375
|
+
cacheTtlMs,
|
|
376
|
+
DEFAULT_COLLECTION_CACHE_TTL_MS,
|
|
559
377
|
),
|
|
560
|
-
|
|
561
|
-
|
|
378
|
+
transports,
|
|
379
|
+
persistLive: (writeDb, livePayload, liveSource) =>
|
|
380
|
+
mergeTimelineCollectionIntoLocalStore(
|
|
381
|
+
writeDb,
|
|
382
|
+
resolvedAccount.accountId,
|
|
383
|
+
kind,
|
|
384
|
+
livePayload,
|
|
385
|
+
liveSource,
|
|
386
|
+
),
|
|
387
|
+
});
|
|
388
|
+
const { source, payload } = syncResult;
|
|
562
389
|
const saturatedAtPage = readSaturatedAtPage(payload);
|
|
563
390
|
|
|
564
391
|
return {
|