**Context:** #9306 (merged) added link-preview tags to the invite page. To build the media URLs, the relay looks up the community for the request host. This fixes a problem found in our review of #9306. **Problem:** The invite page waits for that lookup with no time limit. When the database is slow, the lookup can take as long as the pool acquire timeout (3 s) plus the statement timeout (120 s by default). During that time, a person who opens an invite link gets no page. Before #9306, this page did not use the database. **Fix:** The lookup gets 250 ms. If it does not finish, the relay sends the page without the preview tags. A healthy indexed host lookup finishes well inside that, so crawlers still get the tags, and nothing else changes: the media route, the router and the build are untouched. ### Validation - Added test: a host whose lookup never finishes gets the plain page. Without the timeout, this test hangs (confirmed locally; it was killed after 30 s). - The existing `invite_preview` and router invite tests pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Tom Brow <tomb@squareup.com> Co-authored-by: Tom Brow <tomb@squareup.com> Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@buzz.block.builderlab.xyz>
Invite preview media
A 16-second silent Buzz animation and wordmark-only PNG fallback, with a browser tool for reviewing motion and choosing poster frames. The animation uses the onboarding wordmark and fuzzy shader, pale-blue/lime bees, diagonal paired flights and a solo loop-de-loop.
Preview
From the repository root:
python3 -m http.server 4319 --bind 127.0.0.1 --directory previews/invite-video
Open http://127.0.0.1:4319. Scrub or choose a suggested frame, then select Use this frame. Poster choices persist only in that browser; Download poster PNG exports the choice. The committed poster is the approved wordmark-only frame at 0 seconds. The iMessage-style card is a composition simulation, not evidence of a native Messages unfurl.
Media
buzz-invite-loop.mp4: 960 × 540, 30 fps, H.264/yuv420p, fast-start, no audio.buzz-invite-poster.png: 960 × 540, wordmark only.buzz-wordmark.pngandwordmark.frag: onboarding artwork and 400 ms grain/displacement shader, from the Buzz desktop onboarding implementation; bee silhouette matches the mobile welcome artwork.- Background:
#D7D72E; bees:#D7E7F5and#DBFA52.
Verify or regenerate
Activate the repository's Hermit environment first. Install Chrome, Python 3, and ffmpeg. Then:
cd previews/invite-video
npm ci
npm test
npm run render
Verification starts an isolated localhost server and checks poster selection, PNG export, persistence, loop continuity, mobile overflow and reduced-motion startup. Rendering also rebuilds both committed media files. Temporary captures stay in .output/. PREVIEW_BROWSER may select another installed Playwright Chromium channel.
Production invite previews
The production web build includes the approved MP4 and wordmark-only poster at
/assets/invite-preview/buzz-invite-loop-v1.mp4 and
/assets/invite-preview/buzz-invite-poster-v1.png. The relay adds Open Graph
metadata to the initial HTML for /invite/<code> only. Previews are generic and
do not validate or redeem the invite.
Deploy both the updated relay and its web bundle (the relay Docker image includes
both). The media host comes from the request's resolved community, matching the
invite link's host. RELAY_URL supplies only the wss/ws TLS posture, mapped to
https/http. Unmapped hosts, lookup failures and slow lookups receive no preview metadata.
Each community host must serve the web bundle without authentication. Use HTTPS
in production.
After deployment, inspect an invite response with curl for og:video and
og:image, then fetch both referenced URLs and check that they return MP4/PNG
content rather than a login page. The video endpoint supports HTTP range
requests. Share a fresh invite link in Messages to test actual playback; receiving
apps decide whether to play video or use the poster, and may cache previews.
When replacing approved media, bump the versioned filenames in both
web/vite.config.ts and crates/buzz-relay/src/invite_preview.rs to avoid stale
cached media.
The receiving app chooses playback behavior. The 16-second duration is an animation choice, not an asserted platform limit.