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
package/src/lib/backup.ts
CHANGED
|
@@ -8,7 +8,13 @@ import { Data, Effect } from "effect";
|
|
|
8
8
|
import type { Database } from "./sqlite";
|
|
9
9
|
import { getBirdclawConfig } from "./config";
|
|
10
10
|
import { getNativeDb } from "./db";
|
|
11
|
+
import { databaseWriteEffect } from "./database-writer";
|
|
11
12
|
import { runEffectPromise, tryPromise } from "./effect-runtime";
|
|
13
|
+
import { getImportRepository } from "./import-repository";
|
|
14
|
+
import {
|
|
15
|
+
collectIngestionSourcesEffect,
|
|
16
|
+
streamJsonLines,
|
|
17
|
+
} from "./streaming-ingestion";
|
|
12
18
|
import { safeHttpUrl } from "./url-safety";
|
|
13
19
|
|
|
14
20
|
const execFileAsync = promisify(execFile);
|
|
@@ -1252,36 +1258,35 @@ function assertNoSymlinkAncestorEffect(
|
|
|
1252
1258
|
});
|
|
1253
1259
|
}
|
|
1254
1260
|
|
|
1255
|
-
function readJsonlFileEffect(
|
|
1256
|
-
repoPath: string,
|
|
1257
|
-
relativePath: string,
|
|
1258
|
-
): Effect.Effect<JsonRecord[], unknown> {
|
|
1259
|
-
return Effect.gen(function* () {
|
|
1260
|
-
const filePath = yield* trySync(() =>
|
|
1261
|
-
resolveBackupFilePath(repoPath, relativePath),
|
|
1262
|
-
);
|
|
1263
|
-
yield* assertReadableBackupFileEffect(repoPath, filePath, relativePath);
|
|
1264
|
-
const content = yield* tryPromise(() => fs.readFile(filePath, "utf8"));
|
|
1265
|
-
return yield* trySync(() =>
|
|
1266
|
-
content
|
|
1267
|
-
.split("\n")
|
|
1268
|
-
.filter((line) => line.length > 0)
|
|
1269
|
-
.map((line) => JSON.parse(line) as JsonRecord),
|
|
1270
|
-
);
|
|
1271
|
-
});
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
1261
|
function readJsonlFilesEffect(
|
|
1275
1262
|
repoPath: string,
|
|
1276
1263
|
relativePaths: string[],
|
|
1277
1264
|
): Effect.Effect<JsonRecord[], unknown> {
|
|
1278
1265
|
return Effect.gen(function* () {
|
|
1279
|
-
const
|
|
1266
|
+
const sources = yield* Effect.forEach(
|
|
1280
1267
|
relativePaths,
|
|
1281
|
-
(relativePath) =>
|
|
1268
|
+
(relativePath) =>
|
|
1269
|
+
Effect.gen(function* () {
|
|
1270
|
+
const filePath = yield* trySync(() =>
|
|
1271
|
+
resolveBackupFilePath(repoPath, relativePath),
|
|
1272
|
+
);
|
|
1273
|
+
yield* assertReadableBackupFileEffect(
|
|
1274
|
+
repoPath,
|
|
1275
|
+
filePath,
|
|
1276
|
+
relativePath,
|
|
1277
|
+
);
|
|
1278
|
+
return {
|
|
1279
|
+
id: relativePath,
|
|
1280
|
+
stream: async function* () {
|
|
1281
|
+
for await (const row of streamJsonLines(filePath)) {
|
|
1282
|
+
yield row.value as JsonRecord;
|
|
1283
|
+
}
|
|
1284
|
+
},
|
|
1285
|
+
};
|
|
1286
|
+
}),
|
|
1282
1287
|
{ concurrency: "unbounded" },
|
|
1283
1288
|
);
|
|
1284
|
-
return
|
|
1289
|
+
return yield* collectIngestionSourcesEffect(sources);
|
|
1285
1290
|
});
|
|
1286
1291
|
}
|
|
1287
1292
|
|
|
@@ -1336,18 +1341,6 @@ function rowsForManifestPath(
|
|
|
1336
1341
|
.sort();
|
|
1337
1342
|
}
|
|
1338
1343
|
|
|
1339
|
-
function insertRows(
|
|
1340
|
-
db: Database,
|
|
1341
|
-
sql: string,
|
|
1342
|
-
rows: JsonRecord[],
|
|
1343
|
-
keys: string[],
|
|
1344
|
-
) {
|
|
1345
|
-
const statement = db.prepare(sql);
|
|
1346
|
-
for (const row of rows) {
|
|
1347
|
-
statement.run(...keys.map((key) => row[key] ?? null));
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
1344
|
const JSON_URL_KEYS = new Set([
|
|
1352
1345
|
"url",
|
|
1353
1346
|
"expandedUrl",
|
|
@@ -1427,68 +1420,6 @@ function sanitizeImportedUrlExpansions(rows: JsonRecord[]) {
|
|
|
1427
1420
|
});
|
|
1428
1421
|
}
|
|
1429
1422
|
|
|
1430
|
-
function readFtsIds(
|
|
1431
|
-
db: Database,
|
|
1432
|
-
tableName: "tweets_fts" | "dm_fts",
|
|
1433
|
-
idColumn: "tweet_id" | "message_id",
|
|
1434
|
-
) {
|
|
1435
|
-
const rows = db
|
|
1436
|
-
.prepare(`select ${idColumn} as id from ${tableName}`)
|
|
1437
|
-
.all() as { id: string }[];
|
|
1438
|
-
return new Set(rows.map((row) => row.id));
|
|
1439
|
-
}
|
|
1440
|
-
|
|
1441
|
-
function insertFtsRows(
|
|
1442
|
-
db: Database,
|
|
1443
|
-
tableName: "tweets_fts" | "dm_fts",
|
|
1444
|
-
idColumn: "tweet_id" | "message_id",
|
|
1445
|
-
rows: JsonRecord[],
|
|
1446
|
-
idKey: string,
|
|
1447
|
-
textKey: string,
|
|
1448
|
-
existingIds = new Set<string>(),
|
|
1449
|
-
) {
|
|
1450
|
-
const statement = db.prepare(
|
|
1451
|
-
`insert into ${tableName} (${idColumn}, text) values (?, ?)`,
|
|
1452
|
-
);
|
|
1453
|
-
for (const row of rows) {
|
|
1454
|
-
const id = row[idKey];
|
|
1455
|
-
if (typeof id !== "string" || existingIds.has(id)) {
|
|
1456
|
-
continue;
|
|
1457
|
-
}
|
|
1458
|
-
const text = row[textKey];
|
|
1459
|
-
statement.run(id, typeof text === "string" ? text : "");
|
|
1460
|
-
existingIds.add(id);
|
|
1461
|
-
}
|
|
1462
|
-
}
|
|
1463
|
-
|
|
1464
|
-
function clearBackupImportData(db: Database) {
|
|
1465
|
-
db.exec(`
|
|
1466
|
-
delete from follow_events;
|
|
1467
|
-
delete from follow_edges;
|
|
1468
|
-
delete from follow_snapshot_members;
|
|
1469
|
-
delete from follow_snapshots;
|
|
1470
|
-
delete from ai_scores;
|
|
1471
|
-
delete from tweet_actions;
|
|
1472
|
-
delete from tweet_account_edges;
|
|
1473
|
-
delete from tweet_collections;
|
|
1474
|
-
delete from link_occurrences;
|
|
1475
|
-
delete from url_expansions;
|
|
1476
|
-
delete from blocks;
|
|
1477
|
-
delete from mutes;
|
|
1478
|
-
delete from dm_fts;
|
|
1479
|
-
delete from tweets_fts;
|
|
1480
|
-
delete from dm_messages;
|
|
1481
|
-
delete from dm_conversations;
|
|
1482
|
-
delete from tweets;
|
|
1483
|
-
delete from profile_bio_entities;
|
|
1484
|
-
delete from profile_snapshots;
|
|
1485
|
-
delete from profile_affiliations;
|
|
1486
|
-
delete from profiles;
|
|
1487
|
-
delete from accounts;
|
|
1488
|
-
delete from sync_cache;
|
|
1489
|
-
`);
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1492
1423
|
export function importBackupEffect({
|
|
1493
1424
|
repoPath,
|
|
1494
1425
|
db: providedDb,
|
|
@@ -1538,23 +1469,27 @@ export function importBackupEffect({
|
|
|
1538
1469
|
const sanitizedUrlExpansions = yield* trySync(() =>
|
|
1539
1470
|
sanitizeImportedUrlExpansions(urlExpansions),
|
|
1540
1471
|
);
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1472
|
+
const fingerprint = yield* databaseWriteEffect((writeDb) => {
|
|
1473
|
+
const repository = getImportRepository(writeDb);
|
|
1474
|
+
if (mode === "replace") {
|
|
1475
|
+
repository.clearBackupImport();
|
|
1476
|
+
}
|
|
1477
|
+
const tweetFtsIds =
|
|
1478
|
+
mode === "replace"
|
|
1479
|
+
? new Set<string>()
|
|
1480
|
+
: repository.readFtsIds({
|
|
1481
|
+
table: "tweets_fts",
|
|
1482
|
+
idColumn: "tweet_id",
|
|
1483
|
+
});
|
|
1484
|
+
const dmFtsIds =
|
|
1485
|
+
mode === "replace"
|
|
1486
|
+
? new Set<string>()
|
|
1487
|
+
: repository.readFtsIds({
|
|
1488
|
+
table: "dm_fts",
|
|
1489
|
+
idColumn: "message_id",
|
|
1490
|
+
});
|
|
1491
|
+
repository.insertRows(
|
|
1492
|
+
`
|
|
1558
1493
|
insert into accounts (id, name, handle, external_user_id, transport, is_default, created_at)
|
|
1559
1494
|
values (?, ?, ?, ?, ?, ?, ?)
|
|
1560
1495
|
on conflict(id) do update set
|
|
@@ -1565,20 +1500,19 @@ export function importBackupEffect({
|
|
|
1565
1500
|
is_default = max(accounts.is_default, excluded.is_default),
|
|
1566
1501
|
created_at = min(accounts.created_at, excluded.created_at)
|
|
1567
1502
|
`,
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
`
|
|
1503
|
+
accounts,
|
|
1504
|
+
[
|
|
1505
|
+
"id",
|
|
1506
|
+
"name",
|
|
1507
|
+
"handle",
|
|
1508
|
+
"external_user_id",
|
|
1509
|
+
"transport",
|
|
1510
|
+
"is_default",
|
|
1511
|
+
"created_at",
|
|
1512
|
+
],
|
|
1513
|
+
);
|
|
1514
|
+
repository.insertRows(
|
|
1515
|
+
`
|
|
1582
1516
|
insert into profile_snapshots (
|
|
1583
1517
|
profile_id, snapshot_hash, observed_at, last_seen_at, source, handle,
|
|
1584
1518
|
display_name, bio, location, url, verified_type, followers_count,
|
|
@@ -1592,28 +1526,27 @@ export function importBackupEffect({
|
|
|
1592
1526
|
else profile_snapshots.raw_json
|
|
1593
1527
|
end
|
|
1594
1528
|
`,
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
`
|
|
1529
|
+
profileSnapshots,
|
|
1530
|
+
[
|
|
1531
|
+
"profile_id",
|
|
1532
|
+
"snapshot_hash",
|
|
1533
|
+
"observed_at",
|
|
1534
|
+
"last_seen_at",
|
|
1535
|
+
"source",
|
|
1536
|
+
"handle",
|
|
1537
|
+
"display_name",
|
|
1538
|
+
"bio",
|
|
1539
|
+
"location",
|
|
1540
|
+
"url",
|
|
1541
|
+
"verified_type",
|
|
1542
|
+
"followers_count",
|
|
1543
|
+
"following_count",
|
|
1544
|
+
"affiliations_json",
|
|
1545
|
+
"raw_json",
|
|
1546
|
+
],
|
|
1547
|
+
);
|
|
1548
|
+
repository.insertRows(
|
|
1549
|
+
`
|
|
1617
1550
|
insert into profile_bio_entities (
|
|
1618
1551
|
profile_id, kind, value, source, is_active, first_seen_at, last_seen_at, raw_json
|
|
1619
1552
|
) values (?, ?, ?, coalesce(?, 'backup'), coalesce(?, 1), ?, ?, coalesce(?, '{}'))
|
|
@@ -1626,21 +1559,20 @@ export function importBackupEffect({
|
|
|
1626
1559
|
else profile_bio_entities.raw_json
|
|
1627
1560
|
end
|
|
1628
1561
|
`,
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
`
|
|
1562
|
+
profileBioEntities,
|
|
1563
|
+
[
|
|
1564
|
+
"profile_id",
|
|
1565
|
+
"kind",
|
|
1566
|
+
"value",
|
|
1567
|
+
"source",
|
|
1568
|
+
"is_active",
|
|
1569
|
+
"first_seen_at",
|
|
1570
|
+
"last_seen_at",
|
|
1571
|
+
"raw_json",
|
|
1572
|
+
],
|
|
1573
|
+
);
|
|
1574
|
+
repository.insertRows(
|
|
1575
|
+
`
|
|
1644
1576
|
insert into profiles (
|
|
1645
1577
|
id, handle, display_name, bio, followers_count, following_count,
|
|
1646
1578
|
public_metrics_json, avatar_hue, avatar_url, location, url,
|
|
@@ -1671,28 +1603,27 @@ export function importBackupEffect({
|
|
|
1671
1603
|
end,
|
|
1672
1604
|
created_at = min(profiles.created_at, excluded.created_at)
|
|
1673
1605
|
`,
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
`
|
|
1606
|
+
profiles,
|
|
1607
|
+
[
|
|
1608
|
+
"id",
|
|
1609
|
+
"handle",
|
|
1610
|
+
"display_name",
|
|
1611
|
+
"bio",
|
|
1612
|
+
"followers_count",
|
|
1613
|
+
"following_count",
|
|
1614
|
+
"public_metrics_json",
|
|
1615
|
+
"avatar_hue",
|
|
1616
|
+
"avatar_url",
|
|
1617
|
+
"location",
|
|
1618
|
+
"url",
|
|
1619
|
+
"verified_type",
|
|
1620
|
+
"entities_json",
|
|
1621
|
+
"raw_json",
|
|
1622
|
+
"created_at",
|
|
1623
|
+
],
|
|
1624
|
+
);
|
|
1625
|
+
repository.insertRows(
|
|
1626
|
+
`
|
|
1696
1627
|
insert into profile_affiliations (
|
|
1697
1628
|
subject_profile_id, organization_profile_id, organization_name,
|
|
1698
1629
|
organization_handle, badge_url, url, label, source, is_active,
|
|
@@ -1713,26 +1644,25 @@ export function importBackupEffect({
|
|
|
1713
1644
|
end,
|
|
1714
1645
|
updated_at = excluded.updated_at
|
|
1715
1646
|
`,
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
`
|
|
1647
|
+
profileAffiliations,
|
|
1648
|
+
[
|
|
1649
|
+
"subject_profile_id",
|
|
1650
|
+
"organization_profile_id",
|
|
1651
|
+
"organization_name",
|
|
1652
|
+
"organization_handle",
|
|
1653
|
+
"badge_url",
|
|
1654
|
+
"url",
|
|
1655
|
+
"label",
|
|
1656
|
+
"source",
|
|
1657
|
+
"is_active",
|
|
1658
|
+
"first_seen_at",
|
|
1659
|
+
"last_seen_at",
|
|
1660
|
+
"raw_json",
|
|
1661
|
+
"updated_at",
|
|
1662
|
+
],
|
|
1663
|
+
);
|
|
1664
|
+
repository.insertRows(
|
|
1665
|
+
`
|
|
1736
1666
|
insert into follow_snapshots (
|
|
1737
1667
|
id, account_id, direction, source, status, page_count, result_count,
|
|
1738
1668
|
started_at, completed_at, raw_meta_json
|
|
@@ -1751,23 +1681,22 @@ export function importBackupEffect({
|
|
|
1751
1681
|
else follow_snapshots.raw_meta_json
|
|
1752
1682
|
end
|
|
1753
1683
|
`,
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
`
|
|
1684
|
+
followSnapshots,
|
|
1685
|
+
[
|
|
1686
|
+
"id",
|
|
1687
|
+
"account_id",
|
|
1688
|
+
"direction",
|
|
1689
|
+
"source",
|
|
1690
|
+
"status",
|
|
1691
|
+
"page_count",
|
|
1692
|
+
"result_count",
|
|
1693
|
+
"started_at",
|
|
1694
|
+
"completed_at",
|
|
1695
|
+
"raw_meta_json",
|
|
1696
|
+
],
|
|
1697
|
+
);
|
|
1698
|
+
repository.insertRows(
|
|
1699
|
+
`
|
|
1771
1700
|
insert into follow_snapshot_members (
|
|
1772
1701
|
snapshot_id, profile_id, external_user_id, position
|
|
1773
1702
|
) values (?, ?, ?, coalesce(?, 0))
|
|
@@ -1775,12 +1704,11 @@ export function importBackupEffect({
|
|
|
1775
1704
|
external_user_id = coalesce(nullif(excluded.external_user_id, ''), follow_snapshot_members.external_user_id),
|
|
1776
1705
|
position = excluded.position
|
|
1777
1706
|
`,
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
`
|
|
1707
|
+
followSnapshotMembers,
|
|
1708
|
+
["snapshot_id", "profile_id", "external_user_id", "position"],
|
|
1709
|
+
);
|
|
1710
|
+
repository.insertRows(
|
|
1711
|
+
`
|
|
1784
1712
|
insert into follow_edges (
|
|
1785
1713
|
account_id, direction, profile_id, external_user_id, source, current,
|
|
1786
1714
|
first_seen_at, last_seen_at, ended_at, updated_at
|
|
@@ -1800,23 +1728,22 @@ export function importBackupEffect({
|
|
|
1800
1728
|
end,
|
|
1801
1729
|
updated_at = max(follow_edges.updated_at, excluded.updated_at)
|
|
1802
1730
|
`,
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
`
|
|
1731
|
+
followEdges,
|
|
1732
|
+
[
|
|
1733
|
+
"account_id",
|
|
1734
|
+
"direction",
|
|
1735
|
+
"profile_id",
|
|
1736
|
+
"external_user_id",
|
|
1737
|
+
"source",
|
|
1738
|
+
"current",
|
|
1739
|
+
"first_seen_at",
|
|
1740
|
+
"last_seen_at",
|
|
1741
|
+
"ended_at",
|
|
1742
|
+
"updated_at",
|
|
1743
|
+
],
|
|
1744
|
+
);
|
|
1745
|
+
repository.insertRows(
|
|
1746
|
+
`
|
|
1820
1747
|
insert into follow_events (
|
|
1821
1748
|
id, account_id, direction, profile_id, external_user_id, kind, event_at,
|
|
1822
1749
|
snapshot_id
|
|
@@ -1830,21 +1757,20 @@ export function importBackupEffect({
|
|
|
1830
1757
|
event_at = coalesce(nullif(excluded.event_at, ''), follow_events.event_at),
|
|
1831
1758
|
snapshot_id = coalesce(nullif(excluded.snapshot_id, ''), follow_events.snapshot_id)
|
|
1832
1759
|
`,
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
`
|
|
1760
|
+
followEvents,
|
|
1761
|
+
[
|
|
1762
|
+
"id",
|
|
1763
|
+
"account_id",
|
|
1764
|
+
"direction",
|
|
1765
|
+
"profile_id",
|
|
1766
|
+
"external_user_id",
|
|
1767
|
+
"kind",
|
|
1768
|
+
"event_at",
|
|
1769
|
+
"snapshot_id",
|
|
1770
|
+
],
|
|
1771
|
+
);
|
|
1772
|
+
repository.insertRows(
|
|
1773
|
+
`
|
|
1848
1774
|
insert into tweets (
|
|
1849
1775
|
id, account_id, author_profile_id, kind, text, created_at, is_replied,
|
|
1850
1776
|
reply_to_id, like_count, media_count, bookmarked, liked, entities_json,
|
|
@@ -1876,37 +1802,34 @@ export function importBackupEffect({
|
|
|
1876
1802
|
end,
|
|
1877
1803
|
quoted_tweet_id = coalesce(excluded.quoted_tweet_id, tweets.quoted_tweet_id)
|
|
1878
1804
|
`,
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
"id",
|
|
1882
|
-
"account_id",
|
|
1883
|
-
"author_profile_id",
|
|
1884
|
-
"kind",
|
|
1885
|
-
"text",
|
|
1886
|
-
"created_at",
|
|
1887
|
-
"is_replied",
|
|
1888
|
-
"reply_to_id",
|
|
1889
|
-
"like_count",
|
|
1890
|
-
"media_count",
|
|
1891
|
-
"bookmarked",
|
|
1892
|
-
"liked",
|
|
1893
|
-
"entities_json",
|
|
1894
|
-
"media_json",
|
|
1895
|
-
"quoted_tweet_id",
|
|
1896
|
-
],
|
|
1897
|
-
);
|
|
1898
|
-
insertFtsRows(
|
|
1899
|
-
db,
|
|
1900
|
-
"tweets_fts",
|
|
1901
|
-
"tweet_id",
|
|
1902
|
-
sanitizedTweets,
|
|
1805
|
+
sanitizedTweets,
|
|
1806
|
+
[
|
|
1903
1807
|
"id",
|
|
1808
|
+
"account_id",
|
|
1809
|
+
"author_profile_id",
|
|
1810
|
+
"kind",
|
|
1904
1811
|
"text",
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1812
|
+
"created_at",
|
|
1813
|
+
"is_replied",
|
|
1814
|
+
"reply_to_id",
|
|
1815
|
+
"like_count",
|
|
1816
|
+
"media_count",
|
|
1817
|
+
"bookmarked",
|
|
1818
|
+
"liked",
|
|
1819
|
+
"entities_json",
|
|
1820
|
+
"media_json",
|
|
1821
|
+
"quoted_tweet_id",
|
|
1822
|
+
],
|
|
1823
|
+
);
|
|
1824
|
+
repository.insertFtsRows({
|
|
1825
|
+
target: { table: "tweets_fts", idColumn: "tweet_id" },
|
|
1826
|
+
rows: sanitizedTweets,
|
|
1827
|
+
idKey: "id",
|
|
1828
|
+
textKey: "text",
|
|
1829
|
+
existingIds: tweetFtsIds,
|
|
1830
|
+
});
|
|
1831
|
+
repository.insertRows(
|
|
1832
|
+
`
|
|
1910
1833
|
insert into tweet_collections (
|
|
1911
1834
|
account_id, tweet_id, kind, collected_at, source, raw_json, updated_at
|
|
1912
1835
|
) values (?, ?, ?, ?, ?, ?, ?)
|
|
@@ -1919,20 +1842,19 @@ export function importBackupEffect({
|
|
|
1919
1842
|
end,
|
|
1920
1843
|
updated_at = max(tweet_collections.updated_at, excluded.updated_at)
|
|
1921
1844
|
`,
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
`
|
|
1845
|
+
collections,
|
|
1846
|
+
[
|
|
1847
|
+
"account_id",
|
|
1848
|
+
"tweet_id",
|
|
1849
|
+
"kind",
|
|
1850
|
+
"collected_at",
|
|
1851
|
+
"source",
|
|
1852
|
+
"raw_json",
|
|
1853
|
+
"updated_at",
|
|
1854
|
+
],
|
|
1855
|
+
);
|
|
1856
|
+
repository.insertRows(
|
|
1857
|
+
`
|
|
1936
1858
|
insert into tweet_account_edges (
|
|
1937
1859
|
account_id, tweet_id, kind, first_seen_at, last_seen_at, seen_count,
|
|
1938
1860
|
source, raw_json, updated_at
|
|
@@ -1948,22 +1870,21 @@ export function importBackupEffect({
|
|
|
1948
1870
|
end,
|
|
1949
1871
|
updated_at = max(tweet_account_edges.updated_at, excluded.updated_at)
|
|
1950
1872
|
`,
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
`
|
|
1873
|
+
timelineEdges,
|
|
1874
|
+
[
|
|
1875
|
+
"account_id",
|
|
1876
|
+
"tweet_id",
|
|
1877
|
+
"kind",
|
|
1878
|
+
"first_seen_at",
|
|
1879
|
+
"last_seen_at",
|
|
1880
|
+
"seen_count",
|
|
1881
|
+
"source",
|
|
1882
|
+
"raw_json",
|
|
1883
|
+
"updated_at",
|
|
1884
|
+
],
|
|
1885
|
+
);
|
|
1886
|
+
repository.insertRows(
|
|
1887
|
+
`
|
|
1967
1888
|
insert into dm_conversations (
|
|
1968
1889
|
id, account_id, participant_profile_id, title, inbox_kind, last_message_at, unread_count, needs_reply
|
|
1969
1890
|
) values (?, ?, ?, ?, coalesce(?, 'accepted'), ?, ?, ?)
|
|
@@ -1980,21 +1901,20 @@ export function importBackupEffect({
|
|
|
1980
1901
|
unread_count = max(dm_conversations.unread_count, excluded.unread_count),
|
|
1981
1902
|
needs_reply = max(dm_conversations.needs_reply, excluded.needs_reply)
|
|
1982
1903
|
`,
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
`
|
|
1904
|
+
conversations,
|
|
1905
|
+
[
|
|
1906
|
+
"id",
|
|
1907
|
+
"account_id",
|
|
1908
|
+
"participant_profile_id",
|
|
1909
|
+
"title",
|
|
1910
|
+
"inbox_kind",
|
|
1911
|
+
"last_message_at",
|
|
1912
|
+
"unread_count",
|
|
1913
|
+
"needs_reply",
|
|
1914
|
+
],
|
|
1915
|
+
);
|
|
1916
|
+
repository.insertRows(
|
|
1917
|
+
`
|
|
1998
1918
|
insert into dm_messages (
|
|
1999
1919
|
id, conversation_id, sender_profile_id, text, created_at, direction, is_replied, media_count
|
|
2000
1920
|
) values (?, ?, ?, ?, ?, ?, ?, ?)
|
|
@@ -2007,30 +1927,27 @@ export function importBackupEffect({
|
|
|
2007
1927
|
is_replied = max(dm_messages.is_replied, excluded.is_replied),
|
|
2008
1928
|
media_count = max(dm_messages.media_count, excluded.media_count)
|
|
2009
1929
|
`,
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
"id",
|
|
2013
|
-
"conversation_id",
|
|
2014
|
-
"sender_profile_id",
|
|
2015
|
-
"text",
|
|
2016
|
-
"created_at",
|
|
2017
|
-
"direction",
|
|
2018
|
-
"is_replied",
|
|
2019
|
-
"media_count",
|
|
2020
|
-
],
|
|
2021
|
-
);
|
|
2022
|
-
insertFtsRows(
|
|
2023
|
-
db,
|
|
2024
|
-
"dm_fts",
|
|
2025
|
-
"message_id",
|
|
2026
|
-
messages,
|
|
1930
|
+
messages,
|
|
1931
|
+
[
|
|
2027
1932
|
"id",
|
|
1933
|
+
"conversation_id",
|
|
1934
|
+
"sender_profile_id",
|
|
2028
1935
|
"text",
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
1936
|
+
"created_at",
|
|
1937
|
+
"direction",
|
|
1938
|
+
"is_replied",
|
|
1939
|
+
"media_count",
|
|
1940
|
+
],
|
|
1941
|
+
);
|
|
1942
|
+
repository.insertFtsRows({
|
|
1943
|
+
target: { table: "dm_fts", idColumn: "message_id" },
|
|
1944
|
+
rows: messages,
|
|
1945
|
+
idKey: "id",
|
|
1946
|
+
textKey: "text",
|
|
1947
|
+
existingIds: dmFtsIds,
|
|
1948
|
+
});
|
|
1949
|
+
repository.insertRows(
|
|
1950
|
+
`
|
|
2034
1951
|
insert into url_expansions (
|
|
2035
1952
|
short_url, expanded_url, final_url, status, expanded_tweet_id,
|
|
2036
1953
|
expanded_handle, title, description, image_url, site_name, error, source,
|
|
@@ -2050,26 +1967,25 @@ export function importBackupEffect({
|
|
|
2050
1967
|
source = excluded.source,
|
|
2051
1968
|
updated_at = excluded.updated_at
|
|
2052
1969
|
`,
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
`
|
|
1970
|
+
sanitizedUrlExpansions,
|
|
1971
|
+
[
|
|
1972
|
+
"short_url",
|
|
1973
|
+
"expanded_url",
|
|
1974
|
+
"final_url",
|
|
1975
|
+
"status",
|
|
1976
|
+
"expanded_tweet_id",
|
|
1977
|
+
"expanded_handle",
|
|
1978
|
+
"title",
|
|
1979
|
+
"description",
|
|
1980
|
+
"image_url",
|
|
1981
|
+
"site_name",
|
|
1982
|
+
"error",
|
|
1983
|
+
"source",
|
|
1984
|
+
"updated_at",
|
|
1985
|
+
],
|
|
1986
|
+
);
|
|
1987
|
+
repository.insertRows(
|
|
1988
|
+
`
|
|
2073
1989
|
insert into link_occurrences (
|
|
2074
1990
|
source_kind, source_id, source_position, short_url, account_id,
|
|
2075
1991
|
conversation_id, direction, created_at
|
|
@@ -2080,45 +1996,42 @@ export function importBackupEffect({
|
|
|
2080
1996
|
direction = excluded.direction,
|
|
2081
1997
|
created_at = excluded.created_at
|
|
2082
1998
|
`,
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
`
|
|
1999
|
+
linkOccurrences,
|
|
2000
|
+
[
|
|
2001
|
+
"source_kind",
|
|
2002
|
+
"source_id",
|
|
2003
|
+
"source_position",
|
|
2004
|
+
"short_url",
|
|
2005
|
+
"account_id",
|
|
2006
|
+
"conversation_id",
|
|
2007
|
+
"direction",
|
|
2008
|
+
"created_at",
|
|
2009
|
+
],
|
|
2010
|
+
);
|
|
2011
|
+
repository.insertRows(
|
|
2012
|
+
`
|
|
2098
2013
|
insert into blocks (account_id, profile_id, source, created_at)
|
|
2099
2014
|
values (?, ?, ?, ?)
|
|
2100
2015
|
on conflict(account_id, profile_id) do update set
|
|
2101
2016
|
source = coalesce(nullif(excluded.source, ''), blocks.source),
|
|
2102
2017
|
created_at = min(blocks.created_at, excluded.created_at)
|
|
2103
2018
|
`,
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
`
|
|
2019
|
+
blocks,
|
|
2020
|
+
["account_id", "profile_id", "source", "created_at"],
|
|
2021
|
+
);
|
|
2022
|
+
repository.insertRows(
|
|
2023
|
+
`
|
|
2110
2024
|
insert into mutes (account_id, profile_id, source, created_at)
|
|
2111
2025
|
values (?, ?, ?, ?)
|
|
2112
2026
|
on conflict(account_id, profile_id) do update set
|
|
2113
2027
|
source = coalesce(nullif(excluded.source, ''), mutes.source),
|
|
2114
2028
|
created_at = min(mutes.created_at, excluded.created_at)
|
|
2115
2029
|
`,
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
`
|
|
2030
|
+
mutes,
|
|
2031
|
+
["account_id", "profile_id", "source", "created_at"],
|
|
2032
|
+
);
|
|
2033
|
+
repository.insertRows(
|
|
2034
|
+
`
|
|
2122
2035
|
insert into tweet_actions (id, account_id, tweet_id, kind, body, created_at)
|
|
2123
2036
|
values (?, ?, ?, ?, ?, ?)
|
|
2124
2037
|
on conflict(id) do update set
|
|
@@ -2128,12 +2041,11 @@ export function importBackupEffect({
|
|
|
2128
2041
|
body = coalesce(nullif(excluded.body, ''), tweet_actions.body),
|
|
2129
2042
|
created_at = min(tweet_actions.created_at, excluded.created_at)
|
|
2130
2043
|
`,
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
`
|
|
2044
|
+
actions,
|
|
2045
|
+
["id", "account_id", "tweet_id", "kind", "body", "created_at"],
|
|
2046
|
+
);
|
|
2047
|
+
repository.insertRows(
|
|
2048
|
+
`
|
|
2137
2049
|
insert into ai_scores (
|
|
2138
2050
|
entity_kind, entity_id, model, score, summary, reasoning, updated_at
|
|
2139
2051
|
) values (?, ?, ?, ?, ?, ?, ?)
|
|
@@ -2144,20 +2056,19 @@ export function importBackupEffect({
|
|
|
2144
2056
|
reasoning = coalesce(nullif(excluded.reasoning, ''), ai_scores.reasoning),
|
|
2145
2057
|
updated_at = max(ai_scores.updated_at, excluded.updated_at)
|
|
2146
2058
|
`,
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
});
|
|
2059
|
+
scores,
|
|
2060
|
+
[
|
|
2061
|
+
"entity_kind",
|
|
2062
|
+
"entity_id",
|
|
2063
|
+
"model",
|
|
2064
|
+
"score",
|
|
2065
|
+
"summary",
|
|
2066
|
+
"reasoning",
|
|
2067
|
+
"updated_at",
|
|
2068
|
+
],
|
|
2069
|
+
);
|
|
2070
|
+
return getBackupDatabaseFingerprint(writeDb);
|
|
2071
|
+
}, db);
|
|
2161
2072
|
|
|
2162
2073
|
return {
|
|
2163
2074
|
ok: true,
|