birdclaw 0.8.3 → 0.8.5

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.
Files changed (284) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +10 -8
  3. package/bin/birdclaw.mjs +4 -66
  4. package/dist/cli/birdclaw.js +28164 -0
  5. package/dist/client/assets/AvatarChip-DLoqM5xD.js +1 -0
  6. package/dist/client/assets/ProfilePreview-DQX6_xc3.js +1 -0
  7. package/dist/client/assets/SavedTimelineView-BhSiVyR1.js +1 -0
  8. package/dist/client/assets/SmartTimestamp-BR0-9se2.js +1 -0
  9. package/dist/client/assets/TimelineRouteFrame-9NDLnXzH.js +1 -0
  10. package/dist/client/assets/blocks-CFp_njvG.js +1 -0
  11. package/dist/client/assets/bookmarks-LbYOsoKf.js +1 -0
  12. package/dist/client/assets/chunk-C0phanGV.js +1 -0
  13. package/dist/client/assets/circle-check-C_Vq3ElD.js +1 -0
  14. package/dist/client/assets/client-stream-contracts-sR4xMQxY.js +5 -0
  15. package/dist/client/assets/createLucideIcon-JV8isFFR.js +1 -0
  16. package/dist/client/assets/data-sources-euTr6T_L.js +1 -0
  17. package/dist/client/assets/discuss-BWKu_p7B.js +1 -0
  18. package/dist/client/assets/dms-SLXMtC4v.js +1 -0
  19. package/dist/client/assets/inbox-BybSI5Vf.js +1 -0
  20. package/dist/client/assets/index-DZVisyna.js +31 -0
  21. package/dist/client/assets/index-bpFrQ5yG.css +1 -0
  22. package/dist/client/assets/likes-dyh9p8y_.js +1 -0
  23. package/dist/client/assets/links-CIwqK_dX.js +1 -0
  24. package/dist/client/assets/mapbox-B4zqX7r0.js +2 -0
  25. package/dist/client/assets/mapbox-gl-DYNcLcll.js +3215 -0
  26. package/dist/client/assets/mentions-BoVVAIT7.js +1 -0
  27. package/dist/client/assets/network-map-zRysIY_b.js +2 -0
  28. package/dist/client/assets/profile-analyze-C_yDeX6-.js +1 -0
  29. package/dist/client/assets/profile-hydration-client-YEtJsNTv.js +1 -0
  30. package/dist/client/assets/profiles._handle-DdIVPqU-.js +1 -0
  31. package/dist/client/assets/query-client-fYu2rzRC.js +17 -0
  32. package/dist/client/assets/rate-limits-BWPmPOSh.js +1 -0
  33. package/dist/client/assets/react-dom-DHl6Ug7F.js +1 -0
  34. package/dist/client/assets/react-nBylq1U5.js +1 -0
  35. package/dist/client/assets/repeat-2-xCwHM9hD.js +1 -0
  36. package/dist/client/assets/routes-CiLuYpZr.js +1 -0
  37. package/dist/client/assets/schemas-I9r6F6ya.js +64 -0
  38. package/dist/client/assets/search-Dq5kYsxA.js +1 -0
  39. package/dist/client/assets/sparkles-CQVlvHsZ.js +1 -0
  40. package/dist/client/assets/styles-B8s3tt3r.css +2 -0
  41. package/dist/client/assets/today-BoO64YoY.js +1 -0
  42. package/dist/client/assets/triangle-alert-CBL7s2pf.js +1 -0
  43. package/dist/client/assets/useTimelineRouteData-BaO3Rna1.js +1 -0
  44. package/dist/client/assets/users-CHbKlqUr.js +1 -0
  45. package/dist/server/assets/AvatarChip-zUDAEmjL.js +105 -0
  46. package/dist/server/assets/FeedState-ntW0Q2GB.js +214 -0
  47. package/dist/server/assets/ProfileAnalysisStream-L7bs6IHH.js +198 -0
  48. package/dist/server/assets/ProfilePreview-Cg-AOHBE.js +751 -0
  49. package/dist/server/assets/SavedTimelineView-BtCq1dHk.js +64 -0
  50. package/dist/server/assets/SmartTimestamp-DfwE1NGf.js +45 -0
  51. package/dist/server/assets/SyncNowButton-BOn_IBXS.js +76 -0
  52. package/dist/server/assets/TimelineRouteFrame-CjMIh63G.js +85 -0
  53. package/dist/server/assets/TweetRichText-DDywESRF.js +74 -0
  54. package/dist/server/assets/_tanstack-start-manifest_v-aLWUdbAc.js +148 -0
  55. package/dist/server/assets/account-selection-CTdFGWRk.js +44 -0
  56. package/dist/server/assets/blocks-C1mgGTB3.js +299 -0
  57. package/dist/server/assets/blocks-DSgQghqP.js +17 -0
  58. package/dist/server/assets/bookmarks-D_YkmCK3.js +14 -0
  59. package/dist/server/assets/client-stream-contracts-Bq6kMmhh.js +769 -0
  60. package/dist/server/assets/data-sources-BnA1Q94p.js +180 -0
  61. package/dist/server/assets/discuss-C1QMBBSk.js +338 -0
  62. package/dist/server/assets/discuss-DAq6ehL9.js +15 -0
  63. package/dist/server/assets/dms-BuLj4bp8.js +368 -0
  64. package/dist/server/assets/dms-DAyQrVM2.js +240 -0
  65. package/dist/server/assets/empty-plugin-adapters-DzrEkdBF.js +5 -0
  66. package/dist/server/assets/inbox-CkGOaW1q.js +214 -0
  67. package/dist/server/assets/inbox-DpWd1EzC.js +146 -0
  68. package/dist/server/assets/likes-BMm2JWYI.js +14 -0
  69. package/dist/server/assets/links-Da4tjWtI.js +468 -0
  70. package/dist/server/assets/links-dqXb35YM.js +240 -0
  71. package/dist/server/assets/mentions-CEyEcOFw.js +26 -0
  72. package/dist/server/assets/network-map-D3CzRcC4.js +224 -0
  73. package/dist/server/assets/network-map-D5DoLOwR.js +582 -0
  74. package/dist/server/assets/profile-analyze-CGCj4VFd.js +90 -0
  75. package/dist/server/assets/profile-analyze-DH1TSBkT.js +9 -0
  76. package/dist/server/assets/profile-hydration-client-GJ4kwJS8.js +133 -0
  77. package/dist/server/assets/profiles._handle-B5V-huoo.js +12 -0
  78. package/dist/server/assets/profiles._handle-CJ6rgzt8.js +184 -0
  79. package/dist/server/assets/query-client-BdauHBgd.js +923 -0
  80. package/dist/server/assets/rate-limits-VAr2qzYD.js +262 -0
  81. package/dist/server/assets/route-search-BUlQ5lGM.js +117 -0
  82. package/dist/server/assets/router-C4cz9ypd.js +17026 -0
  83. package/dist/server/assets/routes-B9aikOdB.js +26 -0
  84. package/dist/server/assets/start-FaDOTmto.js +4 -0
  85. package/dist/server/assets/today-B_TA16QG.js +303 -0
  86. package/dist/server/assets/today-JkxZXdBt.js +17 -0
  87. package/dist/server/assets/ui-qbmcMSSX.js +137 -0
  88. package/{src/components/useDebouncedValue.ts → dist/server/assets/useDebouncedValue-DOnA6Xcy.js} +4 -4
  89. package/dist/server/assets/useTimelineRouteData-BLXvMGb2.js +1101 -0
  90. package/dist/server/server.js +5520 -0
  91. package/package.json +26 -34
  92. package/playwright.config.ts +0 -35
  93. package/scripts/browser-perf.mjs +0 -427
  94. package/scripts/build-docs-site.mjs +0 -967
  95. package/scripts/docs-site-assets.mjs +0 -311
  96. package/scripts/run-vitest.mjs +0 -21
  97. package/scripts/sanitize-node-options.mjs +0 -23
  98. package/scripts/start-test-server.mjs +0 -42
  99. package/src/cli/command-context.ts +0 -17
  100. package/src/cli/register-analysis.ts +0 -500
  101. package/src/cli/register-compose.ts +0 -40
  102. package/src/cli/register-graph.ts +0 -132
  103. package/src/cli/register-inbox.ts +0 -41
  104. package/src/cli/register-storage.ts +0 -106
  105. package/src/cli-moderation.ts +0 -210
  106. package/src/cli.ts +0 -1616
  107. package/src/components/AccountSwitcher.tsx +0 -178
  108. package/src/components/AppNav.tsx +0 -118
  109. package/src/components/AvatarChip.tsx +0 -58
  110. package/src/components/AvatarPreload.ts +0 -149
  111. package/src/components/BrandMark.tsx +0 -67
  112. package/src/components/ConversationThread.tsx +0 -131
  113. package/src/components/DmWorkspace.tsx +0 -286
  114. package/src/components/EmbeddedTweetCard.tsx +0 -55
  115. package/src/components/FeedState.tsx +0 -147
  116. package/src/components/FloatingPreview.tsx +0 -382
  117. package/src/components/InboxCard.tsx +0 -152
  118. package/src/components/LinkPreviewCard.tsx +0 -292
  119. package/src/components/MarkdownCitations.tsx +0 -680
  120. package/src/components/MarkdownViewer.tsx +0 -111
  121. package/src/components/ProfileAnalysisClient.ts +0 -191
  122. package/src/components/ProfileAnalysisStream.tsx +0 -259
  123. package/src/components/ProfilePreview.tsx +0 -131
  124. package/src/components/SavedTimelineView.tsx +0 -155
  125. package/src/components/SmartTimestamp.tsx +0 -72
  126. package/src/components/SyncNowButton.tsx +0 -140
  127. package/src/components/ThemeSlider.tsx +0 -80
  128. package/src/components/TimelineCard.tsx +0 -533
  129. package/src/components/TimelineRouteFrame.tsx +0 -186
  130. package/src/components/TweetArticleCard.tsx +0 -66
  131. package/src/components/TweetMediaGrid.tsx +0 -185
  132. package/src/components/TweetRichText.tsx +0 -159
  133. package/src/components/account-selection.ts +0 -64
  134. package/src/components/links-controller.ts +0 -162
  135. package/src/components/links-model.ts +0 -198
  136. package/src/components/network-map-controller.ts +0 -84
  137. package/src/components/network-map-model.ts +0 -255
  138. package/src/components/useTimelineRouteData.ts +0 -193
  139. package/src/lib/account-sync-job.ts +0 -666
  140. package/src/lib/actions-transport.ts +0 -300
  141. package/src/lib/analysis-runtime.ts +0 -238
  142. package/src/lib/api-client.ts +0 -220
  143. package/src/lib/api-contracts.ts +0 -328
  144. package/src/lib/archive-finder.ts +0 -185
  145. package/src/lib/archive-import-plan.ts +0 -102
  146. package/src/lib/archive-import.ts +0 -2695
  147. package/src/lib/authored-live.ts +0 -1027
  148. package/src/lib/avatar-cache.ts +0 -349
  149. package/src/lib/backup.ts +0 -2652
  150. package/src/lib/bird-actions.ts +0 -294
  151. package/src/lib/bird-command.ts +0 -130
  152. package/src/lib/bird.ts +0 -1140
  153. package/src/lib/blocklist.ts +0 -136
  154. package/src/lib/blocks-write.ts +0 -171
  155. package/src/lib/blocks.ts +0 -387
  156. package/src/lib/bookmark-sync-job.ts +0 -536
  157. package/src/lib/config.ts +0 -224
  158. package/src/lib/conversation-surface.ts +0 -205
  159. package/src/lib/data-sources.ts +0 -219
  160. package/src/lib/database-metrics.ts +0 -88
  161. package/src/lib/database-migrations.ts +0 -34
  162. package/src/lib/database-schema.ts +0 -312
  163. package/src/lib/database-writer.ts +0 -69
  164. package/src/lib/db.ts +0 -889
  165. package/src/lib/dm-read-model.ts +0 -533
  166. package/src/lib/dms-live.ts +0 -870
  167. package/src/lib/effect-runtime.ts +0 -45
  168. package/src/lib/follow-graph.ts +0 -1087
  169. package/src/lib/geocoding.ts +0 -296
  170. package/src/lib/http-effect.ts +0 -222
  171. package/src/lib/identity-search-index.ts +0 -369
  172. package/src/lib/import-repository.ts +0 -138
  173. package/src/lib/inbox.ts +0 -242
  174. package/src/lib/link-index.ts +0 -641
  175. package/src/lib/link-insights.ts +0 -860
  176. package/src/lib/link-preview-metadata.ts +0 -754
  177. package/src/lib/live-sync-engine.ts +0 -209
  178. package/src/lib/live-transport-gateway.ts +0 -128
  179. package/src/lib/location.ts +0 -137
  180. package/src/lib/media-fetch.ts +0 -860
  181. package/src/lib/media-includes.ts +0 -165
  182. package/src/lib/mention-threads-live.ts +0 -830
  183. package/src/lib/mentions-export.ts +0 -147
  184. package/src/lib/mentions-live.ts +0 -1114
  185. package/src/lib/moderation-target.ts +0 -227
  186. package/src/lib/moderation-write.ts +0 -131
  187. package/src/lib/mutes-write.ts +0 -171
  188. package/src/lib/mutes.ts +0 -84
  189. package/src/lib/ndjson-stream.ts +0 -106
  190. package/src/lib/network-map.ts +0 -382
  191. package/src/lib/openai-response-runtime.ts +0 -251
  192. package/src/lib/openai.ts +0 -117
  193. package/src/lib/paginated-sync.ts +0 -93
  194. package/src/lib/period-digest.ts +0 -1364
  195. package/src/lib/present.ts +0 -118
  196. package/src/lib/profile-affiliation-hydration.ts +0 -228
  197. package/src/lib/profile-affiliations.ts +0 -262
  198. package/src/lib/profile-analysis.ts +0 -1198
  199. package/src/lib/profile-bio-entities.ts +0 -318
  200. package/src/lib/profile-history.ts +0 -164
  201. package/src/lib/profile-hydration.ts +0 -180
  202. package/src/lib/profile-replies.ts +0 -77
  203. package/src/lib/profile-resolver.ts +0 -650
  204. package/src/lib/queries.ts +0 -6
  205. package/src/lib/query-actions.ts +0 -437
  206. package/src/lib/query-client.tsx +0 -47
  207. package/src/lib/query-read-model-shared.ts +0 -52
  208. package/src/lib/query-read-models.ts +0 -5
  209. package/src/lib/query-resource.ts +0 -41
  210. package/src/lib/query-status.ts +0 -164
  211. package/src/lib/research.ts +0 -652
  212. package/src/lib/runtime-services.ts +0 -20
  213. package/src/lib/search-discussion.ts +0 -812
  214. package/src/lib/seed.ts +0 -613
  215. package/src/lib/server-runtime-services.ts +0 -30
  216. package/src/lib/sqlite.ts +0 -183
  217. package/src/lib/streaming-ingestion.ts +0 -240
  218. package/src/lib/sync-cache.ts +0 -70
  219. package/src/lib/sync-plan.ts +0 -175
  220. package/src/lib/theme-transition.ts +0 -113
  221. package/src/lib/theme.tsx +0 -165
  222. package/src/lib/timeline-collections-live.ts +0 -407
  223. package/src/lib/timeline-live.ts +0 -302
  224. package/src/lib/timeline-read-model.ts +0 -1191
  225. package/src/lib/tweet-account-edges.ts +0 -48
  226. package/src/lib/tweet-lookup.ts +0 -46
  227. package/src/lib/tweet-render.ts +0 -430
  228. package/src/lib/tweet-repository.ts +0 -156
  229. package/src/lib/tweet-search-live.ts +0 -462
  230. package/src/lib/types.ts +0 -723
  231. package/src/lib/ui.ts +0 -529
  232. package/src/lib/url-expansion-store.ts +0 -110
  233. package/src/lib/url-expansion.ts +0 -343
  234. package/src/lib/url-safety.ts +0 -220
  235. package/src/lib/web-sync.ts +0 -533
  236. package/src/lib/whois.ts +0 -1080
  237. package/src/lib/x-profile.ts +0 -365
  238. package/src/lib/x-web.ts +0 -199
  239. package/src/lib/xurl-rate-limits.ts +0 -267
  240. package/src/lib/xurl.ts +0 -1677
  241. package/src/routeTree.gen.ts +0 -723
  242. package/src/router.tsx +0 -20
  243. package/src/routes/__root.tsx +0 -82
  244. package/src/routes/api/action.tsx +0 -147
  245. package/src/routes/api/avatar.tsx +0 -50
  246. package/src/routes/api/blocks.tsx +0 -35
  247. package/src/routes/api/conversation.tsx +0 -45
  248. package/src/routes/api/data-sources.tsx +0 -24
  249. package/src/routes/api/inbox.tsx +0 -43
  250. package/src/routes/api/link-insights.tsx +0 -85
  251. package/src/routes/api/link-preview.tsx +0 -47
  252. package/src/routes/api/network-map.tsx +0 -55
  253. package/src/routes/api/period-digest.tsx +0 -101
  254. package/src/routes/api/profile-analysis.tsx +0 -97
  255. package/src/routes/api/profile-hydrate.tsx +0 -54
  256. package/src/routes/api/query.tsx +0 -121
  257. package/src/routes/api/search-discussion.tsx +0 -113
  258. package/src/routes/api/status.tsx +0 -30
  259. package/src/routes/api/sync.tsx +0 -108
  260. package/src/routes/api/xurl-rate-limits.tsx +0 -24
  261. package/src/routes/blocks.tsx +0 -343
  262. package/src/routes/bookmarks.tsx +0 -18
  263. package/src/routes/data-sources.tsx +0 -249
  264. package/src/routes/discuss.tsx +0 -419
  265. package/src/routes/dms.tsx +0 -415
  266. package/src/routes/inbox.tsx +0 -232
  267. package/src/routes/index.tsx +0 -32
  268. package/src/routes/likes.tsx +0 -18
  269. package/src/routes/links.tsx +0 -631
  270. package/src/routes/mentions.tsx +0 -32
  271. package/src/routes/network-map.tsx +0 -732
  272. package/src/routes/profile-analyze.tsx +0 -112
  273. package/src/routes/profiles.$handle.tsx +0 -228
  274. package/src/routes/rate-limits.tsx +0 -305
  275. package/src/routes/today.tsx +0 -511
  276. package/src/styles.css +0 -257
  277. package/tsconfig.json +0 -29
  278. package/vite.config.ts +0 -29
  279. /package/{public → dist/client}/birdclaw-mark.png +0 -0
  280. /package/{public → dist/client}/favicon.ico +0 -0
  281. /package/{public → dist/client}/logo192.png +0 -0
  282. /package/{public → dist/client}/logo512.png +0 -0
  283. /package/{public → dist/client}/manifest.json +0 -0
  284. /package/{public → dist/client}/robots.txt +0 -0
@@ -0,0 +1,26 @@
1
+ import { t as TimelineRouteFrame } from "./TimelineRouteFrame-CjMIh63G.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/routes/index.tsx?tsr-split=component
4
+ function homeSubtitle(meta) {
5
+ if (!meta) return "Loading local context...";
6
+ return `${String(meta.stats.home)} items · ${String(meta.stats.needsReply)} waiting · ${meta.transport.statusText}`;
7
+ }
8
+ function HomeRoute() {
9
+ return /* @__PURE__ */ jsx(TimelineRouteFrame, {
10
+ emptyDetail: "Try a different filter or sync the timeline again.",
11
+ emptyLabel: "No posts in this view",
12
+ errorFallback: "Timeline unavailable",
13
+ errorTitle: "Could not load posts",
14
+ initialReplyFilter: "all",
15
+ loadingDetail: "Reading the local timeline store",
16
+ loadingLabel: "Loading posts",
17
+ resource: "home",
18
+ searchPlaceholder: "Search local timeline",
19
+ subtitle: homeSubtitle,
20
+ syncKind: "timeline",
21
+ syncLabel: "Sync timeline",
22
+ title: "Home"
23
+ });
24
+ }
25
+ //#endregion
26
+ export { HomeRoute as component };
@@ -0,0 +1,4 @@
1
+ //#region node_modules/.pnpm/@tanstack+react-start@1.168.26_react-dom@19.2.7_react@19.2.7__react@19.2.7_vite@8.0.16__465b94eb4096202468ea7bb8157eb6f6/node_modules/@tanstack/react-start/dist/plugin/default-entry/start.ts
2
+ var startInstance = void 0;
3
+ //#endregion
4
+ export { startInstance };
@@ -0,0 +1,303 @@
1
+ import { Dt as pageSubtitleClass, Et as pageHeaderRowClass, Kt as segmentClass, Ot as pageTitleClass, Tt as pageHeaderClass, Wt as secondaryButtonClass, m as cx, q as errorCopyClass, qt as segmentedClass, wt as pageHeaderActionsClass } from "./ui-qbmcMSSX.js";
2
+ import { a as useNdjsonRun, n as periodDigestStreamEventSchema, o as MarkdownViewer, t as isTerminalStreamEvent } from "./client-stream-contracts-Bq6kMmhh.js";
3
+ import { n as normalizeProfileHydrationHandle, t as hydrateProfileHandles } from "./profile-hydration-client-GJ4kwJS8.js";
4
+ import { s as validateTodaySearch } from "./route-search-BUlQ5lGM.js";
5
+ import { t as Route$1 } from "./today-JkxZXdBt.js";
6
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { CheckCircle2, Loader2, RefreshCw, Sparkles } from "lucide-react";
9
+ import { useQueryClient } from "@tanstack/react-query";
10
+ //#region src/routes/today.tsx?tsr-split=component
11
+ var PROFILE_HYDRATION_LIMIT = 12;
12
+ var PROFILE_HYDRATION_DELAY_MS = 300;
13
+ var DIGEST_STATUS_MESSAGES = { 524: "Digest startup timed out at Cloudflare (524). Retry to open a new stream." };
14
+ var periods = [
15
+ {
16
+ value: "today",
17
+ label: "Today"
18
+ },
19
+ {
20
+ value: "24h",
21
+ label: "24h"
22
+ },
23
+ {
24
+ value: "yesterday",
25
+ label: "Yesterday"
26
+ },
27
+ {
28
+ value: "week",
29
+ label: "Week"
30
+ }
31
+ ];
32
+ function digestUrl(period, includeDms, refresh) {
33
+ const url = new URL("/api/period-digest", window.location.origin);
34
+ url.searchParams.set("period", period);
35
+ url.searchParams.set("includeDms", String(includeDms));
36
+ url.searchParams.set("maxTweets", "5000");
37
+ url.searchParams.set("maxLinks", "20");
38
+ url.searchParams.set("liveSync", "false");
39
+ if (refresh) url.searchParams.set("refresh", "true");
40
+ return url;
41
+ }
42
+ function digestStreamError(cause, phase) {
43
+ const message = cause instanceof Error ? cause.message : String(cause);
44
+ if (cause instanceof TypeError && /network error|failed to fetch|load failed/i.test(message)) return `Digest connection was interrupted while ${phase.toLowerCase()}. Retry to continue.`;
45
+ if (cause instanceof SyntaxError) return `Digest stream returned invalid data while ${phase.toLowerCase()}. Retry to continue.`;
46
+ return message || "Digest failed";
47
+ }
48
+ function formatCounts(context) {
49
+ if (!context) return "Local Twitter memory, summarized as it streams.";
50
+ const counts = context.counts;
51
+ return [
52
+ `${String(counts.home)} home`,
53
+ `${String(counts.mentions)} mentions`,
54
+ `${String(counts.links)} links`,
55
+ context.includeDms ? `${String(counts.dms)} DMs` : null
56
+ ].filter(Boolean).join(" · ");
57
+ }
58
+ function collectProfilesForHydration(result) {
59
+ const handles = /* @__PURE__ */ new Set();
60
+ const tweetIds = /* @__PURE__ */ new Set();
61
+ for (const id of result.digest.sourceTweetIds) tweetIds.add(id);
62
+ for (const topic of result.digest.keyTopics) for (const id of topic.tweetIds) tweetIds.add(id);
63
+ for (const link of result.digest.notableLinks) for (const id of link.sourceTweetIds) tweetIds.add(id);
64
+ for (const item of result.digest.actionItems) if (item.tweetId) tweetIds.add(item.tweetId);
65
+ const tweetsById = new Map(result.context.tweets.flatMap((tweet) => [[tweet.id, tweet], [`tweet_${tweet.id}`, tweet]]));
66
+ for (const id of tweetIds) {
67
+ const tweet = tweetsById.get(id);
68
+ if (!tweet) continue;
69
+ const handle = normalizeProfileHydrationHandle(tweet.author);
70
+ if (handle) handles.add(handle);
71
+ }
72
+ for (const tweet of result.context.tweets) {
73
+ const handle = normalizeProfileHydrationHandle(tweet.author);
74
+ if (handle) handles.add(handle);
75
+ }
76
+ return [...handles];
77
+ }
78
+ function applyHydratedProfilesToContext(context, profilesByHandle) {
79
+ let changed = false;
80
+ const tweets = context.tweets.map((tweet) => {
81
+ const profile = profilesByHandle.get(normalizeProfileHydrationHandle(tweet.author));
82
+ if (!profile || profile === tweet.authorProfile) return tweet;
83
+ changed = true;
84
+ return {
85
+ ...tweet,
86
+ author: profile.handle,
87
+ name: profile.displayName,
88
+ authorProfile: profile
89
+ };
90
+ });
91
+ return changed ? {
92
+ ...context,
93
+ tweets
94
+ } : context;
95
+ }
96
+ function applyHydratedProfilesToResult(result, profiles) {
97
+ const profilesByHandle = new Map(profiles.map((profile) => [normalizeProfileHydrationHandle(profile.handle), profile]));
98
+ if (profilesByHandle.size === 0) return result;
99
+ const context = applyHydratedProfilesToContext(result.context, profilesByHandle);
100
+ return context === result.context ? result : {
101
+ ...result,
102
+ context
103
+ };
104
+ }
105
+ function useDigestStream(period, includeDms) {
106
+ const queryClient = useQueryClient();
107
+ const [markdown, setMarkdown] = useState("");
108
+ const [context, setContext] = useState(null);
109
+ const [result, setResult] = useState(null);
110
+ const [status, setStatus] = useState("Starting digest");
111
+ const latestStatusRef = useRef("Starting digest");
112
+ const onStart = useCallback(() => {
113
+ setMarkdown("");
114
+ setContext(null);
115
+ setResult(null);
116
+ setStatus("Starting digest");
117
+ latestStatusRef.current = "Starting digest";
118
+ }, []);
119
+ const { error, loading, run } = useNdjsonRun({
120
+ schema: periodDigestStreamEventSchema,
121
+ request: useCallback((signal, refresh) => fetch(digestUrl(period, includeDms, refresh), {
122
+ cache: "no-store",
123
+ signal
124
+ }), [includeDms, period]),
125
+ onStart,
126
+ onEvent: useCallback((event) => {
127
+ if (event.type === "status") {
128
+ latestStatusRef.current = event.detail ? `${event.label} · ${event.detail}` : event.label;
129
+ setStatus(latestStatusRef.current);
130
+ } else if (event.type === "start") setContext(event.context);
131
+ else if (event.type === "delta") {
132
+ latestStatusRef.current = "Streaming AI summary";
133
+ setStatus(latestStatusRef.current);
134
+ setMarkdown((current) => current + event.delta);
135
+ } else if (event.type === "done") {
136
+ setResult(event.result);
137
+ setContext(event.result.context);
138
+ setMarkdown(event.result.markdown);
139
+ setStatus(event.result.cached ? "Loaded cached report" : "Ready");
140
+ } else if (event.type === "error") throw new Error(event.error);
141
+ }, []),
142
+ onError: useCallback(() => setStatus("Digest failed"), []),
143
+ isTerminal: isTerminalStreamEvent,
144
+ errorLabel: "Digest request failed",
145
+ emptyBodyMessage: "Digest request failed: empty response body",
146
+ prematureEofError: useCallback(() => /* @__PURE__ */ new Error(`Digest connection closed while ${latestStatusRef.current.toLowerCase()}. Retry to continue.`), []),
147
+ formatError: useCallback((cause) => digestStreamError(cause, latestStatusRef.current), []),
148
+ statusMessages: DIGEST_STATUS_MESSAGES
149
+ });
150
+ useEffect(() => {
151
+ run(false);
152
+ }, [run]);
153
+ useEffect(() => {
154
+ if (!result) return;
155
+ const handles = collectProfilesForHydration(result);
156
+ if (handles.length === 0) return;
157
+ let active = true;
158
+ let idleId = null;
159
+ const runHydration = () => {
160
+ hydrateProfileHandles(queryClient, handles, { limit: PROFILE_HYDRATION_LIMIT }).then((response) => {
161
+ if (!active) return;
162
+ const { profiles } = response;
163
+ if (profiles.length === 0) return;
164
+ setResult((current) => current ? applyHydratedProfilesToResult(current, profiles) : current);
165
+ const profilesByHandle = new Map(profiles.map((profile) => [normalizeProfileHydrationHandle(profile.handle), profile]));
166
+ setContext((current) => current ? applyHydratedProfilesToContext(current, profilesByHandle) : current);
167
+ }).catch((error) => {
168
+ if (!active) return;
169
+ console.warn("Profile hydration failed", error);
170
+ });
171
+ };
172
+ const timer = window.setTimeout(() => {
173
+ if ("requestIdleCallback" in window) idleId = window.requestIdleCallback(runHydration, { timeout: 2500 });
174
+ else runHydration();
175
+ }, PROFILE_HYDRATION_DELAY_MS);
176
+ return () => {
177
+ active = false;
178
+ window.clearTimeout(timer);
179
+ if (idleId !== null && "cancelIdleCallback" in window) window.cancelIdleCallback(idleId);
180
+ };
181
+ }, [queryClient, result]);
182
+ return {
183
+ context,
184
+ error,
185
+ loading,
186
+ markdown,
187
+ result,
188
+ run,
189
+ status
190
+ };
191
+ }
192
+ function TodayRoute() {
193
+ const search = Route$1.useSearch();
194
+ const navigate = Route$1.useNavigate();
195
+ return /* @__PURE__ */ jsx(TodayRouteView, {
196
+ searchState: search,
197
+ onSearchChange: (next, options) => void navigate({
198
+ search: next,
199
+ replace: options?.replace
200
+ })
201
+ });
202
+ }
203
+ function TodayRouteView({ searchState: controlledSearch, onSearchChange } = {}) {
204
+ const [localSearch, setLocalSearch] = useState(() => validateTodaySearch({}));
205
+ const searchState = controlledSearch ?? localSearch;
206
+ const updateSearch = (next, options) => onSearchChange ? onSearchChange(next, options) : setLocalSearch(next);
207
+ const { period, includeDms } = searchState;
208
+ const { context, error, loading, markdown, result, run, status } = useDigestStream(period, includeDms);
209
+ const sourceLabel = useMemo(() => formatCounts(result?.context ?? context), [context, result]);
210
+ return /* @__PURE__ */ jsxs("div", {
211
+ className: "flex min-h-screen flex-col",
212
+ children: [
213
+ /* @__PURE__ */ jsxs("header", {
214
+ className: pageHeaderClass,
215
+ children: [/* @__PURE__ */ jsxs("div", {
216
+ className: pageHeaderRowClass,
217
+ children: [/* @__PURE__ */ jsxs("div", {
218
+ className: "min-w-0",
219
+ children: [/* @__PURE__ */ jsx("h1", {
220
+ className: pageTitleClass,
221
+ children: "What happened"
222
+ }), /* @__PURE__ */ jsx("p", {
223
+ className: pageSubtitleClass,
224
+ children: sourceLabel
225
+ })]
226
+ }), /* @__PURE__ */ jsx("div", {
227
+ className: pageHeaderActionsClass,
228
+ children: /* @__PURE__ */ jsxs("button", {
229
+ type: "button",
230
+ className: secondaryButtonClass,
231
+ onClick: () => run(true),
232
+ disabled: loading,
233
+ children: [/* @__PURE__ */ jsx(RefreshCw, {
234
+ className: cx("size-4", loading && "animate-spin"),
235
+ "aria-hidden": "true"
236
+ }), "Refresh"]
237
+ })
238
+ })]
239
+ }), /* @__PURE__ */ jsxs("div", {
240
+ className: "flex flex-wrap items-center gap-2 px-4 pb-3",
241
+ children: [/* @__PURE__ */ jsx("div", {
242
+ className: segmentedClass,
243
+ "aria-label": "Digest period",
244
+ children: periods.map((item) => /* @__PURE__ */ jsx("button", {
245
+ type: "button",
246
+ className: cx(segmentClass, period === item.value && "bg-[var(--bg-active)] text-[var(--ink)]"),
247
+ onClick: () => updateSearch({
248
+ ...searchState,
249
+ period: item.value
250
+ }),
251
+ children: item.label
252
+ }, item.value))
253
+ }), /* @__PURE__ */ jsxs("label", {
254
+ className: "inline-flex items-center gap-2 rounded-full border border-[var(--line)] px-3 py-1 text-[13px] font-medium text-[var(--ink-soft)]",
255
+ children: [/* @__PURE__ */ jsx("input", {
256
+ type: "checkbox",
257
+ checked: includeDms,
258
+ onChange: (event) => updateSearch({
259
+ ...searchState,
260
+ includeDms: event.currentTarget.checked
261
+ })
262
+ }), "DMs"]
263
+ })]
264
+ })]
265
+ }),
266
+ error ? /* @__PURE__ */ jsxs("div", {
267
+ className: cx(errorCopyClass, "flex items-center justify-between gap-3"),
268
+ role: "alert",
269
+ children: [/* @__PURE__ */ jsx("span", { children: error }), /* @__PURE__ */ jsx("button", {
270
+ className: "shrink-0 font-semibold underline underline-offset-2",
271
+ onClick: () => run(true),
272
+ type: "button",
273
+ children: "Retry"
274
+ })]
275
+ }) : null,
276
+ /* @__PURE__ */ jsx("div", {
277
+ className: "border-b border-[var(--line)] px-4 py-2 text-[13px] text-[var(--ink-soft)]",
278
+ children: /* @__PURE__ */ jsxs("span", {
279
+ className: "inline-flex items-center gap-1",
280
+ children: [loading ? /* @__PURE__ */ jsx(Loader2, {
281
+ className: "size-4 animate-spin",
282
+ "aria-hidden": "true"
283
+ }) : markdown ? /* @__PURE__ */ jsx(CheckCircle2, {
284
+ className: "size-4",
285
+ "aria-hidden": "true"
286
+ }) : /* @__PURE__ */ jsx(Sparkles, {
287
+ className: "size-4",
288
+ "aria-hidden": "true"
289
+ }), loading ? status : result ? `${result.cached ? "Cached" : "Ready"} · ${result.context.window.label}` : error ? "Digest failed" : "Ready"]
290
+ })
291
+ }),
292
+ markdown ? /* @__PURE__ */ jsx(MarkdownViewer, {
293
+ context: result?.context ?? context,
294
+ markdown
295
+ }) : /* @__PURE__ */ jsx("div", {
296
+ className: "px-4 py-5 text-[14px] text-[var(--ink-soft)]",
297
+ children: loading ? status : error ? "No digest was generated. Retry to start a new run." : "Waiting for the first tokens..."
298
+ })
299
+ ]
300
+ });
301
+ }
302
+ //#endregion
303
+ export { TodayRouteView, TodayRoute as component };
@@ -0,0 +1,17 @@
1
+ import "./ui-qbmcMSSX.js";
2
+ import "./client-stream-contracts-Bq6kMmhh.js";
3
+ import "./profile-hydration-client-GJ4kwJS8.js";
4
+ import { s as validateTodaySearch } from "./route-search-BUlQ5lGM.js";
5
+ import "react";
6
+ import { createFileRoute, lazyRouteComponent } from "@tanstack/react-router";
7
+ import "react/jsx-runtime";
8
+ import "lucide-react";
9
+ import "@tanstack/react-query";
10
+ //#region src/routes/today.tsx
11
+ var $$splitComponentImporter = () => import("./today-B_TA16QG.js");
12
+ var Route$1 = createFileRoute("/today")({
13
+ component: lazyRouteComponent($$splitComponentImporter, "component"),
14
+ validateSearch: validateTodaySearch
15
+ });
16
+ //#endregion
17
+ export { Route$1 as t };
@@ -0,0 +1,137 @@
1
+ //#region src/lib/ui.ts
2
+ function cx(...values) {
3
+ return values.filter(Boolean).join(" ");
4
+ }
5
+ var bodyClass = "min-h-screen bg-[var(--bg)] font-sans text-[var(--ink)] antialiased text-[15px] leading-[1.4]";
6
+ var siteShellClass = "mx-auto flex min-h-screen w-full max-w-[1280px] gap-0";
7
+ var sidebarShellClass = "sticky top-0 z-30 flex h-screen w-[72px] shrink-0 flex-col justify-between border-r border-[var(--line)] bg-[var(--bg)] px-2 py-3 min-[1100px]:w-[260px] min-[1100px]:px-3";
8
+ var sidebarShellCompactClass = "sticky top-0 z-30 flex h-screen w-[72px] shrink-0 flex-col justify-between border-r border-[var(--line)] bg-[var(--bg)] px-2 py-3";
9
+ var sidebarBrandClass = "flex items-center gap-2.5 px-2 py-2 text-[var(--ink)] min-[1100px]:px-3";
10
+ var sidebarBrandMarkClass = "grid size-10 place-items-center";
11
+ var sidebarBrandCopyClass = "hidden flex-col leading-tight min-[1100px]:flex";
12
+ var sidebarBrandCopyCompactClass = "sr-only";
13
+ var sidebarBrandTitleClass = "text-[15px] font-bold tracking-tight";
14
+ var sidebarBrandTaglineClass = "text-[12px] text-[var(--ink-soft)]";
15
+ var sidebarNavClass = "mt-2 flex flex-col gap-0.5";
16
+ var sidebarFooterClass = "flex flex-col gap-2 pb-1";
17
+ var navLinkClass = "nav-link group flex items-center justify-center gap-4 rounded-full px-3 py-2.5 text-[15px] text-[var(--ink)] transition-colors duration-150 hover:bg-[var(--bg-hover)] min-[1100px]:justify-start";
18
+ var navLinkCompactClass = "nav-link group flex items-center justify-center rounded-full px-3 py-2.5 text-[15px] text-[var(--ink)] transition-colors duration-150 hover:bg-[var(--bg-hover)]";
19
+ var navLinkActiveClass = "nav-link-active font-bold";
20
+ var navLinkIconClass = "shrink-0";
21
+ var navLinkLabelClass = "sr-only min-[1100px]:not-sr-only";
22
+ var navLinkLabelCompactClass = "sr-only";
23
+ var mainColumnClass = "flex w-full min-w-0 max-w-[680px] flex-1 flex-col border-x border-[var(--line)] bg-[var(--bg)]";
24
+ var mainColumnDmClass = "flex w-full min-w-0 flex-1 flex-col border-x border-[var(--line)] bg-[var(--bg)]";
25
+ var pageHeaderClass = "sticky top-0 z-20 flex flex-col gap-0 border-b border-[var(--line)] bg-[color:color-mix(in_srgb,var(--bg)_85%,transparent)] backdrop-blur";
26
+ var pageHeaderRowClass = "flex items-center justify-between gap-3 px-4 pt-3 pb-2";
27
+ var pageTitleClass = "m-0 text-[20px] font-bold tracking-tight";
28
+ var pageSubtitleClass = "text-[13px] text-[var(--ink-soft)]";
29
+ var pageHeaderActionsClass = "flex items-center gap-2";
30
+ var tabStripClass = "flex w-full items-stretch border-b border-[var(--line)] overflow-x-auto";
31
+ var tabButtonClass = "relative flex flex-1 min-w-[88px] items-center justify-center px-3 py-3.5 text-[14px] font-medium text-[var(--ink-soft)] transition-colors duration-150 hover:bg-[var(--bg-hover)]";
32
+ var tabButtonActiveClass = "text-[var(--ink)] font-bold";
33
+ var tabButtonIndicatorClass = "pointer-events-none absolute bottom-0 left-1/2 h-[3px] w-12 -translate-x-1/2 rounded-full bg-[var(--accent)]";
34
+ var feedClass = "flex flex-col";
35
+ var feedRowClass = "flex w-full gap-3 border-b border-[var(--line)] px-4 py-3 transition-colors duration-150 hover:bg-[var(--bg-hover)]";
36
+ var feedRowBodyClass = "flex min-w-0 flex-1 flex-col gap-1";
37
+ var feedRowHeaderClass = "flex min-w-0 items-center gap-1.5 text-[15px]";
38
+ var feedRowNameClass = "truncate font-bold text-[var(--ink)] hover:underline";
39
+ var feedRowHandleClass = "truncate text-[var(--ink-soft)]";
40
+ var feedRowDotClass = "text-[var(--ink-soft)]";
41
+ var feedRowTimestampClass = "shrink-0 text-[var(--ink-soft)] hover:underline";
42
+ var feedRowActionsClass = "mt-2 flex max-w-md items-center justify-between text-[var(--ink-soft)]";
43
+ var feedActionButtonClass = "action-button group/action inline-flex items-center gap-1 rounded-full border-0 bg-transparent px-2 py-1 text-[13px] text-[var(--ink-soft)] transition-colors duration-150 hover:text-[var(--accent)] disabled:cursor-default disabled:opacity-55";
44
+ var feedActionIconWrapClass = "grid size-[34px] place-items-center rounded-full transition-colors duration-150 group-hover/action:bg-[var(--accent-soft)]";
45
+ var feedActionIconClass = "size-[18px]";
46
+ var feedRowTextClass = "whitespace-pre-wrap break-words text-[15px] leading-[1.45] text-[var(--ink)] [overflow-wrap:anywhere]";
47
+ var feedRowStatePillClass = "inline-flex shrink-0 items-center gap-1 rounded-full border border-[var(--line)] bg-[var(--bg-active)] px-2 py-0.5 text-[12px] font-semibold text-[var(--ink-soft)]";
48
+ var feedRowStatePillActiveClass = "border-[color:color-mix(in_srgb,var(--accent)_35%,var(--line))] bg-[var(--accent-soft)] text-[var(--accent)]";
49
+ var feedRowStatePillOpenClass = "border-[color:color-mix(in_srgb,var(--ink-soft)_34%,var(--line))] bg-transparent text-[var(--ink-soft)]";
50
+ var searchFieldShellClass = "flex items-center gap-2 rounded-full border border-transparent bg-[var(--bg-active)] px-4 py-2 transition-colors focus-within:border-[var(--accent)] focus-within:bg-[var(--bg)] focus-within:shadow-[0_0_0_1px_var(--accent)]";
51
+ var searchFieldIconClass = "size-[18px] text-[var(--ink-soft)] shrink-0";
52
+ var searchFieldInputClass = "min-w-0 flex-1 border-0 bg-transparent text-[14px] text-[var(--ink)] outline-none placeholder:text-[var(--ink-soft)]";
53
+ var textFieldClass = "w-full rounded-md border border-[var(--line)] bg-[var(--bg)] px-3 py-2 text-[14px] text-[var(--ink)] outline-none transition-colors duration-150 placeholder:text-[var(--ink-soft)] focus:border-[var(--accent)] focus:shadow-[0_0_0_1px_var(--accent)] disabled:cursor-default disabled:opacity-55";
54
+ var textFieldShortClass = "w-[120px]";
55
+ var selectFieldClass = cx(textFieldClass, "appearance-none pr-8");
56
+ var primaryButtonClass = "inline-flex items-center justify-center gap-1.5 rounded-full border-0 bg-[var(--accent)] px-4 py-1.5 text-[14px] font-bold text-white shadow-none transition-colors duration-150 hover:bg-[var(--accent-hover)] active:bg-[var(--accent-press)] disabled:cursor-default disabled:opacity-55";
57
+ var secondaryButtonClass = "inline-flex items-center justify-center gap-1.5 rounded-full border border-[var(--line-strong)] bg-transparent px-4 py-1.5 text-[14px] font-bold text-[var(--ink)] transition-colors duration-150 hover:bg-[var(--bg-hover)] disabled:cursor-default disabled:opacity-55";
58
+ var dangerButtonClass = "inline-flex items-center justify-center gap-1.5 rounded-full border border-[var(--alert)] bg-transparent px-4 py-1.5 text-[14px] font-bold text-[var(--alert)] transition-colors duration-150 hover:bg-[var(--alert-soft)] disabled:cursor-default disabled:opacity-55";
59
+ var segmentedClass = "inline-flex shrink-0 items-center gap-1 rounded-full border border-[var(--line)] bg-[var(--bg)] p-1";
60
+ var segmentClass = "rounded-full border-0 bg-transparent px-3 py-1 text-[13px] font-medium text-[var(--ink-soft)] capitalize transition-colors duration-150";
61
+ var segmentActiveClass = "bg-[var(--bg-active)] text-[var(--ink)]";
62
+ var composerShellClass = "mt-2 flex flex-col gap-2 border-t border-[var(--line)] pt-3";
63
+ var composerInputClass = "min-h-[88px] w-full resize-y rounded-md border border-[var(--line)] bg-[var(--bg)] px-3 py-2.5 text-[15px] text-[var(--ink)] outline-none transition-colors duration-150 placeholder:text-[var(--ink-soft)] focus:border-[var(--accent)] focus:shadow-[0_0_0_1px_var(--accent)]";
64
+ var composerBarClass = "flex items-center justify-between gap-3";
65
+ var emptyStateClass = "px-6 py-10 text-center text-[var(--ink-soft)]";
66
+ var errorCopyClass = "mx-4 my-3 whitespace-pre-wrap break-words rounded-md border border-[var(--alert)] bg-[var(--alert-soft)] px-3 py-2 text-[14px] text-[var(--alert)]";
67
+ var statusCopyClass = "mx-4 my-3 rounded-md border border-[var(--line)] bg-[var(--bg-elevated)] px-3 py-2 text-[13px] text-[var(--ink-soft)]";
68
+ var avatarChipClass = "avatar-chip inline-grid size-10 shrink-0 place-items-center overflow-hidden rounded-full text-[14px] font-bold text-white";
69
+ var avatarChipLargeClass = "avatar-chip-large size-16 text-[18px]";
70
+ var avatarChipSmallClass = "avatar-chip-small size-8 text-[12px]";
71
+ var embeddedCardClass = "mt-2 overflow-hidden rounded-2xl border border-[var(--line)] transition-colors duration-150 hover:bg-[var(--bg-hover)]";
72
+ var embeddedCardBodyClass = "flex flex-col gap-2 px-3 py-2.5";
73
+ var embeddedCardHeaderClass = "flex items-center gap-1.5 text-[14px]";
74
+ var embeddedCardNameClass = "font-bold text-[var(--ink)] truncate";
75
+ var embeddedCardHandleClass = "text-[var(--ink-soft)] truncate";
76
+ var embeddedCardLabelClass = "text-[12px] uppercase tracking-wide text-[var(--ink-soft)]";
77
+ var embeddedCardCopyClass = "whitespace-pre-wrap text-[14px] leading-[1.4] text-[var(--ink)] [overflow-wrap:anywhere]";
78
+ var linkPreviewCardClass = "group/link-preview mt-2 flex min-w-0 overflow-hidden rounded-2xl border border-[var(--line)] bg-[var(--bg-card)] transition-colors duration-150 hover:bg-[var(--bg-hover)]";
79
+ var linkPreviewTitleClass = "line-clamp-2 font-bold leading-tight text-[var(--ink)]";
80
+ var linkPreviewDescClass = "line-clamp-2 text-[14px] leading-snug text-[var(--ink-soft)]";
81
+ var linkPreviewHostClass = "text-[13px] text-[var(--ink-soft)] truncate";
82
+ var dmShellClass = "grid h-[calc(100vh-56px)] min-h-[520px] grid-cols-1 min-[960px]:grid-cols-[360px_minmax(0,1fr)] min-[1360px]:grid-cols-[400px_minmax(0,1fr)]";
83
+ var dmListClass = "flex flex-col overflow-y-auto border-r border-[var(--line)]";
84
+ var dmListItemClass = "flex w-full items-start gap-3 border-b border-[var(--line)] border-0 bg-transparent px-3 py-3 text-left transition-colors duration-150 hover:bg-[var(--bg-hover)]";
85
+ var dmListItemActiveClass = "bg-[var(--bg-active)]";
86
+ var dmListBodyClass = "flex min-w-0 flex-1 flex-col gap-1";
87
+ var dmListHeaderClass = "flex items-center justify-between gap-2";
88
+ var dmListNameClass = "truncate text-[14px] font-bold text-[var(--ink)]";
89
+ var dmListHandleClass = "truncate text-[13px] text-[var(--ink-soft)]";
90
+ var dmListPreviewClass = "truncate text-[13px] text-[var(--ink-soft)]";
91
+ var dmListTimestampClass = "shrink-0 text-[12px] text-[var(--ink-soft)]";
92
+ var dmThreadClass = "flex min-w-0 flex-col";
93
+ var dmThreadHeaderClass = "sticky top-0 z-10 flex items-center justify-between gap-3 border-b border-[var(--line)] bg-[color:color-mix(in_srgb,var(--bg)_85%,transparent)] px-4 py-3 backdrop-blur";
94
+ var dmThreadTitleClass = "flex items-center gap-3 min-w-0";
95
+ var dmThreadNameClass = "truncate text-[16px] font-bold";
96
+ var dmThreadSubtitleClass = "truncate text-[13px] text-[var(--ink-soft)]";
97
+ var dmMessagesClass = "flex flex-1 flex-col gap-2 overflow-y-auto px-4 py-4";
98
+ var dmMessageRowClass = "flex max-w-[78%] flex-col gap-1";
99
+ var dmMessageRowOutboundClass = "self-end items-end";
100
+ var dmMessageBubbleClass = "rounded-2xl rounded-bl-md px-3.5 py-2 text-[15px] leading-[1.4]";
101
+ var dmMessageBubbleInboundClass = "bg-[var(--bg-active)] text-[var(--ink)]";
102
+ var dmMessageBubbleOutboundClass = "rounded-bl-2xl rounded-br-md bg-[var(--accent)] text-[var(--accent-text)]";
103
+ var dmMessageMetaClass = "flex items-center gap-2 text-[12px] text-[var(--ink-soft)]";
104
+ var dmComposerShellClass = "flex flex-col gap-2 border-t border-[var(--line)] px-4 py-3";
105
+ var profilePreviewClass = "relative inline-flex";
106
+ var profilePreviewTriggerClass = "profile-preview-trigger inline-flex text-inherit";
107
+ var profilePreviewCardClass = "fixed z-40 w-[280px] overflow-y-auto rounded-2xl border border-[var(--line)] bg-[var(--bg-elevated)] p-3 shadow-[0_8px_28px_var(--shadow-strong)]";
108
+ var profilePreviewHeaderClass = "flex items-center gap-3";
109
+ var profilePreviewNameClass = "block text-[15px] font-bold text-[var(--ink)]";
110
+ var profilePreviewHandleClass = "block text-[14px] text-[var(--ink-soft)]";
111
+ var profilePreviewBioClass = "block text-[14px] leading-[1.4] text-[var(--ink)]";
112
+ var profilePreviewMetaClass = "block text-[13px] text-[var(--ink-soft)]";
113
+ var tweetLinkClass = "text-[var(--accent)] hover:underline";
114
+ var tweetMentionClass = "text-[var(--accent)] hover:underline";
115
+ var tweetHashtagClass = tweetMentionClass;
116
+ function tweetMediaGridClass(count) {
117
+ const capped = Math.min(count, 4);
118
+ const layout = count === 1 ? "grid-cols-1" : count === 3 ? "grid-cols-[1.3fr_1fr]" : count === 4 ? "grid-cols-2 grid-rows-2" : "grid-cols-2";
119
+ return cx(`tweet-media-grid tweet-media-grid-${String(capped)}`, "mt-2 grid gap-0.5 overflow-hidden rounded-2xl border border-[var(--line)]", layout);
120
+ }
121
+ function tweetMediaTileClass(index, count) {
122
+ return cx("tweet-media-tile relative block overflow-hidden border-0 bg-[var(--bg-active)] p-0 text-left", count === 1 && "aspect-[16/10]", count === 2 && "aspect-square", count === 3 && index === 0 && "row-span-2 aspect-[3/4]", count === 3 && index !== 0 && "aspect-square", count === 4 && "aspect-square");
123
+ }
124
+ var inboxAnalysisClass = "mt-2 rounded-xl border border-[var(--line)] bg-[var(--bg-hover)] px-3 py-2.5 text-[14px] text-[var(--ink-soft)] [&_p]:mt-1 [&_p]:mb-0";
125
+ var blockRowClass = "flex items-start gap-3 border-b border-[var(--line)] px-4 py-3 transition-colors duration-150 hover:bg-[var(--bg-hover)]";
126
+ var blockRowBodyClass = "flex min-w-0 flex-1 flex-col gap-1";
127
+ var mutedDotClass = "inline-block size-1 shrink-0 rounded-full bg-[var(--ink-soft)]";
128
+ var pillClass = "inline-flex items-center rounded-full px-2 py-0.5 text-[12px] font-semibold";
129
+ var pillSoftClass = "bg-[var(--accent-soft)] text-[var(--accent)]";
130
+ var pillAlertClass = "bg-[var(--alert-soft)] text-[var(--alert)]";
131
+ var timestampClass = "text-[13px] text-[var(--ink-soft)]";
132
+ var bodyCopyClass = feedRowTextClass;
133
+ var contextStatRowClass = "grid grid-cols-[minmax(0,1fr)_auto] items-center gap-3 border-t border-[var(--line)] py-2 first:border-t-0 first:pt-0";
134
+ var contextStatTermClass = "min-w-0 text-[13px] text-[var(--ink-soft)]";
135
+ var contextStatValueClass = "shrink-0 whitespace-nowrap text-right text-[14px] font-bold text-[var(--ink)]";
136
+ //#endregion
137
+ export { feedRowBodyClass as $, sidebarBrandTaglineClass as $t, dmMessageRowClass as A, pillClass as At, embeddedCardClass as B, profilePreviewTriggerClass as Bt, dmListNameClass as C, navLinkLabelCompactClass as Ct, dmMessageBubbleInboundClass as D, pageSubtitleClass as Dt, dmMessageBubbleClass as E, pageHeaderRowClass as Et, dmThreadHeaderClass as F, profilePreviewClass as Ft, embeddedCardNameClass as G, segmentActiveClass as Gt, embeddedCardHandleClass as H, searchFieldInputClass as Ht, dmThreadNameClass as I, profilePreviewHandleClass as It, feedActionButtonClass as J, selectFieldClass as Jt, emptyStateClass as K, segmentClass as Kt, dmThreadSubtitleClass as L, profilePreviewHeaderClass as Lt, dmMessagesClass as M, primaryButtonClass as Mt, dmShellClass as N, profilePreviewBioClass as Nt, dmMessageBubbleOutboundClass as O, pageTitleClass as Ot, dmThreadClass as P, profilePreviewCardClass as Pt, feedRowActionsClass as Q, sidebarBrandMarkClass as Qt, dmThreadTitleClass as R, profilePreviewMetaClass as Rt, dmListItemClass as S, navLinkLabelClass as St, dmListTimestampClass as T, pageHeaderClass as Tt, embeddedCardHeaderClass as U, searchFieldShellClass as Ut, embeddedCardCopyClass as V, searchFieldIconClass as Vt, embeddedCardLabelClass as W, secondaryButtonClass as Wt, feedActionIconWrapClass as X, sidebarBrandCopyClass as Xt, feedActionIconClass as Y, sidebarBrandClass as Yt, feedClass as Z, sidebarBrandCopyCompactClass as Zt, dmListBodyClass as _, tweetMediaTileClass as _n, mutedDotClass as _t, blockRowClass as a, siteShellClass as an, feedRowStatePillActiveClass as at, dmListHeaderClass as b, navLinkCompactClass as bt, composerBarClass as c, tabButtonClass as cn, feedRowTextClass as ct, contextStatRowClass as d, textFieldClass as dn, linkPreviewCardClass as dt, sidebarBrandTitleClass as en, feedRowClass as et, contextStatTermClass as f, textFieldShortClass as fn, linkPreviewDescClass as ft, dmComposerShellClass as g, tweetMediaGridClass as gn, mainColumnDmClass as gt, dangerButtonClass as h, tweetLinkClass as hn, mainColumnClass as ht, blockRowBodyClass as i, sidebarShellCompactClass as in, feedRowNameClass as it, dmMessageRowOutboundClass as j, pillSoftClass as jt, dmMessageMetaClass as k, pillAlertClass as kt, composerInputClass as l, tabButtonIndicatorClass as ln, feedRowTimestampClass as lt, cx as m, tweetHashtagClass as mn, linkPreviewTitleClass as mt, avatarChipLargeClass as n, sidebarNavClass as nn, feedRowHandleClass as nt, bodyClass as o, statusCopyClass as on, feedRowStatePillClass as ot, contextStatValueClass as p, timestampClass as pn, linkPreviewHostClass as pt, errorCopyClass as q, segmentedClass as qt, avatarChipSmallClass as r, sidebarShellClass as rn, feedRowHeaderClass as rt, bodyCopyClass as s, tabButtonActiveClass as sn, feedRowStatePillOpenClass as st, avatarChipClass as t, sidebarFooterClass as tn, feedRowDotClass as tt, composerShellClass as u, tabStripClass as un, inboxAnalysisClass as ut, dmListClass as v, tweetMentionClass as vn, navLinkActiveClass as vt, dmListPreviewClass as w, pageHeaderActionsClass as wt, dmListItemActiveClass as x, navLinkIconClass as xt, dmListHandleClass as y, navLinkClass as yt, embeddedCardBodyClass as z, profilePreviewNameClass as zt };
@@ -1,12 +1,12 @@
1
1
  import { useEffect, useState } from "react";
2
-
3
- export function useDebouncedValue<T>(value: T, delayMs: number) {
2
+ //#region src/components/useDebouncedValue.ts
3
+ function useDebouncedValue(value, delayMs) {
4
4
  const [debouncedValue, setDebouncedValue] = useState(value);
5
-
6
5
  useEffect(() => {
7
6
  const timeout = window.setTimeout(() => setDebouncedValue(value), delayMs);
8
7
  return () => window.clearTimeout(timeout);
9
8
  }, [delayMs, value]);
10
-
11
9
  return debouncedValue;
12
10
  }
11
+ //#endregion
12
+ export { useDebouncedValue as t };