Skip to content

feat(messages): refresh link metadata after publishing - #94

Merged
Adron merged 2 commits into
mainfrom
feat/refresh-link-metadata-after-publish
Sep 17, 2026
Merged

Adron merged 2 commits into
mainfrom
feat/refresh-link-metadata-after-publish

Conversation

@Adron

@Adron Adron commented Sep 16, 2026

Copy link
Copy Markdown
Member

Summary

Closes #91. APIClient.refreshMessageMetadata(messageId:) was implemented and unit-tested but had no
caller, so a freshly published message's OpenGraph link previews stayed empty until something else
backfilled them. ComposeView now fires POST /api/messages/{id}/metadata after a successful
publish, the same way the web composer does (components/messages/MessageInput.tsx:511).

The call is guarded on the posted content actually containing a link, and it is fire-and-forget: it
is never awaited on the publish path and every failure is swallowed, so it can neither surface an
error nor delay the success alert or the dismiss. A 401 from this route is not escalated either —
the post that just succeeded proves the session is live.

The edit path deliberately does not call it: no route accepts a content edit today
(PATCH /api/messages/{id} is the reschedule route, see #76). That is recorded as a comment on the
new helper.

What's included

  • ComposeView.postMessage() calls the new refreshLinkMetadata(for:) after a successful publish,
    only when firstDetectedHTTPURL(in: text) != nil. A link-free message issues no request.
  • URL detection extracted from the composer's private firstDetectedURL property into a file-level
    firstDetectedHTTPURL(in:) — the same detector the live preview card already used, now shared by
    the publish guard and directly testable. (Same shape as feedTruncated in FeedView.swift.)
  • New ComposeLinkDetectionTests (9 tests) covering the detector and the publish guard, registered
    in project.pbxproj.
  • The "no caller yet" comment on refreshMessageMetadata referenced in the issue is not on main
    (it landed on a different branch), so the function's existing one-line doc comment is untouched.

Not included, deliberately: the response's links are not folded back into AppDataStore's inserted
feed message. The refresh response is [MessageLinkPreview] while the feed row renders
message.linkMetadata?.links ([LinkMetadataItem]), so wiring that up means a new store mutation
plus a shape conversion — out of scope here, and the web has the same behaviour (the preview lands on
the next feed fetch).

Testing

  • Full suite on simulator 9140C403-1629-4BEC-8675-11757BDEB22C, serialized, E2E skipped:
    1156 tests, 0 failures.
  • New ComposeLinkDetectionTests: 9 tests, 0 failures.
    • Detector: empty content, plain prose, http, https, first-of-several, mailto rejected.
    • Guard: link-free content issues no request (requestHistory empty); linked content issues
      exactly one POST to /api/messages/{id}/metadata; a 500 is swallowed without throwing.
  • xcodebuild build: BUILD SUCCEEDED, no new warnings.
  • Not verified: the live end-to-end "preview appears in the feed" path, which needs a real account
    and a real OpenGraph fetch.

🤖 Generated with Claude Code

ComposeView now fires POST /api/messages/{id}/metadata after a successful
publish, matching the web composer, so a new post's OpenGraph previews
populate without waiting for something else to backfill them.

The call is guarded on the posted content actually containing a link and is
fire-and-forget: it is never awaited on the publish path and every failure is
swallowed, so it cannot surface an error or delay the success alert. The edit
path deliberately does not call it — no route accepts a content edit today
(see #76).

URL detection is extracted from the composer's live-preview property into
firstDetectedHTTPURL(in:) so the preview card and the publish guard share one
answer and the guard is directly testable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bss5MgZa7Jvj2m9zdaUd1
@Adron
Adron merged commit a2fca66 into main Sep 17, 2026
1 check passed
@Adron
Adron deleted the feat/refresh-link-metadata-after-publish branch September 17, 2026 09:03
Adron added a commit that referenced this pull request Sep 17, 2026
One conflict, in APIClient.swift, resolved by taking this branch's version.
Main carries the "No caller yet, deliberately" note #90 added to
refreshMessageMetadata; that became stale the moment #94 wired the call from
ComposeView, and this branch replaces it with a comment describing the route's
actual response shape. Keeping both would have restated a claim the code now
contradicts.

Verified after resolving: the stale note is gone, the decode reads top-level
`links` as required, and MessageLinkPreview has no remaining references.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bss5MgZa7Jvj2m9zdaUd1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

W8: Refresh link-preview metadata after publishing a message

1 participant