birdclaw 0.8.3 → 0.8.4
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 +17 -0
- package/README.md +10 -8
- package/bin/birdclaw.mjs +4 -66
- package/dist/cli/birdclaw.js +28165 -0
- package/dist/client/assets/AvatarChip-DLoqM5xD.js +1 -0
- package/dist/client/assets/ProfilePreview-BejAuYsJ.js +1 -0
- package/dist/client/assets/SavedTimelineView-BIS7HKpp.js +1 -0
- package/dist/client/assets/SmartTimestamp-BR0-9se2.js +1 -0
- package/dist/client/assets/TimelineRouteFrame-CyGPj0eM.js +1 -0
- package/dist/client/assets/blocks-7UDKQp8H.js +1 -0
- package/dist/client/assets/bookmarks-CbBkMvXk.js +1 -0
- package/dist/client/assets/chunk-C0phanGV.js +1 -0
- package/dist/client/assets/circle-check-C_Vq3ElD.js +1 -0
- package/dist/client/assets/client-stream-contracts-ys3XhWG4.js +5 -0
- package/dist/client/assets/createLucideIcon-JV8isFFR.js +1 -0
- package/dist/client/assets/data-sources-Cm2bpNvg.js +1 -0
- package/dist/client/assets/discuss-DTjaOugw.js +1 -0
- package/dist/client/assets/dms-CGd6Eogq.js +1 -0
- package/dist/client/assets/inbox-BHlGuOy2.js +1 -0
- package/dist/client/assets/index-CEIG7S6s.js +31 -0
- package/dist/client/assets/index-bpFrQ5yG.css +1 -0
- package/dist/client/assets/likes-cLrcAQem.js +1 -0
- package/dist/client/assets/links-CM9QO1LC.js +1 -0
- package/dist/client/assets/mapbox-BxTlqXt9.js +2 -0
- package/dist/client/assets/mapbox-gl-dgf_hX3a.js +3215 -0
- package/dist/client/assets/mentions-CxKCgzIf.js +1 -0
- package/dist/client/assets/network-map-B5a3whqj.js +2 -0
- package/dist/client/assets/profile-analyze-CRtNEwlb.js +1 -0
- package/dist/client/assets/profile-hydration-client-YEtJsNTv.js +1 -0
- package/dist/client/assets/profiles._handle-C82_HoKX.js +1 -0
- package/dist/client/assets/query-client-fYu2rzRC.js +17 -0
- package/dist/client/assets/rate-limits-ScaEwdVK.js +1 -0
- package/dist/client/assets/react-dom-DHl6Ug7F.js +1 -0
- package/dist/client/assets/react-nBylq1U5.js +1 -0
- package/dist/client/assets/repeat-2-xCwHM9hD.js +1 -0
- package/dist/client/assets/routes-q7ZaW4En.js +1 -0
- package/dist/client/assets/schemas-I9r6F6ya.js +64 -0
- package/dist/client/assets/search-Dq5kYsxA.js +1 -0
- package/dist/client/assets/sparkles-CQVlvHsZ.js +1 -0
- package/dist/client/assets/styles-B8s3tt3r.css +2 -0
- package/dist/client/assets/today-CeG1O7Py.js +1 -0
- package/dist/client/assets/triangle-alert-CBL7s2pf.js +1 -0
- package/dist/client/assets/useTimelineRouteData-1HsqgvUi.js +1 -0
- package/dist/client/assets/users-CHbKlqUr.js +1 -0
- package/dist/server/assets/AvatarChip-zUDAEmjL.js +105 -0
- package/dist/server/assets/FeedState-ntW0Q2GB.js +214 -0
- package/dist/server/assets/ProfileAnalysisStream-BFvhVdhn.js +198 -0
- package/dist/server/assets/ProfilePreview-C6gAor_j.js +752 -0
- package/dist/server/assets/SavedTimelineView-BG1jnBp1.js +64 -0
- package/dist/server/assets/SmartTimestamp-DfwE1NGf.js +45 -0
- package/dist/server/assets/SyncNowButton-BOn_IBXS.js +76 -0
- package/dist/server/assets/TimelineRouteFrame-CU7ilM7U.js +85 -0
- package/dist/server/assets/TweetRichText-DhCVv1-6.js +74 -0
- package/dist/server/assets/_tanstack-start-manifest_v-C-ZRnG_n.js +148 -0
- package/dist/server/assets/account-selection-CTdFGWRk.js +44 -0
- package/dist/server/assets/blocks-C1mgGTB3.js +299 -0
- package/dist/server/assets/blocks-DSgQghqP.js +17 -0
- package/dist/server/assets/bookmarks-BJN8tykY.js +14 -0
- package/dist/server/assets/client-stream-contracts-C2xbWVjm.js +769 -0
- package/dist/server/assets/data-sources-BnA1Q94p.js +180 -0
- package/dist/server/assets/discuss-CJ1dau1j.js +15 -0
- package/dist/server/assets/discuss-QTo08NCN.js +338 -0
- package/dist/server/assets/dms-BuLj4bp8.js +368 -0
- package/dist/server/assets/dms-DAyQrVM2.js +240 -0
- package/dist/server/assets/empty-plugin-adapters-DzrEkdBF.js +5 -0
- package/dist/server/assets/inbox-CkGOaW1q.js +214 -0
- package/dist/server/assets/inbox-DpWd1EzC.js +146 -0
- package/dist/server/assets/likes-DBOAtsJU.js +14 -0
- package/dist/server/assets/links-DAhSjynu.js +240 -0
- package/dist/server/assets/links-DmH5lxHO.js +468 -0
- package/dist/server/assets/mentions-BH2MzKtB.js +26 -0
- package/dist/server/assets/network-map-D3CzRcC4.js +224 -0
- package/dist/server/assets/network-map-D5DoLOwR.js +582 -0
- package/dist/server/assets/profile-analyze-BP65PED0.js +90 -0
- package/dist/server/assets/profile-analyze-C1NoM0tV.js +9 -0
- package/dist/server/assets/profile-hydration-client-GJ4kwJS8.js +133 -0
- package/dist/server/assets/profiles._handle-DjwlN_ac.js +184 -0
- package/dist/server/assets/profiles._handle-DsLNj2Ca.js +12 -0
- package/dist/server/assets/query-client-BdauHBgd.js +923 -0
- package/dist/server/assets/rate-limits-VAr2qzYD.js +262 -0
- package/dist/server/assets/route-search-BUlQ5lGM.js +117 -0
- package/dist/server/assets/router-DqkwSPiM.js +17026 -0
- package/dist/server/assets/routes-A9c9ZhwN.js +26 -0
- package/dist/server/assets/start-FaDOTmto.js +4 -0
- package/dist/server/assets/today-B5hVM57Z.js +17 -0
- package/dist/server/assets/today-fvGiZ7ud.js +303 -0
- package/dist/server/assets/ui-qbmcMSSX.js +137 -0
- package/{src/components/useDebouncedValue.ts → dist/server/assets/useDebouncedValue-DOnA6Xcy.js} +4 -4
- package/dist/server/assets/useTimelineRouteData-27cxynxa.js +1101 -0
- package/dist/server/server.js +5520 -0
- package/package.json +26 -34
- package/playwright.config.ts +0 -35
- package/scripts/browser-perf.mjs +0 -427
- package/scripts/build-docs-site.mjs +0 -967
- package/scripts/docs-site-assets.mjs +0 -311
- package/scripts/run-vitest.mjs +0 -21
- package/scripts/sanitize-node-options.mjs +0 -23
- package/scripts/start-test-server.mjs +0 -42
- package/src/cli/command-context.ts +0 -17
- package/src/cli/register-analysis.ts +0 -500
- package/src/cli/register-compose.ts +0 -40
- package/src/cli/register-graph.ts +0 -132
- package/src/cli/register-inbox.ts +0 -41
- package/src/cli/register-storage.ts +0 -106
- package/src/cli-moderation.ts +0 -210
- package/src/cli.ts +0 -1616
- package/src/components/AccountSwitcher.tsx +0 -178
- package/src/components/AppNav.tsx +0 -118
- package/src/components/AvatarChip.tsx +0 -58
- package/src/components/AvatarPreload.ts +0 -149
- package/src/components/BrandMark.tsx +0 -67
- package/src/components/ConversationThread.tsx +0 -131
- package/src/components/DmWorkspace.tsx +0 -286
- package/src/components/EmbeddedTweetCard.tsx +0 -55
- package/src/components/FeedState.tsx +0 -147
- package/src/components/FloatingPreview.tsx +0 -382
- package/src/components/InboxCard.tsx +0 -152
- package/src/components/LinkPreviewCard.tsx +0 -292
- package/src/components/MarkdownCitations.tsx +0 -680
- package/src/components/MarkdownViewer.tsx +0 -111
- package/src/components/ProfileAnalysisClient.ts +0 -191
- package/src/components/ProfileAnalysisStream.tsx +0 -259
- package/src/components/ProfilePreview.tsx +0 -131
- package/src/components/SavedTimelineView.tsx +0 -155
- package/src/components/SmartTimestamp.tsx +0 -72
- package/src/components/SyncNowButton.tsx +0 -140
- package/src/components/ThemeSlider.tsx +0 -80
- package/src/components/TimelineCard.tsx +0 -533
- package/src/components/TimelineRouteFrame.tsx +0 -186
- package/src/components/TweetArticleCard.tsx +0 -66
- package/src/components/TweetMediaGrid.tsx +0 -185
- package/src/components/TweetRichText.tsx +0 -159
- package/src/components/account-selection.ts +0 -64
- package/src/components/links-controller.ts +0 -162
- package/src/components/links-model.ts +0 -198
- package/src/components/network-map-controller.ts +0 -84
- package/src/components/network-map-model.ts +0 -255
- package/src/components/useTimelineRouteData.ts +0 -193
- package/src/lib/account-sync-job.ts +0 -666
- package/src/lib/actions-transport.ts +0 -300
- package/src/lib/analysis-runtime.ts +0 -238
- package/src/lib/api-client.ts +0 -220
- package/src/lib/api-contracts.ts +0 -328
- package/src/lib/archive-finder.ts +0 -185
- package/src/lib/archive-import-plan.ts +0 -102
- package/src/lib/archive-import.ts +0 -2695
- package/src/lib/authored-live.ts +0 -1027
- package/src/lib/avatar-cache.ts +0 -349
- package/src/lib/backup.ts +0 -2652
- package/src/lib/bird-actions.ts +0 -294
- package/src/lib/bird-command.ts +0 -130
- package/src/lib/bird.ts +0 -1140
- package/src/lib/blocklist.ts +0 -136
- package/src/lib/blocks-write.ts +0 -171
- package/src/lib/blocks.ts +0 -387
- package/src/lib/bookmark-sync-job.ts +0 -536
- package/src/lib/config.ts +0 -224
- package/src/lib/conversation-surface.ts +0 -205
- package/src/lib/data-sources.ts +0 -219
- package/src/lib/database-metrics.ts +0 -88
- package/src/lib/database-migrations.ts +0 -34
- package/src/lib/database-schema.ts +0 -312
- package/src/lib/database-writer.ts +0 -69
- package/src/lib/db.ts +0 -889
- package/src/lib/dm-read-model.ts +0 -533
- package/src/lib/dms-live.ts +0 -870
- package/src/lib/effect-runtime.ts +0 -45
- package/src/lib/follow-graph.ts +0 -1087
- package/src/lib/geocoding.ts +0 -296
- package/src/lib/http-effect.ts +0 -222
- package/src/lib/identity-search-index.ts +0 -369
- package/src/lib/import-repository.ts +0 -138
- package/src/lib/inbox.ts +0 -242
- package/src/lib/link-index.ts +0 -641
- package/src/lib/link-insights.ts +0 -860
- package/src/lib/link-preview-metadata.ts +0 -754
- package/src/lib/live-sync-engine.ts +0 -209
- package/src/lib/live-transport-gateway.ts +0 -128
- package/src/lib/location.ts +0 -137
- package/src/lib/media-fetch.ts +0 -860
- package/src/lib/media-includes.ts +0 -165
- package/src/lib/mention-threads-live.ts +0 -830
- package/src/lib/mentions-export.ts +0 -147
- package/src/lib/mentions-live.ts +0 -1114
- package/src/lib/moderation-target.ts +0 -227
- package/src/lib/moderation-write.ts +0 -131
- package/src/lib/mutes-write.ts +0 -171
- package/src/lib/mutes.ts +0 -84
- package/src/lib/ndjson-stream.ts +0 -106
- package/src/lib/network-map.ts +0 -382
- package/src/lib/openai-response-runtime.ts +0 -251
- package/src/lib/openai.ts +0 -117
- package/src/lib/paginated-sync.ts +0 -93
- package/src/lib/period-digest.ts +0 -1364
- package/src/lib/present.ts +0 -118
- package/src/lib/profile-affiliation-hydration.ts +0 -228
- package/src/lib/profile-affiliations.ts +0 -262
- package/src/lib/profile-analysis.ts +0 -1198
- package/src/lib/profile-bio-entities.ts +0 -318
- package/src/lib/profile-history.ts +0 -164
- package/src/lib/profile-hydration.ts +0 -180
- package/src/lib/profile-replies.ts +0 -77
- package/src/lib/profile-resolver.ts +0 -650
- package/src/lib/queries.ts +0 -6
- package/src/lib/query-actions.ts +0 -437
- package/src/lib/query-client.tsx +0 -47
- package/src/lib/query-read-model-shared.ts +0 -52
- package/src/lib/query-read-models.ts +0 -5
- package/src/lib/query-resource.ts +0 -41
- package/src/lib/query-status.ts +0 -164
- package/src/lib/research.ts +0 -652
- package/src/lib/runtime-services.ts +0 -20
- package/src/lib/search-discussion.ts +0 -812
- package/src/lib/seed.ts +0 -613
- package/src/lib/server-runtime-services.ts +0 -30
- package/src/lib/sqlite.ts +0 -183
- package/src/lib/streaming-ingestion.ts +0 -240
- package/src/lib/sync-cache.ts +0 -70
- package/src/lib/sync-plan.ts +0 -175
- package/src/lib/theme-transition.ts +0 -113
- package/src/lib/theme.tsx +0 -165
- package/src/lib/timeline-collections-live.ts +0 -407
- package/src/lib/timeline-live.ts +0 -302
- package/src/lib/timeline-read-model.ts +0 -1191
- package/src/lib/tweet-account-edges.ts +0 -48
- package/src/lib/tweet-lookup.ts +0 -46
- package/src/lib/tweet-render.ts +0 -430
- package/src/lib/tweet-repository.ts +0 -156
- package/src/lib/tweet-search-live.ts +0 -462
- package/src/lib/types.ts +0 -723
- package/src/lib/ui.ts +0 -529
- package/src/lib/url-expansion-store.ts +0 -110
- package/src/lib/url-expansion.ts +0 -343
- package/src/lib/url-safety.ts +0 -220
- package/src/lib/web-sync.ts +0 -533
- package/src/lib/whois.ts +0 -1080
- package/src/lib/x-profile.ts +0 -365
- package/src/lib/x-web.ts +0 -199
- package/src/lib/xurl-rate-limits.ts +0 -267
- package/src/lib/xurl.ts +0 -1677
- package/src/routeTree.gen.ts +0 -723
- package/src/router.tsx +0 -20
- package/src/routes/__root.tsx +0 -82
- package/src/routes/api/action.tsx +0 -147
- package/src/routes/api/avatar.tsx +0 -50
- package/src/routes/api/blocks.tsx +0 -35
- package/src/routes/api/conversation.tsx +0 -45
- package/src/routes/api/data-sources.tsx +0 -24
- package/src/routes/api/inbox.tsx +0 -43
- package/src/routes/api/link-insights.tsx +0 -85
- package/src/routes/api/link-preview.tsx +0 -47
- package/src/routes/api/network-map.tsx +0 -55
- package/src/routes/api/period-digest.tsx +0 -101
- package/src/routes/api/profile-analysis.tsx +0 -97
- package/src/routes/api/profile-hydrate.tsx +0 -54
- package/src/routes/api/query.tsx +0 -121
- package/src/routes/api/search-discussion.tsx +0 -113
- package/src/routes/api/status.tsx +0 -30
- package/src/routes/api/sync.tsx +0 -108
- package/src/routes/api/xurl-rate-limits.tsx +0 -24
- package/src/routes/blocks.tsx +0 -343
- package/src/routes/bookmarks.tsx +0 -18
- package/src/routes/data-sources.tsx +0 -249
- package/src/routes/discuss.tsx +0 -419
- package/src/routes/dms.tsx +0 -415
- package/src/routes/inbox.tsx +0 -232
- package/src/routes/index.tsx +0 -32
- package/src/routes/likes.tsx +0 -18
- package/src/routes/links.tsx +0 -631
- package/src/routes/mentions.tsx +0 -32
- package/src/routes/network-map.tsx +0 -732
- package/src/routes/profile-analyze.tsx +0 -112
- package/src/routes/profiles.$handle.tsx +0 -228
- package/src/routes/rate-limits.tsx +0 -305
- package/src/routes/today.tsx +0 -511
- package/src/styles.css +0 -257
- package/tsconfig.json +0 -29
- package/vite.config.ts +0 -29
- /package/{public → dist/client}/birdclaw-mark.png +0 -0
- /package/{public → dist/client}/favicon.ico +0 -0
- /package/{public → dist/client}/logo192.png +0 -0
- /package/{public → dist/client}/logo512.png +0 -0
- /package/{public → dist/client}/manifest.json +0 -0
- /package/{public → dist/client}/robots.txt +0 -0
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import { Effect } from "effect";
|
|
2
|
-
import { databaseWriteEffect } from "./database-writer";
|
|
3
|
-
import type { Database } from "./sqlite";
|
|
4
|
-
import { readSyncCache, writeSyncCache } from "./sync-cache";
|
|
5
|
-
|
|
6
|
-
export interface LiveTransportAdapter<Source extends string, Payload> {
|
|
7
|
-
source: Source;
|
|
8
|
-
fetch: Effect.Effect<Payload, Error>;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface LiveSyncAccount {
|
|
12
|
-
accountId: string;
|
|
13
|
-
username: string;
|
|
14
|
-
externalUserId?: string;
|
|
15
|
-
isDefault: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface CachedLiveSyncOptions<Source extends string, Payload, Persisted> {
|
|
19
|
-
db: Database;
|
|
20
|
-
cacheKey: string;
|
|
21
|
-
refresh: boolean;
|
|
22
|
-
cacheTtlMs: number;
|
|
23
|
-
transports: readonly LiveTransportAdapter<Source, Payload>[];
|
|
24
|
-
persistLive: (db: Database, payload: Payload, source: Source) => Persisted;
|
|
25
|
-
persistCached?: (db: Database, payload: Payload) => Persisted;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface CachedLiveSyncResult<
|
|
29
|
-
Source extends string,
|
|
30
|
-
Payload,
|
|
31
|
-
Persisted,
|
|
32
|
-
> {
|
|
33
|
-
source: Source | "cache";
|
|
34
|
-
payload: Payload;
|
|
35
|
-
persisted: Persisted | undefined;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function toError(error: unknown) {
|
|
39
|
-
return error instanceof Error ? error : new Error(String(error));
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function resolveLiveSyncAccount(
|
|
43
|
-
db: Database,
|
|
44
|
-
accountId?: string,
|
|
45
|
-
): LiveSyncAccount {
|
|
46
|
-
const row = accountId
|
|
47
|
-
? (db
|
|
48
|
-
.prepare(
|
|
49
|
-
"select id, handle, external_user_id, is_default from accounts where id = ?",
|
|
50
|
-
)
|
|
51
|
-
.get(accountId) as
|
|
52
|
-
| {
|
|
53
|
-
id: string;
|
|
54
|
-
handle: string;
|
|
55
|
-
external_user_id: string | null;
|
|
56
|
-
is_default: number;
|
|
57
|
-
}
|
|
58
|
-
| undefined)
|
|
59
|
-
: (db
|
|
60
|
-
.prepare(
|
|
61
|
-
`
|
|
62
|
-
select id, handle, external_user_id, is_default
|
|
63
|
-
from accounts
|
|
64
|
-
order by is_default desc, created_at asc
|
|
65
|
-
limit 1
|
|
66
|
-
`,
|
|
67
|
-
)
|
|
68
|
-
.get() as
|
|
69
|
-
| {
|
|
70
|
-
id: string;
|
|
71
|
-
handle: string;
|
|
72
|
-
external_user_id: string | null;
|
|
73
|
-
is_default: number;
|
|
74
|
-
}
|
|
75
|
-
| undefined);
|
|
76
|
-
|
|
77
|
-
if (!row) {
|
|
78
|
-
throw new Error(`Unknown account: ${accountId ?? "default"}`);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const externalUserId = row.external_user_id?.trim();
|
|
82
|
-
return {
|
|
83
|
-
accountId: row.id,
|
|
84
|
-
username: row.handle.replace(/^@/, ""),
|
|
85
|
-
...(externalUserId ? { externalUserId } : {}),
|
|
86
|
-
isDefault: row.is_default === 1,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function createLiveTransportAdapter<Source extends string, Payload>(
|
|
91
|
-
source: Source,
|
|
92
|
-
fetch: Effect.Effect<Payload, unknown>,
|
|
93
|
-
): LiveTransportAdapter<Source, Payload> {
|
|
94
|
-
return {
|
|
95
|
-
source,
|
|
96
|
-
fetch: fetch.pipe(Effect.mapError(toError)),
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export function assertLiveAccountMatches({
|
|
101
|
-
source,
|
|
102
|
-
account,
|
|
103
|
-
liveUsername,
|
|
104
|
-
liveExternalUserId,
|
|
105
|
-
}: {
|
|
106
|
-
source: string;
|
|
107
|
-
account: LiveSyncAccount;
|
|
108
|
-
liveUsername: string;
|
|
109
|
-
liveExternalUserId?: string;
|
|
110
|
-
}) {
|
|
111
|
-
if (
|
|
112
|
-
account.externalUserId &&
|
|
113
|
-
liveExternalUserId &&
|
|
114
|
-
account.externalUserId === liveExternalUserId
|
|
115
|
-
) {
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
if (account.externalUserId && liveExternalUserId) {
|
|
119
|
-
throw new Error(
|
|
120
|
-
`${source} is authenticated as user ${liveExternalUserId}; refusing to sync into ${account.accountId} (${account.externalUserId})`,
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
if (liveUsername.toLowerCase() !== account.username.toLowerCase()) {
|
|
124
|
-
throw new Error(
|
|
125
|
-
`${source} is authenticated as @${liveUsername}; refusing to sync into ${account.accountId} (@${account.username})`,
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export function normalizeCacheTtlMs(
|
|
131
|
-
value: number | undefined,
|
|
132
|
-
defaultValue: number,
|
|
133
|
-
) {
|
|
134
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
135
|
-
return defaultValue;
|
|
136
|
-
}
|
|
137
|
-
return Math.floor(value);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export function fetchWithTransportFallbackEffect<
|
|
141
|
-
Source extends string,
|
|
142
|
-
Payload,
|
|
143
|
-
>(
|
|
144
|
-
transports: readonly LiveTransportAdapter<Source, Payload>[],
|
|
145
|
-
): Effect.Effect<{ source: Source; payload: Payload }, Error> {
|
|
146
|
-
const [first, ...rest] = transports;
|
|
147
|
-
if (!first) {
|
|
148
|
-
return Effect.fail(new Error("No live transport adapters configured"));
|
|
149
|
-
}
|
|
150
|
-
return first.fetch.pipe(
|
|
151
|
-
Effect.map((payload) => ({ source: first.source, payload })),
|
|
152
|
-
Effect.catchAll((error) =>
|
|
153
|
-
rest.length > 0
|
|
154
|
-
? fetchWithTransportFallbackEffect(rest)
|
|
155
|
-
: Effect.fail(toError(error)),
|
|
156
|
-
),
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export function runCachedLiveSyncEffect<
|
|
161
|
-
Source extends string,
|
|
162
|
-
Payload,
|
|
163
|
-
Persisted,
|
|
164
|
-
>({
|
|
165
|
-
db,
|
|
166
|
-
cacheKey,
|
|
167
|
-
refresh,
|
|
168
|
-
cacheTtlMs,
|
|
169
|
-
transports,
|
|
170
|
-
persistLive,
|
|
171
|
-
persistCached,
|
|
172
|
-
}: CachedLiveSyncOptions<Source, Payload, Persisted>): Effect.Effect<
|
|
173
|
-
CachedLiveSyncResult<Source, Payload, Persisted>,
|
|
174
|
-
Error
|
|
175
|
-
> {
|
|
176
|
-
return Effect.gen(function* () {
|
|
177
|
-
const cached = yield* Effect.try({
|
|
178
|
-
try: () => readSyncCache<Payload>(cacheKey, db),
|
|
179
|
-
catch: toError,
|
|
180
|
-
});
|
|
181
|
-
const cacheAgeMs = cached
|
|
182
|
-
? Date.now() - new Date(cached.updatedAt).getTime()
|
|
183
|
-
: Number.POSITIVE_INFINITY;
|
|
184
|
-
if (!refresh && cached && cacheAgeMs <= cacheTtlMs) {
|
|
185
|
-
const persisted = persistCached
|
|
186
|
-
? yield* databaseWriteEffect((writeDb) =>
|
|
187
|
-
persistCached(writeDb, cached.value),
|
|
188
|
-
)
|
|
189
|
-
: undefined;
|
|
190
|
-
return {
|
|
191
|
-
source: "cache",
|
|
192
|
-
payload: cached.value,
|
|
193
|
-
persisted,
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const fetched = yield* fetchWithTransportFallbackEffect(transports);
|
|
198
|
-
const persisted = yield* databaseWriteEffect((writeDb) => {
|
|
199
|
-
const value = persistLive(writeDb, fetched.payload, fetched.source);
|
|
200
|
-
writeSyncCache(cacheKey, fetched.payload, writeDb);
|
|
201
|
-
return value;
|
|
202
|
-
});
|
|
203
|
-
return {
|
|
204
|
-
source: fetched.source,
|
|
205
|
-
payload: fetched.payload,
|
|
206
|
-
persisted,
|
|
207
|
-
};
|
|
208
|
-
});
|
|
209
|
-
}
|
|
@@ -1,128 +0,0 @@
|
|
|
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
|
-
};
|
package/src/lib/location.ts
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
const COMBINING_DIACRITIC_PATTERN = /[\u0300-\u036f]/g;
|
|
2
|
-
const COLLAPSED_WHITESPACE_PATTERN = /\s+/g;
|
|
3
|
-
const COORDINATE_CAPTURE_PATTERN =
|
|
4
|
-
/^\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*$/;
|
|
5
|
-
const LETTER_PATTERN = /[a-z]/i;
|
|
6
|
-
const URL_OR_HANDLE_PATTERN = /(https?:\/\/|@|[A-Z0-9._%+-]+@[A-Z0-9.-]+)/i;
|
|
7
|
-
const MONEY_PATTERN = /\$\s?\d/;
|
|
8
|
-
const EMOJI_BLOCK_PATTERN =
|
|
9
|
-
/[\u{1f1e6}-\u{1f1ff}\u{1f300}-\u{1faff}\u{2600}-\u{27bf}]/gu;
|
|
10
|
-
|
|
11
|
-
const GENERIC_LOCATIONS = new Set([
|
|
12
|
-
"earth",
|
|
13
|
-
"everywhere",
|
|
14
|
-
"internet",
|
|
15
|
-
"milky way",
|
|
16
|
-
"n/a",
|
|
17
|
-
"na",
|
|
18
|
-
"none",
|
|
19
|
-
"null",
|
|
20
|
-
"online",
|
|
21
|
-
"somewhere",
|
|
22
|
-
"space",
|
|
23
|
-
"the internet",
|
|
24
|
-
"the world",
|
|
25
|
-
"undefined",
|
|
26
|
-
"world",
|
|
27
|
-
"world wide web",
|
|
28
|
-
]);
|
|
29
|
-
|
|
30
|
-
const DROP_WORDS = new Set([
|
|
31
|
-
"a",
|
|
32
|
-
"an",
|
|
33
|
-
"and",
|
|
34
|
-
"anywhere",
|
|
35
|
-
"around",
|
|
36
|
-
"at",
|
|
37
|
-
"between",
|
|
38
|
-
"by",
|
|
39
|
-
"everywhere",
|
|
40
|
-
"global",
|
|
41
|
-
"here",
|
|
42
|
-
"in",
|
|
43
|
-
"inside",
|
|
44
|
-
"my",
|
|
45
|
-
"near",
|
|
46
|
-
"nearby",
|
|
47
|
-
"of",
|
|
48
|
-
"on",
|
|
49
|
-
"remote",
|
|
50
|
-
"somewhere",
|
|
51
|
-
"the",
|
|
52
|
-
"there",
|
|
53
|
-
"where",
|
|
54
|
-
"worldwide",
|
|
55
|
-
]);
|
|
56
|
-
|
|
57
|
-
const NON_LOCATION_PHRASES = [
|
|
58
|
-
/\b(check(out)? my|follow me|newsletter|subscribe|readers)\b/i,
|
|
59
|
-
/\b(in my (own )?head|right behind you|on my computer)\b/i,
|
|
60
|
-
/\b(dev\/null|dev null|xcode|vim|screen|framebuffer)\b/i,
|
|
61
|
-
/\b(blockchain|metaverse|omniverse|hyperamerica)\b/i,
|
|
62
|
-
];
|
|
63
|
-
|
|
64
|
-
function parseCoordinatesFromString(input: string) {
|
|
65
|
-
const match = input.match(COORDINATE_CAPTURE_PATTERN);
|
|
66
|
-
if (!match) return null;
|
|
67
|
-
const lat = Number(match[1]);
|
|
68
|
-
const lng = Number(match[2]);
|
|
69
|
-
if (!Number.isFinite(lat) || !Number.isFinite(lng)) return null;
|
|
70
|
-
if (lat < -90 || lat > 90 || lng < -180 || lng > 180) return null;
|
|
71
|
-
return { lat, lng };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function stripJunkWords(part: string) {
|
|
75
|
-
const words = part
|
|
76
|
-
.split(" ")
|
|
77
|
-
.map((word) => word.trim())
|
|
78
|
-
.filter((word) => word.length > 0);
|
|
79
|
-
const kept = words.filter((word) => !DROP_WORDS.has(word));
|
|
80
|
-
return kept.join(" ").replace(COLLAPSED_WHITESPACE_PATTERN, " ").trim();
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function normalizeLocationKey(input: string): string {
|
|
84
|
-
const raw = String(input || "").trim();
|
|
85
|
-
if (!raw) return "";
|
|
86
|
-
|
|
87
|
-
if (URL_OR_HANDLE_PATTERN.test(raw) || MONEY_PATTERN.test(raw)) return "";
|
|
88
|
-
for (const pattern of NON_LOCATION_PHRASES) {
|
|
89
|
-
if (pattern.test(raw)) return "";
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const coords = parseCoordinatesFromString(raw);
|
|
93
|
-
if (coords) {
|
|
94
|
-
return `coords:${Number(coords.lat.toFixed(6))},${Number(
|
|
95
|
-
coords.lng.toFixed(6),
|
|
96
|
-
)}`;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
let value = raw
|
|
100
|
-
.toLowerCase()
|
|
101
|
-
.normalize("NFKD")
|
|
102
|
-
.replace(COMBINING_DIACRITIC_PATTERN, "")
|
|
103
|
-
.replace(EMOJI_BLOCK_PATTERN, "")
|
|
104
|
-
.replace(/[|;]+/g, ",")
|
|
105
|
-
.replace(/\s+(?:and|or|\/|-)\s+/g, ",")
|
|
106
|
-
.replace(/[\\/]+/g, ",")
|
|
107
|
-
.replace(/[“”"']/g, "")
|
|
108
|
-
.replace(COLLAPSED_WHITESPACE_PATTERN, " ")
|
|
109
|
-
.replace(/\s*,\s*/g, ",")
|
|
110
|
-
.replace(/,+/g, ",")
|
|
111
|
-
.replace(/[^a-z0-9, .-]/g, "")
|
|
112
|
-
.replace(/^[,\s.-]+|[,\s.-]+$/g, "");
|
|
113
|
-
|
|
114
|
-
if (!value || GENERIC_LOCATIONS.has(value)) return "";
|
|
115
|
-
|
|
116
|
-
const parts = value
|
|
117
|
-
.split(",")
|
|
118
|
-
.map((part) => stripJunkWords(part.trim()))
|
|
119
|
-
.filter((part) => part.length > 0 && !GENERIC_LOCATIONS.has(part));
|
|
120
|
-
|
|
121
|
-
value = parts.join(",");
|
|
122
|
-
if (!value || GENERIC_LOCATIONS.has(value)) return "";
|
|
123
|
-
return value.length <= 100 ? value : "";
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export function isMeaningfulLocation(input: string): boolean {
|
|
127
|
-
const key = normalizeLocationKey(input);
|
|
128
|
-
if (!key) return false;
|
|
129
|
-
if (key.startsWith("coords:")) return true;
|
|
130
|
-
return LETTER_PATTERN.test(key) && key.length >= 2 && key.length <= 100;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export function coordinatesFromLocationKey(key: string) {
|
|
134
|
-
if (!key.startsWith("coords:")) return null;
|
|
135
|
-
const parsed = parseCoordinatesFromString(key.slice("coords:".length));
|
|
136
|
-
return parsed ? { ...parsed, provider: "coords" as const } : null;
|
|
137
|
-
}
|