birdclaw 0.9.0 → 0.9.2

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 (77) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +3 -1
  3. package/dist/cli/birdclaw.js +189 -17
  4. package/dist/client/assets/AvatarChip-BN3b4MhM.js +1 -0
  5. package/dist/client/assets/ProfilePreview-CHbT0U9a.js +1 -0
  6. package/dist/client/assets/SavedTimelineView-mGXE9EYJ.js +1 -0
  7. package/dist/client/assets/SmartTimestamp-DG8XJKUz.js +1 -0
  8. package/dist/client/assets/TimelineRouteFrame-BmMC7qLj.js +1 -0
  9. package/dist/client/assets/blocks-CawnB0mN.js +1 -0
  10. package/dist/client/assets/{bookmarks-Cprrli-V.js → bookmarks-DZIMTKEp.js} +1 -1
  11. package/dist/client/assets/chunk-C0phanGV.js +1 -0
  12. package/dist/client/assets/circle-check-C_Vq3ElD.js +1 -0
  13. package/dist/client/assets/{client-stream-contracts-D1QUdWfh.js → client-stream-contracts-DcKcyZhg.js} +1 -1
  14. package/dist/client/assets/createLucideIcon-JV8isFFR.js +1 -0
  15. package/dist/client/assets/data-sources-BJUT2qaO.js +1 -0
  16. package/dist/client/assets/discuss-DMPJVaRk.js +1 -0
  17. package/dist/client/assets/dms-BfPFG4Qr.js +1 -0
  18. package/dist/client/assets/inbox-DmeYJ7tt.js +1 -0
  19. package/dist/client/assets/index-Bqmo4MbK.js +31 -0
  20. package/dist/client/assets/likes-BxVL-j_C.js +1 -0
  21. package/dist/client/assets/links-BeA1Wt8F.js +1 -0
  22. package/dist/client/assets/mapbox-BTSMNSry.js +2 -0
  23. package/dist/client/assets/{mapbox-gl-WUhsQcSS.js → mapbox-gl-CPemBIlO.js} +1 -1
  24. package/dist/client/assets/{mentions-C3JYXV2K.js → mentions-DBrY-UPg.js} +1 -1
  25. package/dist/client/assets/network-map-MqbE164r.js +2 -0
  26. package/dist/client/assets/profile-analyze-DEA75Reh.js +1 -0
  27. package/dist/client/assets/{profile-hydration-client-BQyC5--e.js → profile-hydration-client-BNe0sUmK.js} +1 -1
  28. package/dist/client/assets/profiles._handle-K34ofz9U.js +1 -0
  29. package/dist/client/assets/query-client-DUP1ZzP7.js +17 -0
  30. package/dist/client/assets/rate-limits-B8Wmpt9r.js +1 -0
  31. package/dist/client/assets/react-dom-DHl6Ug7F.js +1 -0
  32. package/dist/client/assets/react-nBylq1U5.js +1 -0
  33. package/dist/client/assets/{repeat-2-CQ0lek01.js → repeat-2-xCwHM9hD.js} +1 -1
  34. package/dist/client/assets/{routes-CeIv5bkV.js → routes-Bl-Lw2hN.js} +1 -1
  35. package/dist/client/assets/schemas-CaALBBpc.js +64 -0
  36. package/dist/client/assets/search-Dq5kYsxA.js +1 -0
  37. package/dist/client/assets/{sparkles-Gx_BHkDX.js → sparkles-CQVlvHsZ.js} +1 -1
  38. package/dist/client/assets/{styles-DTMajAmk.css → styles-zihNNCGg.css} +2 -2
  39. package/dist/client/assets/today-DFvZ0Ys5.js +1 -0
  40. package/dist/client/assets/{triangle-alert-DJPCW6jQ.js → triangle-alert-CBL7s2pf.js} +1 -1
  41. package/dist/client/assets/useTimelineRouteData-Cpf-Jqsx.js +1 -0
  42. package/dist/client/assets/{users-DI3w8Mol.js → users-CHbKlqUr.js} +1 -1
  43. package/dist/server/assets/{_tanstack-start-manifest_v-CjYYXQ8Z.js → _tanstack-start-manifest_v-CVfs07C8.js} +35 -35
  44. package/dist/server/assets/{empty-plugin-adapters-D9UWiqvJ.js → empty-plugin-adapters-DzrEkdBF.js} +1 -1
  45. package/dist/server/assets/{router-DP7iZD-q.js → router-D8AUR_Gz.js} +114 -38
  46. package/dist/server/assets/start-FaDOTmto.js +4 -0
  47. package/dist/server/server.js +3413 -50
  48. package/package.json +1 -1
  49. package/dist/client/assets/AvatarChip-C8zELEVt.js +0 -1
  50. package/dist/client/assets/ProfilePreview-CsiLpFrb.js +0 -1
  51. package/dist/client/assets/SavedTimelineView-DE4CXK-h.js +0 -1
  52. package/dist/client/assets/SmartTimestamp-BypN4KPq.js +0 -1
  53. package/dist/client/assets/TimelineRouteFrame-D6djyMAT.js +0 -1
  54. package/dist/client/assets/blocks-h27nF3TL.js +0 -1
  55. package/dist/client/assets/circle-check-BCK_qvXt.js +0 -1
  56. package/dist/client/assets/createLucideIcon-CMLcIxOz.js +0 -1
  57. package/dist/client/assets/data-sources-Beb3JZkl.js +0 -1
  58. package/dist/client/assets/discuss-ciwVz7Fo.js +0 -1
  59. package/dist/client/assets/dms-BZ3GUPey.js +0 -1
  60. package/dist/client/assets/inbox-Dajdut79.js +0 -1
  61. package/dist/client/assets/index-a1ZAcWSa.js +0 -31
  62. package/dist/client/assets/likes-CxZZqiZC.js +0 -1
  63. package/dist/client/assets/links-CsWS9uKL.js +0 -1
  64. package/dist/client/assets/mapbox-dx7h2mOm.js +0 -2
  65. package/dist/client/assets/network-map-D4XA7TTO.js +0 -2
  66. package/dist/client/assets/profile-analyze-QAznTMjZ.js +0 -1
  67. package/dist/client/assets/profiles._handle-qntfbCE1.js +0 -1
  68. package/dist/client/assets/query-client-DZ5C7UNo.js +0 -17
  69. package/dist/client/assets/rate-limits-eHs_5dDB.js +0 -1
  70. package/dist/client/assets/react-BwGzW7mM.js +0 -1
  71. package/dist/client/assets/react-dom-DEMAB80t.js +0 -1
  72. package/dist/client/assets/rolldown-runtime-B-9mzPXz.js +0 -1
  73. package/dist/client/assets/schemas-CntsNLmN.js +0 -64
  74. package/dist/client/assets/search-C_LqodNa.js +0 -1
  75. package/dist/client/assets/today-DxppbQGF.js +0 -1
  76. package/dist/client/assets/useTimelineRouteData-CWvBmHLE.js +0 -1
  77. package/dist/server/assets/start-5Z2QO8AU.js +0 -4
@@ -0,0 +1 @@
1
+ import{r as e}from"./chunk-C0phanGV.js";import{t}from"./react-nBylq1U5.js";import{At as n,Ct as r,Dt as i,Et as a,Fn as o,Gt as s,In as c,Kt as l,M as u,Mt as d,Rn as f,St as p,Tt as m,Ut as h,Wt as g,_t as _,an as v,at as y,bt as b,ct as x,ft as S,gt as C,ht as w,it as T,jt as E,kt as D,lt as O,mt as k,on as ee,ot as te,pt as A,rt as ne,sn as re,st as ie,vt as ae,wt as j,xt as oe,yt as se}from"./schemas-CaALBBpc.js";import{t as M}from"./createLucideIcon-JV8isFFR.js";import{t as ce}from"./circle-check-C_Vq3ElD.js";import{t as le}from"./repeat-2-xCwHM9hD.js";import{t as ue}from"./search-Dq5kYsxA.js";import{C as de,a as fe,b as N,i as pe,l as me,m as he,n as P,o as ge,r as _e,s as ve,v as ye,w as be}from"./query-client-DUP1ZzP7.js";import{r as F,t as xe}from"./AvatarChip-BN3b4MhM.js";import{c as Se,i as I,s as Ce,t as L}from"./ProfilePreview-CHbT0U9a.js";import{t as R}from"./SmartTimestamp-DG8XJKUz.js";import{A as we,M as Te,O as Ee,at as De,ct as z,d as Oe,dt as ke,gt as B,it as Ae,k as je,lt as Me,mt as Ne,ot as Pe,pt as V,s as H,st as Fe,ut as Ie,yt as Le}from"./index-Bqmo4MbK.js";var Re=M(`book-open`,[[`path`,{d:`M12 7v14`,key:`1akyts`}],[`path`,{d:`M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z`,key:`ruj8y`}]]),ze=M(`bookmark-check`,[[`path`,{d:`M17 3a2 2 0 0 1 2 2v15a1 1 0 0 1-1.496.868l-4.512-2.578a2 2 0 0 0-1.984 0l-4.512 2.578A1 1 0 0 1 5 20V5a2 2 0 0 1 2-2z`,key:`oz39mx`}],[`path`,{d:`m9 10 2 2 4-4`,key:`1gnqz4`}]]),Be=M(`image`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}],[`circle`,{cx:`9`,cy:`9`,r:`2`,key:`af1f0g`}],[`path`,{d:`m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21`,key:`1xmnt7`}]]),Ve=M(`x`,[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]]),He=class extends Ie{constructor(e,t){super(e,t)}bindMethods(){super.bindMethods(),this.fetchNextPage=this.fetchNextPage.bind(this),this.fetchPreviousPage=this.fetchPreviousPage.bind(this)}setOptions(e){e._type=`infinite`,super.setOptions(e)}getOptimisticResult(e){return e._type=`infinite`,super.getOptimisticResult(e)}fetchNextPage(e){return this.fetch({...e,meta:{fetchMore:{direction:`forward`}}})}fetchPreviousPage(e){return this.fetch({...e,meta:{fetchMore:{direction:`backward`}}})}createResult(e,t){let{state:n}=e,r=super.createResult(e,t),{isFetching:i,isRefetching:a,isError:o,isRefetchError:s}=r,c=n.fetchMeta?.fetchMore?.direction,l=o&&c===`forward`,u=i&&c===`forward`,d=o&&c===`backward`,f=i&&c===`backward`;return{...r,fetchNextPage:this.fetchNextPage,fetchPreviousPage:this.fetchPreviousPage,hasNextPage:de(t,n.data),hasPreviousPage:be(t,n.data),isFetchNextPageError:l,isFetchingNextPage:u,isFetchPreviousPageError:d,isFetchingPreviousPage:f,isRefetchError:s&&!l&&!d,isRefetching:a&&!u&&!f}}};function Ue(e){return e}function We(e,t){return Me(e,He,t)}var U=e(t(),1),Ge=(0,U.createContext)(null);function Ke(e){return Ue({queryKey:[...P.conversations,e],queryFn:()=>me(pe(`/api/conversation?tweetId=${encodeURIComponent(e)}`,void 0,ye,`Conversation unavailable`)).then(e=>e.items),staleTime:1/0})}function qe({children:e}){let[t,n]=(0,U.useState)(null),r=(0,U.useMemo)(()=>({expandedSurfaceId:t,setExpandedSurfaceId:n}),[t]);return(0,U.createElement)(Ge.Provider,{value:r},e)}function Je(e,t=e){let n=(0,U.useContext)(Ge),[r,i]=(0,U.useState)(null),a=n?.expandedSurfaceId??r,o=n?.setExpandedSurfaceId??i,s=a===e,c=N(),l=z({...Ke(t),enabled:s}),u=(0,U.useCallback)(()=>{o(s?null:e)},[s,o,e]),d=(0,U.useCallback)(()=>{c.prefetchQuery(Ke(t))},[c,t]),f=l.isError?`error`:l.isFetching?`loading`:l.data?`ready`:`idle`;return{error:l.error instanceof Error?l.error.message:null,isOpen:s,items:l.data??[],loading:l.isFetching,prefetch:d,status:f,toggle:u}}var W=f();function Ye(e){let t=I(e);if(!t)return null;try{return new URL(t).hostname===`pbs.twimg.com`?t:null}catch{return null}}function G({article:e}){let t=I(e.url);if(!t)return null;let r=Ye(e.coverImageUrl);return(0,W.jsxs)(`a`,{"aria-label":`Read article: ${e.title}`,className:D,"data-perf":`tweet-article-card`,href:t,rel:`noreferrer`,target:`_blank`,children:[(0,W.jsxs)(`div`,{className:`flex min-w-0 flex-1 flex-col justify-center gap-1 px-3.5 py-3`,children:[(0,W.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,W.jsx)(Re,{"aria-hidden":`true`,className:`size-3.5 shrink-0 text-[var(--ink-soft)]`,strokeWidth:1.8}),(0,W.jsx)(`span`,{className:E,children:`Article on X`}),(0,W.jsx)(B,{"aria-hidden":`true`,className:`size-3.5 shrink-0 text-[var(--ink-soft)] opacity-0 transition-opacity group-hover/link-preview:opacity-100`,strokeWidth:1.8})]}),(0,W.jsx)(`span`,{className:d,children:e.title}),e.previewText?(0,W.jsx)(`span`,{className:n,children:e.previewText}):null]}),r?(0,W.jsx)(`div`,{className:`flex aspect-[1.45] w-40 shrink-0 overflow-hidden border-l border-[var(--line)] bg-[var(--bg-soft)] max-[720px]:w-28`,children:(0,W.jsx)(`img`,{alt:``,className:`size-full object-cover transition-transform duration-200 group-hover/link-preview:scale-[1.03]`,loading:`lazy`,src:r})}):null]})}function K({items:e}){let[t,n]=(0,U.useState)(null);if(e.length===0)return null;let r=e.slice(0,4),i=t===null?null:r[t]??null,a=i?.type===`video`||i?.type===`gif`?i.variants?.[0]?.url??Ze(i.url):null,s=r.length===1&&r[0]?.type===`image`?r[0]:null;return(0,W.jsxs)(W.Fragment,{children:[s?(0,W.jsx)(`button`,{"aria-label":`Open tweet media 1`,className:u(`tweet-media-single mt-2 max-w-full overflow-hidden rounded-2xl border border-[var(--line)] bg-[var(--bg-active)] p-0 text-left`,s.width&&s.height?`block`:`inline-block align-top`),onClick:e=>{e.stopPropagation(),n(0)},style:Xe(s),type:`button`,children:(0,W.jsx)(`img`,{alt:s.altText??`Tweet media 1`,className:u(`tweet-media-image block max-h-[720px] max-w-full`,s.width&&s.height?`size-full object-cover`:`h-auto w-auto object-contain`),height:s.height,loading:`lazy`,src:s.thumbnailUrl??s.url,width:s.width})}):(0,W.jsx)(`div`,{className:o(Math.min(e.length,4)),children:r.map((t,i)=>(0,W.jsx)(`button`,{"aria-label":`Open tweet media ${String(i+1)}`,className:c(i,Math.min(e.length,4)),onClick:e=>{e.stopPropagation(),n(i)},style:r.length===1&&t.width&&t.height?{aspectRatio:`${String(t.width)} / ${String(t.height)}`}:void 0,type:`button`,children:t.type===`image`?(0,W.jsx)(`img`,{alt:t.altText??`Tweet media ${String(i+1)}`,className:`tweet-media-image block size-full object-contain`,loading:`lazy`,src:t.thumbnailUrl??t.url}):(0,W.jsx)(`span`,{className:`tweet-media-fallback grid min-h-40 place-items-center font-semibold text-[var(--ink-soft)]`,children:t.type===`video`?`Video`:t.type===`gif`?`GIF`:`Media`})},t.url+String(i)))}),i?(0,W.jsxs)(`div`,{"aria-modal":`true`,className:`fixed inset-0 z-50 flex items-center justify-center bg-black/85 p-4`,onClick:e=>{e.stopPropagation(),n(null)},role:`dialog`,children:[(0,W.jsx)(`button`,{"aria-label":`Close media viewer`,className:`absolute right-4 top-4 grid size-10 place-items-center rounded-full bg-white/10 text-white transition-colors hover:bg-white/20`,onClick:e=>{e.stopPropagation(),n(null)},type:`button`,children:(0,W.jsx)(Ve,{className:`size-5`,strokeWidth:1.8})}),i.type===`image`?(0,W.jsx)(`img`,{alt:i.altText??`Tweet media`,className:`max-h-[92vh] max-w-[92vw] object-contain`,onClick:e=>e.stopPropagation(),src:i.url}):a?(0,W.jsx)(`video`,{autoPlay:i.type===`gif`,className:`max-h-[92vh] max-w-[92vw]`,controls:!0,loop:i.type===`gif`,muted:i.type===`gif`,onClick:e=>e.stopPropagation(),playsInline:!0,poster:i.thumbnailUrl,src:a}):(0,W.jsxs)(`div`,{className:`grid min-h-64 min-w-80 place-items-center gap-3 rounded-2xl border border-white/20 bg-black p-6 text-white`,onClick:e=>e.stopPropagation(),children:[(0,W.jsx)(`span`,{children:i.type===`video`?`Video`:i.type===`gif`?`GIF`:`Media`}),(0,W.jsx)(`a`,{className:`rounded-full bg-white/10 px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-white/20`,href:i.url,rel:`noreferrer`,target:`_blank`,children:`Open media`})]})]}):null]})}function Xe(e){if(!e.width||!e.height)return;let t=Math.min(e.width,Math.round(e.width/e.height*720));return{aspectRatio:`${String(e.width)} / ${String(e.height)}`,width:`${String(t)}px`}}function Ze(e){try{let t=new URL(e);return t.hostname===`video.twimg.com`||/\.(?:mp4|m3u8)(?:$|[?#])/i.test(t.pathname)?e:void 0}catch{return/\.(?:mp4|m3u8)(?:$|[?#])/i.test(e)?e:void 0}}function Qe({anchorId:e,error:t,items:n,loading:r}){return r?(0,W.jsx)(`section`,{className:`mt-3 rounded-2xl border border-[var(--line)] bg-[var(--bg-card)]`,children:(0,W.jsx)(De,{detail:`Finding archived replies around this post`,label:`Loading conversation`})}):t?(0,W.jsx)(`section`,{className:`mt-3 rounded-2xl border border-[var(--alert)] bg-[var(--alert-soft)] px-4 py-3 text-[14px] text-[var(--alert)]`,children:t}):n.length<=1?(0,W.jsx)(`section`,{className:`mt-3 rounded-2xl border border-[var(--line)]`,children:(0,W.jsx)(Ae,{detail:`This post has no other archived replies locally.`,label:`No thread context yet`})}):(0,W.jsxs)(`section`,{"aria-label":`Conversation`,className:`mt-3 overflow-hidden rounded-2xl border border-[var(--line)] bg-[var(--bg-card)]`,children:[(0,W.jsxs)(`div`,{className:`flex items-center gap-2 border-b border-[var(--line)] px-4 py-2.5 text-[13px] font-bold text-[var(--ink)]`,children:[(0,W.jsx)(V,{className:A,strokeWidth:1.8}),(0,W.jsxs)(`span`,{children:[n.length,` tweets in conversation`]})]}),(0,W.jsx)(`div`,{className:`flex flex-col`,children:n.map((t,r)=>{let a=t.id===e;return(0,W.jsxs)(`div`,{className:u(`flex gap-3 px-4 py-3`,r>0&&`border-t border-[var(--line)]`,a&&`bg-[var(--accent-soft)]`),children:[(0,W.jsxs)(`div`,{className:`flex flex-col items-center`,children:[(0,W.jsx)(xe,{avatarUrl:t.author.avatarUrl,hue:t.author.avatarHue,name:t.author.displayName,profileId:t.author.id,size:`small`}),r<n.length-1?(0,W.jsx)(`span`,{className:`mt-2 w-px flex-1 bg-[var(--line)]`}):null]}),(0,W.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,W.jsxs)(`header`,{className:`flex min-w-0 items-center gap-1.5 text-[14px]`,children:[(0,W.jsx)(L,{profile:t.author,children:(0,W.jsxs)(`span`,{className:`flex min-w-0 items-center gap-1.5`,children:[(0,W.jsx)(`span`,{className:p,children:t.author.displayName}),(0,W.jsxs)(`span`,{className:b,children:[`@`,t.author.handle]})]})}),(0,W.jsx)(`span`,{className:`text-[var(--ink-soft)]`,children:`·`}),(0,W.jsx)(R,{className:i,value:t.createdAt}),a?(0,W.jsx)(`span`,{className:`ml-auto rounded-full bg-[var(--accent)] px-2 py-0.5 text-[11px] font-bold text-white`,children:`selected`}):null]}),(0,W.jsx)(H,{className:`mt-1 whitespace-pre-wrap break-words text-[14px] leading-[1.45] text-[var(--ink)] [overflow-wrap:anywhere]`,entities:t.entities,text:t.text}),(0,W.jsx)(K,{items:t.media}),t.entities.article?(0,W.jsx)(G,{article:t.entities.article}):null]})]},t.id)})})]})}function q({item:e,label:t}){return(0,W.jsxs)(`section`,{className:ne,children:[(0,W.jsx)(`p`,{className:x,children:t}),(0,W.jsxs)(`header`,{className:ie,children:[(0,W.jsx)(L,{profile:e.author,children:(0,W.jsxs)(`span`,{className:`flex min-w-0 items-center gap-1.5`,children:[(0,W.jsx)(`span`,{className:O,children:e.author.displayName}),(0,W.jsxs)(`span`,{className:te,children:[`@`,e.author.handle]})]})}),(0,W.jsx)(`span`,{className:`text-[var(--ink-soft)]`,children:`·`}),(0,W.jsx)(R,{className:i,value:e.createdAt})]}),(0,W.jsx)(H,{className:y,entities:e.entities,text:e.text}),(0,W.jsx)(K,{items:e.media}),e.entities.article?(0,W.jsx)(G,{article:e.entities.article}):null]})}var $e=2,J=0,Y=[];function et(e){let t=e.expandedUrl||``;return e.imageUrl&&e.siteName&&e.title&&it(t)?!1:!e.imageUrl||!e.title||!e.description||e.title===e.displayUrl||e.description===e.displayUrl}function tt(){for(;J<$e&&Y.length>0;)Y.shift()?.()}function nt(e){return new Promise((t,n)=>{Y.push(()=>{J+=1,e().then(t).catch(n).finally(()=>{J=Math.max(0,J-1),tt()})}),tt()})}function rt(e){let t=new URLSearchParams({url:e});return Ue({queryKey:[...P.linkPreviews,e],queryFn:()=>nt(()=>_e(`/api/link-preview?${t.toString()}`,void 0,he,`Link preview unavailable`).then(e=>e.preview)),staleTime:30*6e4})}function X(e,t){try{return new URL(e).hostname.replace(/^www\./,``)}catch{return t}}function it(e){try{let t=new URL(e);return t.protocol===`https:`&&t.hostname===`pbs.twimg.com`&&(t.pathname.startsWith(`/media/`)||t.pathname.startsWith(`/amplify_video_thumb/`))}catch{return!1}}function at(e){if(!e)return null;try{let t=new URL(e);return t.protocol===`https:`&&t.hostname===`pbs.twimg.com`&&(t.pathname.startsWith(`/media/`)||t.pathname.startsWith(`/amplify_video_thumb/`))?t.toString():null}catch{return null}}function ot({entry:e,index:t}){let r=I(e.expandedUrl||e.url),i=r??``,a=e.displayUrl||(r?X(r,r):``),o=r&&it(r)?r:null,s=(0,U.useMemo)(()=>({expandedUrl:i,displayUrl:a,title:e.title??(o?X(i,a):void 0),description:e.description??(o?a:void 0),imageUrl:e.imageUrl??o,siteName:e.siteName??(o?X(i,a):void 0)}),[o,a,e.description,e.imageUrl,e.siteName,e.title,i]),[c,l]=(0,U.useState)(!1),[f,p]=(0,U.useState)(!1),[m,h]=(0,U.useState)(!1),g=(0,U.useRef)(null),_=!!(r&&et(s)),v=z({...rt(r??``),enabled:_&&f&&m}),y=(0,U.useMemo)(()=>{let e=v.data;return e?{expandedUrl:I(e.url)??s.expandedUrl,displayUrl:s.displayUrl,title:e.title??s.title,description:e.description??s.description,imageUrl:e.imageUrl??s.imageUrl,siteName:e.siteName??s.siteName}:s},[s,v.data]);if((0,U.useEffect)(()=>{l(!1),p(!1),h(!1)},[s]),(0,U.useEffect)(()=>{if(!r||!_)return;let e=g.current;if(!e||typeof IntersectionObserver>`u`){p(!0);return}let t=new IntersectionObserver(e=>{e.some(e=>e.isIntersecting)&&(p(!0),t.disconnect())},{rootMargin:`320px 0px`});return t.observe(e),()=>t.disconnect()},[_,r]),(0,U.useEffect)(()=>{if(!r||!f||!_)return;let e=window.setTimeout(()=>{h(!0)},100);return()=>window.clearTimeout(e)},[f,_,r]),!r)return null;let b=y.title||e.displayUrl,x=y.description&&y.description!==b?y.description:y.siteName||X(y.expandedUrl,e.displayUrl),S=y.siteName||X(y.expandedUrl,e.displayUrl),C=at(y.imageUrl),w=!!(C&&!c);return(0,W.jsxs)(`a`,{className:D,"data-perf":`link-preview-card`,href:I(y.expandedUrl)??r,ref:g,rel:`noreferrer`,target:`_blank`,children:[(0,W.jsxs)(`div`,{className:`flex min-w-0 flex-1 flex-col justify-center gap-1 px-3.5 py-3`,children:[(0,W.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,W.jsx)(`span`,{className:E,children:S}),(0,W.jsx)(B,{"aria-hidden":`true`,className:`size-3.5 shrink-0 text-[var(--ink-soft)] opacity-0 transition-opacity group-hover/link-preview:opacity-100`,strokeWidth:1.8})]}),(0,W.jsx)(`span`,{className:d,children:b}),(0,W.jsx)(`span`,{className:n,children:x}),(0,W.jsx)(`span`,{className:u(E,`text-[12px]`),children:e.displayUrl})]}),(0,W.jsx)(`div`,{className:`flex aspect-[1.45] w-40 shrink-0 items-center justify-center overflow-hidden border-l border-[var(--line)] bg-[var(--bg-soft)] max-[720px]:w-28`,children:w?(0,W.jsx)(`img`,{alt:b,className:`size-full object-cover transition-transform duration-200 group-hover/link-preview:scale-[1.03]`,loading:`lazy`,onError:()=>l(!0),src:C??``}):(0,W.jsx)(Be,{"aria-hidden":`true`,className:`size-8 text-[var(--ink-soft)]`,strokeWidth:1.7})})]},`${e.expandedUrl}-${String(t)}`)}function st(e){if(!e)return null;try{let t=new URL(e);return`${t.protocol}//${t.hostname}${t.pathname}`}catch{return e.split(`?`)[0]??e}}function ct(e){let t=new Set;for(let n of e)for(let e of[n.url,n.thumbnailUrl]){let n=st(e);n&&t.add(n)}return t}function lt(e,t,n){if(t.size>0&&ft(e.expandedUrl,n))return!0;for(let n of[e.url,e.expandedUrl,e.displayUrl]){let e=st(n);if(e&&t.has(e))return!0}return!1}function Z(e){if(!e)return!1;try{let t=e.includes(`://`)?e:`https://${e}`;return new URL(t).hostname.replace(/^www\./,``)===`t.co`}catch{return!1}}function Q(e){return Z(e.expandedUrl)?!0:e.expandedUrl?!1:Z(e.displayUrl)?!0:!e.displayUrl&&Z(e.url)}function ut(e,t){return(t.urls??[]).filter(Q).map(t=>Se(e,t))}function dt(e,t){let n=0,r=``;for(let i of[...t].sort((e,t)=>e.start-t.start))i.start<n||i.end<=i.start||i.end>e.length||(r+=e.slice(n,i.start),n=i.end);return r+=e.slice(n),r}function $(e,t,n){if(n.size===0)return!1;let r=ut(e,t);return r.length===0?!1:dt(e,r).trim().length===0}function ft(e,t){if(!e)return!1;try{let n=new URL(e),r=n.hostname.replace(/^www\./,``);if(r!==`x.com`&&r!==`twitter.com`)return!1;let i=n.pathname.split(`/`).filter(Boolean),a=i.indexOf(`status`);if(a<0||i[a+1]!==t)return!1;let o=i[a+2];return o===`photo`||o===`video`}catch{return!1}}function pt(e,t,n,r){let i=ct(t);if(i.size===0)return e;let a=$(r,e,i);return{...e,urls:(e.urls??[]).filter(e=>!lt(e,i,n)&&!(a&&Q(e)))}}function mt(e,t,n,r){let i=ct(t);if(i.size===0)return[];let a=$(r,e,i);return(e.urls??[]).filter(e=>lt(e,i,n)||a&&Q(e)).map(e=>Se(r,e))}function ht(e,t){return(e.urls??[]).filter(n=>Q(n)||e.article&&Ce(n,e.article)?!1:t?!n.expandedUrl.includes(t):!0)}function gt(e){return e instanceof Element&&!!e.closest(`a,button,input,textarea,select,[role='button']`)}function _t({tweet:e,hiddenUrlRanges:t,visibleUrlCards:n,replyToTweet:r,quotedTweet:i}){return(0,W.jsxs)(W.Fragment,{children:[(0,W.jsx)(H,{className:a,entities:e.entities,hiddenUrlRanges:t,text:e.text}),(0,W.jsx)(K,{items:e.media}),e.entities.article?(0,W.jsx)(G,{article:e.entities.article}):null,r?(0,W.jsx)(`div`,{className:T,children:(0,W.jsx)(q,{item:r,label:`In reply to`})}):null,i?(0,W.jsx)(`div`,{className:T,children:(0,W.jsx)(q,{item:i,label:`Quoted tweet`})}):null,n.map((e,t)=>(0,W.jsx)(ot,{entry:e,index:t},`${e.expandedUrl}-${String(t)}`))]})}function vt({item:e,onReply:t,showReplyControls:n=!0}){let a=n&&e.kind!==`like`&&e.kind!==`bookmark`,o=e.retweetedTweet??e,s=o.id,c=e.retweetedTweet&&s===`${e.id}:retweeted`?e.id:s,l=o.author,d=Je(e.id,c),f=pt(o.entities,o.media,o.id,o.text),h=mt(o.entities,o.media,o.id,o.text),g=ht(f,e.retweetedTweet?null:e.quotedTweet?.id??null),v=e.retweetedTweet?o.mediaCount??o.media.length:e.mediaCount,y=o.isReplied??e.isReplied,x=o.likeCount??e.likeCount,w=o.bookmarked??e.bookmarked,T=o.liked??e.liked,E=T||x>0,D=v>0,O=!!(e.retweetedTweet?o.replyToId:e.replyToTweet||e.replyToId);return(0,W.jsxs)(`article`,{className:u(ae,`cursor-pointer [content-visibility:auto] [contain-intrinsic-size:auto_280px]`),"data-perf":`timeline-card`,onFocus:d.prefetch,onMouseEnter:d.prefetch,onClick:e=>{gt(e.target)||d.toggle()},children:[(0,W.jsx)(xe,{avatarUrl:l.avatarUrl,hue:l.avatarHue,name:l.displayName,profileId:l.id}),(0,W.jsxs)(`div`,{className:_,children:[e.retweetedTweet?(0,W.jsxs)(`div`,{className:`inline-flex items-center gap-2 text-[13px] font-medium text-[var(--ink-soft)]`,children:[(0,W.jsx)(le,{className:`size-4`,strokeWidth:1.8}),(0,W.jsx)(L,{profile:e.author,children:(0,W.jsxs)(`span`,{children:[e.author.displayName,` reposted`]})})]}):null,(0,W.jsxs)(`header`,{className:oe,children:[(0,W.jsx)(L,{profile:l,children:(0,W.jsxs)(`span`,{className:`flex min-w-0 items-center gap-1.5`,children:[(0,W.jsx)(`span`,{className:p,children:l.displayName}),(0,W.jsxs)(`span`,{className:b,children:[`@`,l.handle]})]})}),(0,W.jsx)(`span`,{className:se,children:`·`}),(0,W.jsx)(R,{className:i,value:o.createdAt}),a||O?(0,W.jsxs)(`span`,{className:`ml-auto inline-flex items-center gap-1`,children:[O?(0,W.jsxs)(`span`,{"aria-label":`Part of a conversation`,className:u(j,r),title:`Part of a conversation`,children:[(0,W.jsx)(V,{className:`size-3.5`,strokeWidth:2}),`thread`]}):null,a?(0,W.jsxs)(`span`,{"aria-label":y?`We replied`:`Reply open`,className:u(j,y?r:m),title:y?`We replied`:`Reply open`,children:[y?(0,W.jsx)(ce,{className:`size-3.5`,strokeWidth:2}):(0,W.jsx)(Le,{className:`size-3`,strokeWidth:2.2}),y?`replied`:`open`]}):null]}):null]}),(0,W.jsx)(_t,{hiddenUrlRanges:h,quotedTweet:e.retweetedTweet?null:e.quotedTweet,replyToTweet:e.retweetedTweet?null:e.replyToTweet,tweet:o,visibleUrlCards:g}),(0,W.jsx)(`footer`,{className:C,children:(0,W.jsxs)(`div`,{className:`flex items-center gap-3 text-[13px] text-[var(--ink-soft)]`,children:[(0,W.jsxs)(`button`,{"aria-expanded":d.isOpen,"aria-label":d.isOpen?`Hide conversation`:`Show conversation`,className:S,onClick:e=>{e.stopPropagation(),d.toggle()},type:`button`,children:[(0,W.jsx)(`span`,{className:k,children:(0,W.jsx)(V,{className:A,strokeWidth:1.7})}),(0,W.jsx)(`span`,{className:`text-[13px]`,children:d.isOpen?`Hide thread`:`Thread`})]}),a?(0,W.jsxs)(`button`,{className:S,onClick:e=>{e.stopPropagation(),t(c)},type:`button`,"aria-label":`Reply`,children:[(0,W.jsx)(`span`,{className:k,children:(0,W.jsx)(V,{className:A,strokeWidth:1.7})}),(0,W.jsx)(`span`,{className:`text-[13px]`,children:`Reply`})]}):null,(0,W.jsxs)(`a`,{"aria-label":`Analyse @${l.handle}`,className:S,href:`/profiles/${encodeURIComponent(l.handle)}`,onClick:e=>{e.stopPropagation()},title:`Analyse @${l.handle}`,children:[(0,W.jsx)(`span`,{className:k,children:(0,W.jsx)(ke,{className:A,strokeWidth:1.7})}),(0,W.jsx)(`span`,{className:`text-[13px]`,children:`Analyse`})]}),E?(0,W.jsxs)(`span`,{"aria-label":`${F(x)} likes`,className:u(`inline-flex items-center gap-1 px-2 py-1 text-[13px]`,T&&`text-[var(--like)]`),title:`${F(x)} likes`,children:[(0,W.jsx)(Ne,{className:A,strokeWidth:1.7,fill:T?`currentColor`:`none`}),(0,W.jsx)(`span`,{children:F(x)})]}):null,w?(0,W.jsx)(`span`,{"aria-label":`Bookmarked`,className:`inline-flex items-center px-2 py-1`,title:`Bookmarked`,children:(0,W.jsx)(ze,{className:A,strokeWidth:1.7})}):null,D?(0,W.jsxs)(`span`,{"aria-label":`${String(v)} media attachments`,className:`inline-flex items-center gap-1 px-2 py-1 text-[13px]`,title:`${String(v)} media attachments`,children:[(0,W.jsx)(Be,{className:A,strokeWidth:1.7}),(0,W.jsx)(`span`,{children:v})]}):null]})}),d.isOpen?(0,W.jsx)(Qe,{anchorId:c,error:d.error,items:d.items,loading:d.loading}):null]})]})}function yt({title:e,subtitles:t,action:n,controls:r}){return(0,W.jsxs)(`header`,{className:h,children:[(0,W.jsxs)(`div`,{className:`${g} flex-wrap`,children:[(0,W.jsxs)(`div`,{className:`flex min-w-0 flex-col`,children:[(0,W.jsx)(`h1`,{className:l,children:e}),t]}),n]}),r]})}function bt({children:e}){return(0,W.jsx)(`p`,{className:s,children:e})}function xt({value:e,onChange:t,placeholder:n}){return(0,W.jsx)(`div`,{className:`px-4 pb-3`,children:(0,W.jsxs)(`label`,{className:re,children:[(0,W.jsx)(ue,{className:v,strokeWidth:2}),(0,W.jsx)(`input`,{className:ee,onChange:e=>t(e.target.value),placeholder:n,value:e})]})})}function St({header:e,notice:t,loading:n,loadingLabel:r,loadingDetail:i,error:a,errorTitle:o,onRetry:s,empty:c,emptyLabel:l,emptyDetail:u,children:d,hasMore:f,loadingMore:p,onLoadMore:m}){return(0,W.jsxs)(W.Fragment,{children:[e,t,(0,W.jsx)(qe,{children:(0,W.jsxs)(`section`,{className:w,children:[n?(0,W.jsx)(we,{detail:i,label:r,children:(0,W.jsx)(Te,{})}):a?(0,W.jsx)(je,{action:(0,W.jsx)(`button`,{className:`rounded-full bg-[var(--accent)] px-4 py-1.5 text-[14px] font-bold text-white`,onClick:s,type:`button`,children:`Retry`}),message:a,title:o}):c?(0,W.jsx)(Ee,{detail:u,label:l}):null,d,!n&&!a&&f?(0,W.jsx)(`div`,{className:`flex justify-center py-4`,children:(0,W.jsx)(`button`,{className:`rounded-full bg-[var(--accent)] px-5 py-1.5 text-[14px] font-bold text-white disabled:opacity-60`,disabled:p,onClick:m,type:`button`,children:p?`Loading…`:`Load more`})}):null]})})]})}var Ct=50,wt=5*6e4;function Tt({resource:e,search:t,replyFilter:n,likedOnly:r,bookmarkedOnly:i,selectedAccountId:a,pageParam:o}){let s=new URLSearchParams({resource:e,limit:String(Ct)});a&&s.set(`account`,a),n&&s.set(`replyFilter`,n),r&&s.set(`liked`,`true`),i&&s.set(`bookmarked`,`true`),t.trim()&&s.set(`search`,t.trim()),o&&(s.set(`until`,o.until),s.set(`untilId`,o.untilId)),s.sort();let c=typeof window>`u`?`http://birdclaw.local`:window.location.origin;return new URL(`/api/query?${s.toString()}`,c).toString()}function Et({resource:e,search:t,errorFallback:n,replyFilter:r,likedOnly:i=!1,bookmarkedOnly:a=!1}){let o=N(),s=z({queryKey:P.status,queryFn:({signal:e})=>fe({signal:e})}).data??null,c=Pe(s?.accounts),l=Oe(t,180),u=[...P.timelines,{resource:e,search:l,replyFilter:r??`all`,likedOnly:i,bookmarkedOnly:a,selectedAccountId:c??null}],d=We({queryKey:u,initialPageParam:void 0,queryFn:({pageParam:t,signal:n})=>ge(Tt({resource:e,search:l,replyFilter:r,likedOnly:i,bookmarkedOnly:a,selectedAccountId:c,pageParam:t}),{signal:n}),getNextPageParam:e=>{if(e.resource===`dms`)return;let t=e.items,n=t.at(-1);return t.length>=Ct&&n?{until:n.createdAt,untilId:n.id}:void 0},staleTime:wt}),f=(0,U.useMemo)(()=>{let e=new Set,t=[];for(let n of d.data?.pages??[])if(n.resource!==`dms`)for(let r of n.items)e.has(r.id)||(e.add(r.id),t.push(r));return t},[d.data]),p=Fe({mutationFn:({tweetId:e,text:t})=>ve({kind:`replyTweet`,accountId:c??`acct_primary`,tweetId:e,text:t}),onSuccess:()=>o.invalidateQueries({queryKey:u})});function m(){d.refetch()}function h(){Promise.all([o.invalidateQueries({queryKey:P.timelines}),o.invalidateQueries({queryKey:P.status})])}async function g(e){let t=window.prompt(`Reply text`);t?.trim()&&await p.mutateAsync({tweetId:e,text:t.trim()}).catch(()=>{})}let _=d.error;return{meta:s,items:f,loading:d.isPending,error:_?_ instanceof Error?_.message:n:null,replyError:p.error?p.error instanceof Error?p.error.message:`Reply failed`:null,retry:m,refreshLocalView:h,replyToTweet:g,selectedAccountId:c,hasMore:d.hasNextPage,loadingMore:d.isFetchingNextPage,loadMore:()=>d.fetchNextPage().then(()=>void 0)}}export{xt as a,bt as i,yt as n,vt as o,St as r,Et as t};
@@ -1 +1 @@
1
- import{t as e}from"./createLucideIcon-CMLcIxOz.js";var t=e(`users`,[[`path`,{d:`M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2`,key:`1yyitq`}],[`path`,{d:`M16 3.128a4 4 0 0 1 0 7.744`,key:`16gr8j`}],[`path`,{d:`M22 21v-2a4 4 0 0 0-3-3.87`,key:`kshegd`}],[`circle`,{cx:`9`,cy:`7`,r:`4`,key:`nufk8`}]]);export{t};
1
+ import{t as e}from"./createLucideIcon-JV8isFFR.js";var t=e(`users`,[[`path`,{d:`M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2`,key:`1yyitq`}],[`path`,{d:`M16 3.128a4 4 0 0 1 0 7.744`,key:`16gr8j`}],[`path`,{d:`M22 21v-2a4 4 0 0 0-3-3.87`,key:`kshegd`}],[`circle`,{cx:`9`,cy:`7`,r:`4`,key:`nufk8`}]]);export{t};
@@ -38,110 +38,110 @@ var tsrStartManifest = () => ({ routes: {
38
38
  ],
39
39
  css: ["/assets/index-bpFrQ5yG.css"],
40
40
  preloads: [
41
- "/assets/index-a1ZAcWSa.js",
42
- "/assets/rolldown-runtime-B-9mzPXz.js",
43
- "/assets/react-BwGzW7mM.js",
44
- "/assets/react-dom-DEMAB80t.js",
45
- "/assets/schemas-CntsNLmN.js",
46
- "/assets/createLucideIcon-CMLcIxOz.js",
47
- "/assets/circle-check-BCK_qvXt.js",
48
- "/assets/client-stream-contracts-D1QUdWfh.js",
49
- "/assets/sparkles-Gx_BHkDX.js",
50
- "/assets/query-client-DZ5C7UNo.js",
51
- "/assets/AvatarChip-C8zELEVt.js",
52
- "/assets/ProfilePreview-CsiLpFrb.js",
53
- "/assets/SmartTimestamp-BypN4KPq.js",
54
- "/assets/profile-hydration-client-BQyC5--e.js"
41
+ "/assets/index-Bqmo4MbK.js",
42
+ "/assets/chunk-C0phanGV.js",
43
+ "/assets/query-client-DUP1ZzP7.js",
44
+ "/assets/createLucideIcon-JV8isFFR.js",
45
+ "/assets/circle-check-C_Vq3ElD.js",
46
+ "/assets/client-stream-contracts-DcKcyZhg.js",
47
+ "/assets/sparkles-CQVlvHsZ.js",
48
+ "/assets/react-dom-DHl6Ug7F.js",
49
+ "/assets/schemas-CaALBBpc.js",
50
+ "/assets/react-nBylq1U5.js",
51
+ "/assets/AvatarChip-BN3b4MhM.js",
52
+ "/assets/ProfilePreview-CHbT0U9a.js",
53
+ "/assets/SmartTimestamp-DG8XJKUz.js",
54
+ "/assets/profile-hydration-client-BNe0sUmK.js"
55
55
  ],
56
56
  scripts: [{ attrs: {
57
57
  type: "module",
58
58
  async: !0,
59
- src: "/assets/index-a1ZAcWSa.js"
59
+ src: "/assets/index-Bqmo4MbK.js"
60
60
  } }]
61
61
  },
62
62
  "/": {
63
63
  filePath: "/Users/steipete/Projects/birdclaw/src/routes/index.tsx",
64
64
  children: void 0,
65
- preloads: ["/assets/routes-CeIv5bkV.js", "/assets/TimelineRouteFrame-D6djyMAT.js"]
65
+ preloads: ["/assets/routes-Bl-Lw2hN.js", "/assets/TimelineRouteFrame-BmMC7qLj.js"]
66
66
  },
67
67
  "/blocks": {
68
68
  filePath: "/Users/steipete/Projects/birdclaw/src/routes/blocks.tsx",
69
69
  children: void 0,
70
- preloads: ["/assets/blocks-h27nF3TL.js"]
70
+ preloads: ["/assets/blocks-CawnB0mN.js"]
71
71
  },
72
72
  "/bookmarks": {
73
73
  filePath: "/Users/steipete/Projects/birdclaw/src/routes/bookmarks.tsx",
74
74
  children: void 0,
75
- preloads: ["/assets/bookmarks-Cprrli-V.js", "/assets/SavedTimelineView-DE4CXK-h.js"]
75
+ preloads: ["/assets/bookmarks-DZIMTKEp.js", "/assets/SavedTimelineView-mGXE9EYJ.js"]
76
76
  },
77
77
  "/data-sources": {
78
78
  filePath: "/Users/steipete/Projects/birdclaw/src/routes/data-sources.tsx",
79
79
  children: void 0,
80
- preloads: ["/assets/data-sources-Beb3JZkl.js", "/assets/triangle-alert-DJPCW6jQ.js"]
80
+ preloads: ["/assets/data-sources-BJUT2qaO.js", "/assets/triangle-alert-CBL7s2pf.js"]
81
81
  },
82
82
  "/discuss": {
83
83
  filePath: "/Users/steipete/Projects/birdclaw/src/routes/discuss.tsx",
84
84
  children: void 0,
85
- preloads: ["/assets/discuss-ciwVz7Fo.js", "/assets/search-C_LqodNa.js"]
85
+ preloads: ["/assets/discuss-DMPJVaRk.js", "/assets/search-Dq5kYsxA.js"]
86
86
  },
87
87
  "/dms": {
88
88
  filePath: "/Users/steipete/Projects/birdclaw/src/routes/dms.tsx",
89
89
  children: void 0,
90
- preloads: ["/assets/dms-BZ3GUPey.js", "/assets/search-C_LqodNa.js"]
90
+ preloads: ["/assets/dms-BfPFG4Qr.js", "/assets/search-Dq5kYsxA.js"]
91
91
  },
92
92
  "/inbox": {
93
93
  filePath: "/Users/steipete/Projects/birdclaw/src/routes/inbox.tsx",
94
94
  children: void 0,
95
- preloads: ["/assets/inbox-Dajdut79.js"]
95
+ preloads: ["/assets/inbox-DmeYJ7tt.js"]
96
96
  },
97
97
  "/likes": {
98
98
  filePath: "/Users/steipete/Projects/birdclaw/src/routes/likes.tsx",
99
99
  children: void 0,
100
- preloads: ["/assets/likes-CxZZqiZC.js", "/assets/SavedTimelineView-DE4CXK-h.js"]
100
+ preloads: ["/assets/likes-BxVL-j_C.js", "/assets/SavedTimelineView-mGXE9EYJ.js"]
101
101
  },
102
102
  "/links": {
103
103
  filePath: "/Users/steipete/Projects/birdclaw/src/routes/links.tsx",
104
104
  children: void 0,
105
105
  preloads: [
106
- "/assets/links-CsWS9uKL.js",
107
- "/assets/repeat-2-CQ0lek01.js",
108
- "/assets/search-C_LqodNa.js",
109
- "/assets/users-DI3w8Mol.js"
106
+ "/assets/links-BeA1Wt8F.js",
107
+ "/assets/repeat-2-xCwHM9hD.js",
108
+ "/assets/search-Dq5kYsxA.js",
109
+ "/assets/users-CHbKlqUr.js"
110
110
  ]
111
111
  },
112
112
  "/mentions": {
113
113
  filePath: "/Users/steipete/Projects/birdclaw/src/routes/mentions.tsx",
114
114
  children: void 0,
115
- preloads: ["/assets/mentions-C3JYXV2K.js", "/assets/TimelineRouteFrame-D6djyMAT.js"]
115
+ preloads: ["/assets/mentions-DBrY-UPg.js", "/assets/TimelineRouteFrame-BmMC7qLj.js"]
116
116
  },
117
117
  "/network-map": {
118
118
  filePath: "/Users/steipete/Projects/birdclaw/src/routes/network-map.tsx",
119
119
  children: void 0,
120
120
  preloads: [
121
- "/assets/network-map-D4XA7TTO.js",
122
- "/assets/search-C_LqodNa.js",
123
- "/assets/users-DI3w8Mol.js"
121
+ "/assets/network-map-MqbE164r.js",
122
+ "/assets/search-Dq5kYsxA.js",
123
+ "/assets/users-CHbKlqUr.js"
124
124
  ]
125
125
  },
126
126
  "/profile-analyze": {
127
127
  filePath: "/Users/steipete/Projects/birdclaw/src/routes/profile-analyze.tsx",
128
128
  children: void 0,
129
- preloads: ["/assets/profile-analyze-QAznTMjZ.js", "/assets/search-C_LqodNa.js"]
129
+ preloads: ["/assets/profile-analyze-DEA75Reh.js", "/assets/search-Dq5kYsxA.js"]
130
130
  },
131
131
  "/rate-limits": {
132
132
  filePath: "/Users/steipete/Projects/birdclaw/src/routes/rate-limits.tsx",
133
133
  children: void 0,
134
- preloads: ["/assets/rate-limits-eHs_5dDB.js", "/assets/triangle-alert-DJPCW6jQ.js"]
134
+ preloads: ["/assets/rate-limits-B8Wmpt9r.js", "/assets/triangle-alert-CBL7s2pf.js"]
135
135
  },
136
136
  "/today": {
137
137
  filePath: "/Users/steipete/Projects/birdclaw/src/routes/today.tsx",
138
138
  children: void 0,
139
- preloads: ["/assets/today-DxppbQGF.js"]
139
+ preloads: ["/assets/today-DFvZ0Ys5.js"]
140
140
  },
141
141
  "/profiles/$handle": {
142
142
  filePath: "/Users/steipete/Projects/birdclaw/src/routes/profiles.$handle.tsx",
143
143
  children: void 0,
144
- preloads: ["/assets/profiles._handle-qntfbCE1.js"]
144
+ preloads: ["/assets/profiles._handle-K34ofz9U.js"]
145
145
  }
146
146
  } });
147
147
  //#endregion
@@ -1,4 +1,4 @@
1
- //#region node_modules/@tanstack/start-server-core/dist/esm/empty-plugin-adapters.js
1
+ //#region node_modules/.pnpm/@tanstack+start-server-core@1.169.15/node_modules/@tanstack/start-server-core/dist/esm/empty-plugin-adapters.js
2
2
  var pluginSerializationAdapters = [];
3
3
  var hasPluginAdapters = false;
4
4
  //#endregion
@@ -521,7 +521,7 @@ function AppNav({ compact = false }) {
521
521
  }
522
522
  //#endregion
523
523
  //#region src/styles.css?url
524
- var styles_default = "/assets/styles-DTMajAmk.css";
524
+ var styles_default = "/assets/styles-zihNNCGg.css";
525
525
  //#endregion
526
526
  //#region src/routes/__root.tsx
527
527
  var Route$24 = createRootRoute({
@@ -598,7 +598,7 @@ var $$splitComponentImporter = () => import("./routes-D9226vKz.js");
598
598
  var Route$18 = createFileRoute("/")({ component: lazyRouteComponent($$splitComponentImporter, "component") });
599
599
  //#endregion
600
600
  //#region src/lib/http-effect.ts
601
- var LOCAL_HOSTS = /* @__PURE__ */ new Set([
601
+ var LOCAL_HOSTS = new Set([
602
602
  "localhost",
603
603
  "127.0.0.1",
604
604
  "::1",
@@ -2546,6 +2546,10 @@ var Route$17 = createFileRoute("/api/xurl-rate-limits")({ server: { handlers: {
2546
2546
  })) } } });
2547
2547
  //#endregion
2548
2548
  //#region src/lib/backup-table-codecs.ts
2549
+ var BACKUP_SHARD_PART_PATTERN = /\.part-\d{4,}\.jsonl$/u;
2550
+ function logicalBackupShardPath(relativePath) {
2551
+ return relativePath.replace(BACKUP_SHARD_PART_PATTERN, ".jsonl");
2552
+ }
2549
2553
  function fixedShard(relativePath, countKey) {
2550
2554
  return {
2551
2555
  shardPath: () => relativePath,
@@ -2561,7 +2565,7 @@ function yearFromTimestamp(value) {
2561
2565
  function pathLeaf(relativePath) {
2562
2566
  return relativePath.split("/").at(-1) ?? "";
2563
2567
  }
2564
- var JSON_URL_KEYS = /* @__PURE__ */ new Set([
2568
+ var JSON_URL_KEYS = new Set([
2565
2569
  "url",
2566
2570
  "expandedUrl",
2567
2571
  "expanded_url",
@@ -3514,7 +3518,7 @@ function adaptLegacyTweetState(schemaVersion, tweets, collections, timelineEdges
3514
3518
  const nextTimelineEdges = [...timelineEdges];
3515
3519
  const collectionKeys = new Set(collections.map((row) => `${String(row.account_id)}\0${String(row.tweet_id)}\0${String(row.kind)}`));
3516
3520
  const edgeKeys = new Set(timelineEdges.map((row) => `${String(row.account_id)}\0${String(row.tweet_id)}\0${String(row.kind)}`));
3517
- const edgeKinds = /* @__PURE__ */ new Set([
3521
+ const edgeKinds = new Set([
3518
3522
  "home",
3519
3523
  "mention",
3520
3524
  "authored",
@@ -3567,7 +3571,8 @@ function adaptLegacyTweetState(schemaVersion, tweets, collections, timelineEdges
3567
3571
  };
3568
3572
  }
3569
3573
  function backupCodecForPath(relativePath, codecs = BACKUP_TABLE_CODECS) {
3570
- const matches = codecs.filter((codec) => codec.matchesPath(relativePath));
3574
+ const logicalPath = logicalBackupShardPath(relativePath);
3575
+ const matches = codecs.filter((codec) => codec.matchesPath(logicalPath));
3571
3576
  if (matches.length !== 1) throw new Error(matches.length === 0 ? `No backup codec owns path: ${relativePath}` : `Multiple backup codecs own path: ${relativePath}`);
3572
3577
  return matches[0];
3573
3578
  }
@@ -3590,7 +3595,7 @@ function countBackupFiles(files, codecs = BACKUP_TABLE_CODECS) {
3590
3595
  const counts = {};
3591
3596
  for (const file of files) {
3592
3597
  if (!file.path.startsWith("data/")) continue;
3593
- const key = backupCodecForPath(file.path, codecs).countKey(file.path);
3598
+ const key = backupCodecForPath(file.path, codecs).countKey(logicalBackupShardPath(file.path));
3594
3599
  counts[key] = (counts[key] ?? 0) + file.rows;
3595
3600
  }
3596
3601
  return counts;
@@ -3996,8 +4001,9 @@ function runSubprocessEffect(options) {
3996
4001
  }
3997
4002
  //#endregion
3998
4003
  //#region src/lib/backup.ts
3999
- var BACKUP_SCHEMA_VERSION = 3;
4004
+ var BACKUP_SCHEMA_VERSION = 4;
4000
4005
  var MIN_SUPPORTED_BACKUP_SCHEMA_VERSION = 1;
4006
+ var DEFAULT_MAX_BACKUP_SHARD_BYTES = 48 * 1024 * 1024;
4001
4007
  var MANIFEST_PATH = "manifest.json";
4002
4008
  var DATA_DIR = "data";
4003
4009
  var GITATTRIBUTES_PATH = ".gitattributes";
@@ -4080,6 +4086,40 @@ function getExportRowSets(db) {
4080
4086
  function buildShards(db) {
4081
4087
  return buildBackupShardsFromRowSets(getExportRowSets(db));
4082
4088
  }
4089
+ function normalizeMaxBackupShardBytes(value) {
4090
+ const maxBytes = value ?? DEFAULT_MAX_BACKUP_SHARD_BYTES;
4091
+ if (!Number.isSafeInteger(maxBytes) || maxBytes <= 0) throw new Error("Backup shard byte limit must be a positive integer");
4092
+ return maxBytes;
4093
+ }
4094
+ function partPath(relativePath, partNumber) {
4095
+ if (!relativePath.endsWith(".jsonl")) throw new Error(`Backup shard path must end in .jsonl: ${relativePath}`);
4096
+ return relativePath.replace(/\.jsonl$/u, `.part-${String(partNumber).padStart(4, "0")}.jsonl`);
4097
+ }
4098
+ function splitJsonlShard(relativePath, rows, maxBytes) {
4099
+ const parts = [];
4100
+ let currentRows = [];
4101
+ let currentBytes = 0;
4102
+ for (const [index, row] of rows.entries()) {
4103
+ const rowBytes = Buffer.byteLength(jsonlStringify(row)) + 1;
4104
+ if (rowBytes > maxBytes) throw new Error(`Backup row exceeds shard byte limit: ${relativePath}:${index + 1} is ${rowBytes} bytes (limit ${maxBytes})`);
4105
+ if (currentRows.length > 0 && currentBytes + rowBytes > maxBytes) {
4106
+ parts.push(currentRows);
4107
+ currentRows = [];
4108
+ currentBytes = 0;
4109
+ }
4110
+ currentRows.push(row);
4111
+ currentBytes += rowBytes;
4112
+ }
4113
+ if (currentRows.length > 0) parts.push(currentRows);
4114
+ if (parts.length <= 1) return [{
4115
+ relativePath,
4116
+ rows: parts[0] ?? []
4117
+ }];
4118
+ return parts.map((partRows, index) => ({
4119
+ relativePath: partPath(relativePath, index + 1),
4120
+ rows: partRows
4121
+ }));
4122
+ }
4083
4123
  function writeJsonlFileEffect(repoPath, relativePath, rows) {
4084
4124
  return Effect.gen(function* () {
4085
4125
  const fullPath = yield* trySync$10(() => resolveBackupFilePath(repoPath, relativePath));
@@ -4165,6 +4205,7 @@ data/follow_events.jsonl
4165
4205
  \`\`\`
4166
4206
 
4167
4207
  Tweets are sharded by creation year. Collection-only tweets whose creation date is unknown live in \`data/tweets/unknown.jsonl\`. Timeline edges keep account-scoped home/mention membership separate from canonical tweet content. DMs are sharded by year and keep \`conversation_id\` in each row.
4208
+ Logical shards larger than 48 MiB are split into deterministic \`.part-0001.jsonl\` files so ordinary Git hosting remains usable without Git LFS.
4168
4209
  The links shard stores expanded short URLs and their source tweet/DM occurrences so linked-tweet search can be rebuilt without re-expanding every \`t.co\` URL.
4169
4210
 
4170
4211
  Never commit live tokens, browser cookies, raw SQLite WAL/SHM sidecars, or temporary cache files here.
@@ -4398,7 +4439,7 @@ function pullBackupGitRepoEffect(repoPath) {
4398
4439
  ]).pipe(Effect.as(true), Effect.catchAll(() => Effect.succeed(false)))));
4399
4440
  });
4400
4441
  }
4401
- function exportBackupEffect({ repoPath, db, commit = false, push = false, message = "archive: update birdclaw backup", validate = true }) {
4442
+ function exportBackupEffect({ repoPath, db, commit = false, push = false, message = "archive: update birdclaw backup", validate = true, maxShardBytes }) {
4402
4443
  return Effect.gen(function* () {
4403
4444
  const resolvedRepoPath = yield* trySync$10(() => path.resolve(repoPath));
4404
4445
  const database = db ?? (yield* trySync$10(() => getNativeDb({ seedDemoData: false })));
@@ -4407,10 +4448,12 @@ function exportBackupEffect({ repoPath, db, commit = false, push = false, messag
4407
4448
  if (!repoStat.isDirectory() || repoStat.isSymbolicLink()) return yield* Effect.fail(/* @__PURE__ */ new Error("Backup repository path must be a real directory"));
4408
4449
  yield* ensureBackupGitattributesEffect(resolvedRepoPath);
4409
4450
  yield* ensureBackupReadmeEffect(resolvedRepoPath);
4451
+ const maxBytes = yield* trySync$10(() => normalizeMaxBackupShardBytes(maxShardBytes));
4410
4452
  const shards = yield* trySync$10(() => buildShards(database));
4411
4453
  const shardEntries = yield* trySync$10(() => [...shards.entries()].sort(([left], [right]) => left.localeCompare(right)));
4412
- const expectedPaths = yield* trySync$10(() => new Set(shardEntries.map(([relativePath]) => relativePath)));
4413
- const files = yield* Effect.forEach(shardEntries, ([relativePath, rows]) => writeJsonlFileEffect(resolvedRepoPath, relativePath, rows), { concurrency: "unbounded" });
4454
+ const shardParts = yield* trySync$10(() => shardEntries.flatMap(([relativePath, rows]) => splitJsonlShard(relativePath, rows, maxBytes)));
4455
+ const expectedPaths = yield* trySync$10(() => new Set(shardParts.map(({ relativePath }) => relativePath)));
4456
+ const files = yield* Effect.forEach(shardParts, ({ relativePath, rows }) => writeJsonlFileEffect(resolvedRepoPath, relativePath, rows), { concurrency: 1 });
4414
4457
  yield* removeStaleBackupFilesEffect(resolvedRepoPath, expectedPaths);
4415
4458
  const counts = yield* trySync$10(() => countBackupFiles(files));
4416
4459
  const backupHash = yield* trySync$10(() => computeBackupHash(files));
@@ -4526,7 +4569,7 @@ function readBackupImportRowsEffect(resolvedRepoPath, manifest) {
4526
4569
  });
4527
4570
  }
4528
4571
  function rowsForManifestPath(manifest, predicate) {
4529
- return manifest.files.map((file) => file.path).filter(predicate).sort();
4572
+ return manifest.files.map((file) => file.path).filter((relativePath) => predicate(logicalBackupShardPath(relativePath))).sort();
4530
4573
  }
4531
4574
  function importBackupEffect({ repoPath, db: providedDb, validate = true, mode = "merge" }) {
4532
4575
  return Effect.gen(function* () {
@@ -4901,7 +4944,7 @@ function validateBackupEffect(repoPath) {
4901
4944
  file,
4902
4945
  errors: fileErrors
4903
4946
  };
4904
- }), { concurrency: "unbounded" });
4947
+ }), { concurrency: 1 });
4905
4948
  const files = [];
4906
4949
  for (const result of results) {
4907
4950
  errors.push(...result.errors);
@@ -5338,9 +5381,11 @@ function parseBirdWhoami(stdout) {
5338
5381
  if (/[A-Za-z@]/.test(line)) return;
5339
5382
  return line.match(/^\D*(\d{2,})\D*$/)?.[1];
5340
5383
  }).find((value) => Boolean(value));
5384
+ const name = stdout.match(/@[A-Za-z0-9_]{1,15}\s*\(([^)]+)\)/)?.[1]?.trim();
5341
5385
  return {
5342
5386
  username: usernameMatch[1],
5343
- ...id ? { id } : {}
5387
+ ...id ? { id } : {},
5388
+ ...name ? { name } : {}
5344
5389
  };
5345
5390
  }
5346
5391
  function getAuthenticatedBirdAccountEffect() {
@@ -5776,7 +5821,7 @@ function runOAuth2JsonCommandEffect({ args, username, options, useConfiguredCand
5776
5821
  return yield* runJsonCommandEffect(oauth2ArgsForCandidate(authCandidate, args), scopedOptions).pipe(Effect.catchAll((error) => {
5777
5822
  if (!primaryUsername) return Effect.fail(error);
5778
5823
  oauth2CandidateCache.delete(primaryUsername.toLowerCase());
5779
- const attempted = /* @__PURE__ */ new Set([authCandidate ? `${authCandidate.app ?? "default"}:${authCandidate.username}` : `default:${primaryUsername}`]);
5824
+ const attempted = new Set([authCandidate ? `${authCandidate.app ?? "default"}:${authCandidate.username}` : `default:${primaryUsername}`]);
5780
5825
  if (authCandidate?.username !== primaryUsername) attempted.add(`default:${primaryUsername}`);
5781
5826
  return lookupOAuth2UsernameForAccountEffect(primaryUsername, attempted, deadlineMs).pipe(Effect.flatMap((fallbackUsername) => {
5782
5827
  if (!fallbackUsername) return Effect.fail(error);
@@ -6412,8 +6457,8 @@ var MAX_AVATAR_BYTES = 2 * 1024 * 1024;
6412
6457
  var MAX_AVATAR_DATA_URL_CHARS = MAX_AVATAR_BYTES * 4;
6413
6458
  var REMOTE_AVATAR_TIMEOUT_MS = 1e4;
6414
6459
  var DEFAULT_AVATAR_PREFETCH_CONCURRENCY = 8;
6415
- var ALLOWED_REMOTE_AVATAR_HOSTS = /* @__PURE__ */ new Set(["pbs.twimg.com"]);
6416
- var RASTER_CONTENT_TYPES = /* @__PURE__ */ new Set([
6460
+ var ALLOWED_REMOTE_AVATAR_HOSTS = new Set(["pbs.twimg.com"]);
6461
+ var RASTER_CONTENT_TYPES = new Set([
6417
6462
  "image/jpeg",
6418
6463
  "image/png",
6419
6464
  "image/webp",
@@ -8211,7 +8256,7 @@ function listMentionsByIds(db, accountId, tweetIds, limit) {
8211
8256
  }
8212
8257
  function mergeMentionThreadIntoLocalStore({ db, accountId, accountHandle, mentionIds, payload, source = "bird", writeThreadContextEdges = false }) {
8213
8258
  const usersById = new Map((payload.includes?.users ?? []).map((user) => [user.id, user]));
8214
- const groups = /* @__PURE__ */ new Map([
8259
+ const groups = new Map([
8215
8260
  ["mention", []],
8216
8261
  ["home", []],
8217
8262
  ["thread", []]
@@ -8272,7 +8317,7 @@ function fetchParentChainViaXurlEffect({ mention, maxDepth, timeoutMs, deadlineM
8272
8317
  return Effect.gen(function* () {
8273
8318
  const pages = [];
8274
8319
  const warnings = [];
8275
- const seenTweetIds = /* @__PURE__ */ new Set([mention.id]);
8320
+ const seenTweetIds = new Set([mention.id]);
8276
8321
  let nextParentId = mention.replyToId;
8277
8322
  let fallbackDepth = 0;
8278
8323
  let generalReadTweets = 0;
@@ -8318,7 +8363,7 @@ function fetchParentChainViaXurlEffect({ mention, maxDepth, timeoutMs, deadlineM
8318
8363
  }
8319
8364
  function findMissingAncestorId(mention, payload) {
8320
8365
  const tweetsById = new Map(payload.data.map((tweet) => [tweet.id, tweet]));
8321
- const seenTweetIds = /* @__PURE__ */ new Set([mention.id]);
8366
+ const seenTweetIds = new Set([mention.id]);
8322
8367
  const anchorTweet = tweetsById.get(mention.id) ?? mention.rawTweet;
8323
8368
  let nextParentId = anchorTweet ? getReplyToId(anchorTweet) : mention.replyToId;
8324
8369
  while (nextParentId) {
@@ -10665,6 +10710,26 @@ var DEFAULT_DELIMITER_HOLD = 8;
10665
10710
  function toError$13(error) {
10666
10711
  return error instanceof Error ? error : new Error(String(error));
10667
10712
  }
10713
+ var DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
10714
+ /**
10715
+ * Resolve the OpenAI-compatible API base URL. Point this at Ollama
10716
+ * (`http://localhost:11434/v1`) or any other OpenAI-compatible server via
10717
+ * the Birdclaw-specific `BIRDCLAW_OPENAI_BASE_URL`. The previously shipped
10718
+ * `OPENAI_BASE_URL` setting remains a lower-priority compatibility fallback.
10719
+ * A trailing slash is trimmed so callers can safely append `/responses` etc.
10720
+ */
10721
+ function resolveOpenAIBaseUrl(getEnv) {
10722
+ return ((getEnv("BIRDCLAW_OPENAI_BASE_URL") || getEnv("OPENAI_BASE_URL"))?.trim() || DEFAULT_OPENAI_BASE_URL).replace(/\/+$/, "");
10723
+ }
10724
+ /**
10725
+ * Emit an OpenAI-transport debug line to stderr when `BIRDCLAW_DEBUG` is set.
10726
+ * Gated so normal runs stay quiet; enable with `BIRDCLAW_DEBUG=1`.
10727
+ */
10728
+ function debugLog(getEnv, message) {
10729
+ if (!getEnv("BIRDCLAW_DEBUG")) return;
10730
+ if (typeof process === "undefined") return;
10731
+ process.stderr.write(`[birdclaw:openai] ${message}\n`);
10732
+ }
10668
10733
  function createOpenAIStreamState() {
10669
10734
  return {
10670
10735
  eventBuffer: "",
@@ -10762,7 +10827,9 @@ function requestOpenAIResponseEffect({ body, signal, runtime = defaultRuntimeSer
10762
10827
  return Effect.gen(function* () {
10763
10828
  const apiKey = runtime.env("OPENAI_API_KEY");
10764
10829
  if (!apiKey) return yield* Effect.fail(/* @__PURE__ */ new Error("OPENAI_API_KEY is not set"));
10765
- const response = yield* tryPromise(() => runtime.fetch("https://api.openai.com/v1/responses", {
10830
+ const url = `${resolveOpenAIBaseUrl(runtime.env)}/responses`;
10831
+ debugLog(runtime.env, `POST ${url}`);
10832
+ const response = yield* tryPromise(() => runtime.fetch(url, {
10766
10833
  method: "POST",
10767
10834
  signal,
10768
10835
  headers: {
@@ -10770,11 +10837,13 @@ function requestOpenAIResponseEffect({ body, signal, runtime = defaultRuntimeSer
10770
10837
  "content-type": "application/json"
10771
10838
  },
10772
10839
  body: JSON.stringify(body)
10773
- })).pipe(Effect.mapError(toError$13));
10840
+ })).pipe(Effect.mapError(toError$13), Effect.tapError((error) => Effect.sync(() => debugLog(runtime.env, `network error for ${url}: ${error.message}`))));
10774
10841
  if (!response.ok) {
10775
10842
  const text = yield* tryPromise(() => response.text()).pipe(Effect.mapError(toError$13));
10843
+ debugLog(runtime.env, `${url} -> ${String(response.status)} ${text.slice(0, 400)}`);
10776
10844
  return yield* Effect.fail(/* @__PURE__ */ new Error(`OpenAI request failed: ${String(response.status)} ${text.slice(0, 400)}`));
10777
10845
  }
10846
+ debugLog(runtime.env, `${url} -> ${String(response.status)} OK`);
10778
10847
  return response;
10779
10848
  });
10780
10849
  }
@@ -11407,7 +11476,7 @@ function runModeEffect(mode, options) {
11407
11476
  }
11408
11477
  function combineTweetSearchResults(left, right, limit) {
11409
11478
  if (left.ok && right.ok) {
11410
- const tweetIds = [.../* @__PURE__ */ new Set([...left.tweetIds, ...right.tweetIds])].slice(0, limit);
11479
+ const tweetIds = [...new Set([...left.tweetIds, ...right.tweetIds])].slice(0, limit);
11411
11480
  const liveSources = new Set([left.source, right.source].filter((source) => source !== "cache"));
11412
11481
  return {
11413
11482
  ok: true,
@@ -13014,7 +13083,7 @@ var Route$11 = createFileRoute("/api/profile-analysis")({ server: { handlers: {
13014
13083
  //#region src/lib/link-insights.ts
13015
13084
  var DEFAULT_LIMIT$1 = 30;
13016
13085
  var DEFAULT_COMMENTS_LIMIT = 8;
13017
- var TRACKING_PARAMS = /* @__PURE__ */ new Set([
13086
+ var TRACKING_PARAMS = new Set([
13018
13087
  "fbclid",
13019
13088
  "gclid",
13020
13089
  "igshid",
@@ -13033,17 +13102,17 @@ var VIDEO_HOST_SUFFIXES = [
13033
13102
  "tiktok.com",
13034
13103
  "loom.com"
13035
13104
  ];
13036
- var VIDEO_EXACT_HOSTS = /* @__PURE__ */ new Set([
13105
+ var VIDEO_EXACT_HOSTS = new Set([
13037
13106
  "youtu.be",
13038
13107
  "clips.twitch.tv",
13039
13108
  "vm.tiktok.com"
13040
13109
  ]);
13041
13110
  var EXCLUDED_HOST_SUFFIXES = ["x.com", "twitter.com"];
13042
- var EXCLUDED_EXACT_HOSTS = /* @__PURE__ */ new Set(["t.co"]);
13111
+ var EXCLUDED_EXACT_HOSTS = new Set(["t.co"]);
13043
13112
  var URL_WHITESPACE = /\s+/g;
13044
13113
  var RAW_URL_PATTERN = /https?:\/\/[^\s<>"'`]+/g;
13045
13114
  var SQL_URL_EXPRESSION = "lower(coalesce(nullif(e.final_url, ''), nullif(e.expanded_url, ''), e.short_url))";
13046
- var TITLE_SEGMENT_STOPWORDS = /* @__PURE__ */ new Set([
13115
+ var TITLE_SEGMENT_STOPWORDS = new Set([
13047
13116
  "a",
13048
13117
  "about",
13049
13118
  "blog",
@@ -13056,7 +13125,7 @@ var TITLE_SEGMENT_STOPWORDS = /* @__PURE__ */ new Set([
13056
13125
  "story",
13057
13126
  "watch"
13058
13127
  ]);
13059
- var TITLE_WORD_OVERRIDES = /* @__PURE__ */ new Map([
13128
+ var TITLE_WORD_OVERRIDES = new Map([
13060
13129
  ["ai", "AI"],
13061
13130
  ["api", "API"],
13062
13131
  ["codex", "Codex"],
@@ -13067,7 +13136,7 @@ var TITLE_WORD_OVERRIDES = /* @__PURE__ */ new Map([
13067
13136
  ["url", "URL"],
13068
13137
  ["wwdc", "WWDC"]
13069
13138
  ]);
13070
- var TITLE_SMALL_WORDS = /* @__PURE__ */ new Set([
13139
+ var TITLE_SMALL_WORDS = new Set([
13071
13140
  "a",
13072
13141
  "an",
13073
13142
  "and",
@@ -13216,7 +13285,7 @@ function stripUrls(text, urls) {
13216
13285
  let output = text;
13217
13286
  for (const url of urls) {
13218
13287
  if (!url) continue;
13219
- const variants = /* @__PURE__ */ new Set([url]);
13288
+ const variants = new Set([url]);
13220
13289
  try {
13221
13290
  const parsed = new URL(url);
13222
13291
  variants.add(parsed.href);
@@ -13603,9 +13672,9 @@ function getLinkInsights(query = {}) {
13603
13672
  kind: rowKind,
13604
13673
  lastSeenAt: row.created_at,
13605
13674
  mentions: [mention],
13606
- seenMentions: /* @__PURE__ */ new Set([mention.id]),
13607
- sharers: /* @__PURE__ */ new Set([sharerKey]),
13608
- sharerProfiles: mention.sharedBy ? /* @__PURE__ */ new Map([[mention.sharedBy.id, mention.sharedBy]]) : /* @__PURE__ */ new Map(),
13675
+ seenMentions: new Set([mention.id]),
13676
+ sharers: new Set([sharerKey]),
13677
+ sharerProfiles: mention.sharedBy ? new Map([[mention.sharedBy.id, mention.sharedBy]]) : /* @__PURE__ */ new Map(),
13609
13678
  shareCount: 1,
13610
13679
  title: row.title,
13611
13680
  topSharer: mention.sharedBy ?? null,
@@ -14471,7 +14540,7 @@ var LETTER_PATTERN = /[a-z]/i;
14471
14540
  var URL_OR_HANDLE_PATTERN = /(https?:\/\/|@|[A-Z0-9._%+-]+@[A-Z0-9.-]+)/i;
14472
14541
  var MONEY_PATTERN = /\$\s?\d/;
14473
14542
  var EMOJI_BLOCK_PATTERN = /[\u{1f1e6}-\u{1f1ff}\u{1f300}-\u{1faff}\u{2600}-\u{27bf}]/gu;
14474
- var GENERIC_LOCATIONS = /* @__PURE__ */ new Set([
14543
+ var GENERIC_LOCATIONS = new Set([
14475
14544
  "earth",
14476
14545
  "everywhere",
14477
14546
  "internet",
@@ -14489,7 +14558,7 @@ var GENERIC_LOCATIONS = /* @__PURE__ */ new Set([
14489
14558
  "world",
14490
14559
  "world wide web"
14491
14560
  ]);
14492
- var DROP_WORDS = /* @__PURE__ */ new Set([
14561
+ var DROP_WORDS = new Set([
14493
14562
  "a",
14494
14563
  "an",
14495
14564
  "and",
@@ -15043,7 +15112,7 @@ function upsertUrlExpansion(db, item) {
15043
15112
  var FETCH_TIMEOUT_MS = 12e3;
15044
15113
  var MAX_HTML_CHARS = 2e6;
15045
15114
  var MAX_REDIRECTS = 4;
15046
- var NO_BODY_STATUS_CODES = /* @__PURE__ */ new Set([
15115
+ var NO_BODY_STATUS_CODES = new Set([
15047
15116
  204,
15048
15117
  205,
15049
15118
  304
@@ -15517,6 +15586,7 @@ var Route$7 = createFileRoute("/api/link-insights")({ server: { handlers: { GET:
15517
15586
  })) } } });
15518
15587
  //#endregion
15519
15588
  //#region src/lib/openai.ts
15589
+ var getEnv = (name) => process.env[name];
15520
15590
  function clampScore(value) {
15521
15591
  return Math.max(0, Math.min(100, Math.round(value)));
15522
15592
  }
@@ -15534,7 +15604,9 @@ function scoreInboxItemWithOpenAIEffect(input) {
15534
15604
  const apiKey = process.env.OPENAI_API_KEY;
15535
15605
  if (!apiKey) return yield* Effect.fail(/* @__PURE__ */ new Error("OPENAI_API_KEY is not set"));
15536
15606
  const model = process.env.BIRDCLAW_OPENAI_MODEL || "gpt-5.2";
15537
- const response = yield* tryPromise(() => fetch("https://api.openai.com/v1/chat/completions", {
15607
+ const url = `${resolveOpenAIBaseUrl(getEnv)}/chat/completions`;
15608
+ debugLog(getEnv, `POST ${url} (model=${model})`);
15609
+ const response = yield* tryPromise(() => fetch(url, {
15538
15610
  method: "POST",
15539
15611
  headers: {
15540
15612
  authorization: `Bearer ${apiKey}`,
@@ -15551,8 +15623,12 @@ function scoreInboxItemWithOpenAIEffect(input) {
15551
15623
  content: JSON.stringify(input)
15552
15624
  }]
15553
15625
  })
15554
- })).pipe(Effect.mapError(toError$7));
15555
- if (!response.ok) return yield* Effect.fail(/* @__PURE__ */ new Error(`OpenAI request failed: ${response.status}`));
15626
+ })).pipe(Effect.mapError(toError$7), Effect.tapError((error) => Effect.sync(() => debugLog(getEnv, `network error for ${url}: ${error.message}`))));
15627
+ if (!response.ok) {
15628
+ const text = yield* tryPromise(() => response.text()).pipe(Effect.mapError(toError$7));
15629
+ debugLog(getEnv, `${url} -> ${response.status} ${text.slice(0, 400)}`);
15630
+ return yield* Effect.fail(/* @__PURE__ */ new Error(`OpenAI request failed: ${response.status} ${text.slice(0, 400)}`));
15631
+ }
15556
15632
  const content = (yield* tryPromise(() => response.json()).pipe(Effect.mapError(toError$7))).choices?.[0]?.message?.content;
15557
15633
  if (!content) return yield* Effect.fail(/* @__PURE__ */ new Error("OpenAI returned no content"));
15558
15634
  const parsed = yield* trySync$6(() => JSON.parse(content));
@@ -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 };