feat: broadcast metrics and recipients - #1037
Conversation
…point Fixes the metrics response to match the real API shape (total/percentage instead of count/rate, plus status/timestamps/clicked_links), and adds broadcasts.recipients() to list a broadcast's recipients filtered by event type. The response type is generic over the request's `type`, so a literal type gets precisely-typed fields while a dynamic type value degrades to optional fields instead of failing to compile. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
commit: |
There was a problem hiding this comment.
All reported issues were addressed across 5 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| if (email !== undefined) { | ||
| searchParams.set('email', email); | ||
| } | ||
|
|
||
| if (bounceType !== undefined) { | ||
| searchParams.set('bounce_type', bounceType); | ||
| } |
There was a problem hiding this comment.
keeping the codebase pattern, but I think != null would be safer.
A T like 'opened' | 'clicked' distributed member-by-member across the per-field conditionals and lost clicked_links entirely instead of making it optional, since the fields' shapes don't recombine correctly across separately-distributed intersections. Switch to a non-distributive exhaustive match against each single literal, so anything that isn't exactly one literal (partial unions included) falls back to the safe BroadcastRecipientLoose shape. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
0 issues found across 1 file (changes from recent commits).
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Auto-approved: Adds two bounded, well-tested broadcast API methods with corrected response types and generic recipient filtering. No operational or security tradeoffs.
Re-trigger cubic
| count: number; | ||
| clicked_links: BroadcastRecipientClickedLink[]; | ||
| } | ||
| : [T] extends ['opened'] |
There was a problem hiding this comment.
yes! love TS! kinda nostalgic to think about it nowadays
Minor bump for the new broadcasts.recipients() endpoint, tagged as a preview since broadcast metrics/recipients are still in private beta.
There was a problem hiding this comment.
0 issues found across 1 file (changes from recent commits).
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Auto-approved: Adds two bounded, clearly beneficial API surface additions (broadcast metrics and recipients) with correct types and comprehensive tests.
Re-trigger cubic
…cipient Addresses review feedback: index into a per-type field map guarded by an IsUnion check, instead of a chain of tuple-wrapped conditional types.
There was a problem hiding this comment.
0 issues found across 1 file (changes from recent commits).
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Requires human review: Adds new broadcast metrics and recipients API methods, expanding the library's public contract. The non-trivial generic type for recipients and the new API endpoints benefit from human review to ensure alignment with the external Resend API.
Re-trigger cubic
Summary
broadcasts.metrics()'s response type to match the real API shape:{ total, percentage }counters (was{ count, rate }), plusstatus,created_at,scheduled_at,sent_at,remaining, andclicked_links.broadcasts.recipients()to list a broadcast's recipients filtered by event type (sent,delivered,opened,clicked,bounced,complained,unsubscribed,suppressed), with cursor pagination andemail/bounceTypefilters.recipients()'s response type is generic over the request'stype: a literaltype(the common case) gives precisely-typed fields with no null-checks (e.g.clickedguaranteescount/clicked_links); a dynamically-typedtypevalue degrades those fields to optional instead of failing to compile.Based on resend-docs#1677.
Test plan
broadcasts.spec.tscoversmetrics()with the corrected shape, andrecipients()for not-found, type filtering, email/bounceType filters, and bothafter/beforecursor paginationtsccheck (precise fields for literaltype, optional fields for dynamictype, invalid combinations rejected)🤖 Generated with Claude Code
Summary by cubic
Add broadcast analytics and recipient listing, released as preview
6.19.0-preview-broadcast-metrics.0.New Features
broadcasts.metrics()returns aggregate counters as{ total, percentage }, plusstatus,created_at,scheduled_at,sent_at,sent,remaining, andclicked_links.broadcasts.recipients()lists recipients by event type (sent,delivered,opened,clicked,bounced,complained,unsubscribed,suppressed) with cursor pagination andemail/bounceTypefilters. The response is generic to the requestedtype: literal types guarantee fields; unions or dynamic values fall back to a safe loose shape.Refactors
IsUnionforBroadcastRecipient, preventing partial unions from dropping fields while keeping precise types for single-literaltype.Written for commit 55d348c. Summary will update on new commits.