feat(providers): reshape InboundEmailProvider seam to carry raw RFC822 (HT-35) - #35
Merged
Merged
Conversation
…2 (HT-35)
Replace parseWebhook -> NormalizedInboundEmail (which parsed inside the provider, breaking the spec's parse-once invariant) with receiveDelivery -> RawInboundMessage[]: the provider authenticates a delivery and yields raw RFC822 bytes (inline or a blob ref) + { mailboxId, providerMessageId, receivedAt }; the pipeline owns the single parseInboundEmail. verifySignature unchanged.
Delete NormalizedInboundEmail/NormalizedInboundAttachment (wrong boundary, no implementations yet); add RawMessageContent (kind-tagged inline|blobRef, matching QueueHandlerResult); add an in-memory dev fake + test mirroring dev-sender.ts; fix parse.ts doc comments that named the deleted types.
Implements specs/mail/inbound-ingestion.md §2. Gates green: typecheck, biome lint, 402 tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughThe inbound email provider contract now returns raw messages instead of normalized emails. A FIFO in-memory development provider and Vitest coverage were added, while parser documentation clarifies inline attachment handling and downstream persistence. ChangesInbound email ingestion
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements HT-35 [B] — the first code ticket under the HT-33 inbound epic, built against the merged spec.
What changed
Reshapes the
InboundEmailProviderseam so it carries raw RFC822 bytes + metadata, not a pre-parsed email — realizingspecs/mail/inbound-ingestion.md§2's parse-once invariant.src/providers/inbound-email.ts— deletesNormalizedInboundEmail/NormalizedInboundAttachment(they put the parse inside the provider); addsRawMessageContent(akind-taggedinline | blobRefunion, matching theQueueHandlerResultconvention) andRawInboundMessage(content+mailboxId+providerMessageId+receivedAt); replacesparseWebhook → NormalizedInboundEmailwithreceiveDelivery → RawInboundMessage[](0..N messages per delivery).verifySignatureunchanged.src/dev/dev-inbound-email.ts(new) +dev-inbound-email.test.ts— in-memory fake mirroringdev-sender.ts, so the ingest pipeline (HT-37) can be driven without a real provider.src/providers/index.ts— barrel re-exports updated.src/mail/parse.ts— doc comments that named the now-deleted types corrected (cleanup of this change's own mess; comments only, no behavior change).Scope is the seam only — no Gmail adapter, no ingest pipeline (later tickets). Gates green locally: typecheck, biome lint, 402 tests.
One design note for review (consciously deferred to HT-41)
receiveDelivery(request: Request)takes the webhookRequest. That fits a forwarding transport cleanly (the request is the message). For Gmail, the spec's flow is two-phase — the webhook enqueues a notification and acks fast (gmail-push.md§2), and a queue consumer does the history fetch (§3). A singlereceiveDelivery(request)can express that (the adapter reads the Pub/Sub envelope, then fetches), but where it's invoked — and whether the consumer wants the originalRequestor an enqueued descriptor — is best pinned when HT-41 builds the real adapter with concrete usage. I deliberately didn't over-design the seam for a flow that isn't built yet (charter: nothing speculative); it's a two-way door. Flagging so it's a conscious deferral, not an oversight.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation