Skip to content

feat: restore attachment fetchData after queue/debounce serialization#338

Open
dancer wants to merge 8 commits intomainfrom
josh/fix-fetchdata-serialization
Open

feat: restore attachment fetchData after queue/debounce serialization#338
dancer wants to merge 8 commits intomainfrom
josh/fix-fetchdata-serialization

Conversation

@dancer
Copy link
Copy Markdown
Contributor

@dancer dancer commented Apr 6, 2026

summary

attachment fetchData closures are lost when messages pass through queue/debounce concurrency strategies because JSON.stringify strips functions during enqueue. after dequeue and rehydration, handlers get fetchData: undefined and can't download files

adds fetchMetadata field to Attachment for storing platform-specific IDs that survive serialization (e.g. WhatsApp mediaId, Telegram fileId, Google Chat resourceName), and rehydrateAttachment optional method to Adapter for rebuilding fetchData closures from those IDs after deserialization

implemented in all five adapters that use fetchData: slack, whatsapp, telegram, gchat, teams

closes #323
closes #299

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Apr 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
chat Ready Ready Preview, Comment, Open in v0 Apr 9, 2026 11:39pm
chat-sdk-nextjs-chat Ready Ready Preview, Comment, Open in v0 Apr 9, 2026 11:39pm

...attachment,
fetchData: () => this.fetchSlackFile(url, this.getToken()),
};
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rehydrateAttachment calls this.getToken() lazily at fetch time, but rehydration runs from a queue consumer where there is no AsyncLocalStorage request context. In multi-workspace deployments this will throw AuthenticationError("No bot token available").

The original createAttachment captures the token eagerly during webhook processing for exactly this reason. The new path loses that.

fetchMetadata only stores { url } today, so there is no way to recover which workspace's token to use after deserialization. Either the token needs to be stored in fetchMetadata so it survives the roundtrip, or this needs to be scoped to single-workspace only.

- Slack createAttachment now calls fetchSlackFile instead of duplicating fetch logic inline
- Remove unnecessary IIFE wrapper in fetchSlackFile
- Fix redundant optional chain in rehydrateMessage by extracting bound method
- Full JSON.stringify/parse roundtrip test for fetchMetadata in message.test.ts
- Queue drain test: rehydrateAttachment called on deserialized attachments
- Queue drain test: skip rehydration when fetchData already present
- Queue drain test: attachments unchanged when adapter has no rehydrateAttachment
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.

Attachment fetchData lost after debounce/queue serialization No attachment fetchData in WhatsApp queued messages

2 participants