diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-08-28 03:43:29 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-08-28 03:43:29 +0200 |
| commit | 25ebaed11772056c611c3ce650387d6961e0baa0 (patch) | |
| tree | e22bee25a2cdf3e11cbfce2525728d2010ab85d8 /packages/meshbay-hub/src/meshbay_hub/static/transport.js | |
| parent | 2f573b4143212b21d92ff20179356acb8f8fe635 (diff) | |
| parent | ce4e10c4b8bd9c66c375c3a5d5c18d8552655775 (diff) | |
| download | meshbay-25ebaed11772056c611c3ce650387d6961e0baa0.tar.gz | |
Merge branch 'feat/chat-link-previews'
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/transport.js')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/transport.js | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/transport.js b/packages/meshbay-hub/src/meshbay_hub/static/transport.js index 9f85ee1..1a146ce 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/transport.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/transport.js @@ -847,6 +847,20 @@ class MeshBayTransport { } /** + * Unfurl a URL pasted in chat. The node fetches it (the browser cannot — + * CSP and CORS — and would leak every reader's IP), parses an OpenGraph + * card, and caches any image in its thumb store; `image_thumb_hash` then + * rides the normal file_req path like a poster. `ok: false` means "no + * preview" (blocked, unreachable, not HTML) — the caller just shows the + * bare link. Keyed by url: a message with several links fires one each. + */ + async fetchLinkPreview(url) { + const msg = await this._sendAndWait({ type: 'link_preview_req', v: '0.6', url }); + if (msg.type === 'error') throw new Error(msg.detail); + return msg; + } + + /** * One season's own overview/air_date/poster (docs/mediacenter.md §5.4's * per-season view) — a show's own tmdb_meta is one static field that does * not necessarily describe every season alike, found live: a 3-season @@ -1854,6 +1868,9 @@ class MeshBayTransport { ? `chunk:${obj.file_id}:${obj.chunk_index}` : obj.type === 'ping' ? `ping:${obj.token}` : obj.type === 'media_meta_req' ? `media_meta:${obj.file_id}` + // One chat message can carry several links, each unfurled on its + // own; matching by arrival order would swap two cards. + : obj.type === 'link_preview_req' ? `link_preview:${obj.url}` // Same reordering hazard as media_meta_req: an album grid fires // one music_meta_req per visible tile, several at a time. : obj.type === 'music_meta_req' ? `music_meta:${obj.file_id}` @@ -2171,6 +2188,16 @@ class MeshBayTransport { return; } + // Same reasoning as media_meta_resp: keyed by url, and "nobody's waiting" + // must not fall through. + if (msg.type === 'link_preview_resp') { + const key = `link_preview:${msg.url}`; + for (const [, handler] of this._pending) { + if (handler._key === key) { handler.resolve(msg); return; } + } + return; + } + // Same reasoning as media_meta_resp: keyed, not arrival-order, and // "nobody's waiting any more" must not fall through either. if (msg.type === 'music_meta_resp') { |