Skip to content

W8: Fold the refreshed link metadata into the just-posted feed row #96

Closed

Description

@Adron

Split out of #91 (see PR #94), which wired POST /api/messages/{id}/metadata after publishing but
stopped short of using its response.

Where it stands

After #94, posting a message with a link fires the metadata refresh. The preview appears on the
next feed fetch — not on the row that was just inserted locally. That matches the web, so this is
a polish item, not a bug.

Why it wasn't done in #94

Two different shapes:

  • The feed row renders message.linkMetadata?.links → [LinkMetadataItem] (nested metadata object)
  • refreshMessageMetadata returns [MessageLinkPreview] (flat image / title)

Folding one into the other needs a conversion plus a new AppDataStore mutation to update an
already-inserted message in place. That was outside "wire the existing call", so it was called out
rather than smuggled in.

Build this

  • A conversion from [MessageLinkPreview] to [LinkMetadataItem] — pure and unit-testable, not
    inline in a view.
  • An AppDataStore mutation that replaces the linkMetadata of one already-inserted message by id.
  • ComposeView applies the refresh response through it, still fire-and-forget: a failure must
    leave the row exactly as it is, with no error surfaced.
  • No extra request — reuse the response feat(messages): refresh link metadata after publishing #94 already receives and currently discards.

Acceptance criteria

  • Posting a message with a link shows its preview without waiting for a feed refresh.
  • A failed or empty metadata response leaves the row unchanged and silent.
  • Unit tests for the shape conversion (including an entry with no image and no title) and for the
    store mutation targeting the right message.

Files: Views/ComposeView.swift, Services/AppDataStore.swift, Models/Message.swift.

Activity

  1. Adron commented on Sep 16, 2026

    @Adron
    MemberAuthor

    Implemented in #103 (stacked on #94). Closing here — further work tracks in the PR.

    Read before merging: the conversion is correct but the pipeline is inert

    The two shapes convert cleanly, so #103 does what this issue asked. But nothing user-visible
    changes yet
    , because of two problems on either side of it — neither introduced by #103, both
    verified independently:

    1. refreshMessageMetadata decodes a shape the route never sends — filed as Bug: refreshMessageMetadata decodes a response shape the route never sends — always returns [] #104. It expects
      {"metadata":{"links":[…]}}; app/api/messages/[id]/metadata/route.ts:105 returns
      serialize({ links }) — top-level, with full LinkMetadataItem entries. Against the live API the
      decode yields [] every time. The existing test passes only because its fixture was written to
      the assumed shape.
    2. FeedView cannot see an in-place row update — filed as Bug: FeedView cannot see in-place row updates — merges only unseen ids, keyed on count #105. It mirrors store.feedMessages
      into a private @State and merges only unseen ids, keyed on .count (FeedView.swift:385).
      Replacing a row's linkMetadata changes content, not count.

    #103 is still worth landing: the conversion and the store mutation are exactly what both fixes will
    consume, and they are tested. But the chain only becomes visible once #104 and #105 land.

    Note this does not invalidate #94 — that PR fires the POST and ignores the response, and the POST
    still makes the server fetch and persist the metadata, so "preview appears on the next feed fetch"
    works today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestws:papercutsW8 — small parity papercuts

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions