Repository navigation
feat: route events to targets by event type - #3
bahriy-dev wants to merge 1 commit into
Conversation
Targets can now subscribe to specific event types with patterns such as "order.paid" or "stock.*". Plain URLs still receive every event. The event type is read from X-Event-Type or the payload's type/event field. Adds src/routing.ts with 6 tests. Closes #2 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FYiLwGkrgfn7ftZh1WDFpq
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: efa8b56abf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const eventType = eventTypeOf(header(req, 'x-event-type'), payload); | ||
| const targets = routeEvent(source.targets, eventType); |
There was a problem hiding this comment.
Authenticate the event type before using it to select targets
For sources with filtered targets, anyone possessing a valid request can change X-Event-Type and replay it within the signature tolerance to route the signed payload to otherwise excluded targets. verify() authenticates only the timestamp and raw body, but this header overrides the authenticated payload type. For example, replaying a signed stock.updated event with X-Event-Type: order.paid queues it for an accounting target subscribed only to paid orders; per-target deduplication does not prevent this new delivery. Bind header-based event types to the signature, or derive routing from authenticated payload data.
Useful? React with 👍 / 👎.
| const urls: string[] = []; | ||
| for (const target of targets) { | ||
| if (typeof target === 'string') urls.push(target); | ||
| else if (!target.events?.length) urls.push(target.url); |
There was a problem hiding this comment.
Distinguish an empty event subscription from an absent filter
When a target has an explicit events: [], this condition treats it as unfiltered and sends it every event, including untyped events. That contradicts the documented behavior that objects with an events filter receive only matching types: an empty subscription has no matches. Clearing a target's subscriptions therefore broadens delivery instead of stopping it. Treat only an absent events property as unfiltered and let an empty array match nothing.
Useful? React with 👍 / 👎.
Every event used to go to every target. In a real shop the warehouse only needs paid orders and stock changes, and accounting only needs payments and refunds.
What changed
{ "url": "…", "events": ["order.paid", "stock.*"] }X-Event-Type, or the payload'stype/eventfield202response now includeseventTypeand the number of routedtargetssources.example.jsonsrc/routing.tswith 6 tests (20 total)Closes #2