mailpace / mailpace.js

The official Node.js library for the https://ohmysmtp.com transactional email API
https://ohmysmtp.com
MIT License
9 stars 1 forks source link

Type-safe webhooks #1

Open franky47 opened 2 years ago

franky47 commented 2 years ago

I'm planning to use OhMySMTP in a Fastify app, for which I've made the fastify-ohmysmtp package, and next on my roadmap is to add a route and handlers for webhooks.

While I could list the event types and define the payload type within the plugin, I feel like those type definitions would be better located here in the Node.js API.

I've done a similar job for the Stripe webhooks here (though they had additional complexity that would be unneeded here if all webhooks have the same payload type), if that's something you're interested in, I can open a PR.

franky47 commented 2 years ago

Suggested API:

export const webhookEvents = [
  'email.queued',
  'email.delivered',
  'email.deferred',
  'email.bounced',
  'email.spam'
] as const

export type WebhookEvents = typeof webhookEvents[number]

export type ExtractStatusFromEvent<Event extends string> =
  Event extends `email.${infer T}` ? T : never

export interface WebhookPayload<Event extends WebhookEvents> {
  /**
   * Email status
   */
  status: ExtractStatusFromEvent<Event>

  /**
   * Reference ID of email
   */
  id: number

  /**
   * Reference ID of sending Domain
   */
  domain_id: number

  /**
   * Timestamp of when the email was first received by our API
   */
  created_at: Date

  /**
   * Timestamp of when the email was last updated, typically a status change
   */
  updated_at: Date

  /**
   * From email address
   */
  from: string

  /**
   * To email address, may be a comma separated list if multiple recipients provided
   */
  to: string | null

  /**
   * HTML body in email
   */
  htmlbody: string | null

  /**
   * Text body in email
   */
  textbody: string | null

  /**
   * Carbon Copy email address, may be a comma separated list if multiple recipients provided
   */
  cc: string | null

  /**
   * Blind Carbon Copy email address, may be a comma separated list if multiple recipients provided
   */
  bcc: string | null

  /**
   * Email subject
   */
  subject: string | null

  /**
   * Reply to address
   */
  replyto: string | null

  /**
   * Message ID set by OhMySMTP, in the format `<message-id>@<mailer.ohmysmtp.com>`
   */
  message_id: string

  /**
   * List-Unsubscribe header
   */
  list_unsubscribe: string | null
}

export type WebhookBody<Event extends WebhookEvents = WebhookEvents> = {
  event: Event
  payload: WebhookPayload<Event>
}
franky47 commented 2 years ago

Note: I've gone a different route when implementing webhook handlers in my plugin, to add a layer of input validation (because static types don't help much with runtime validation) with zod: https://github.com/47ng/fastify-ohmysmtp/blob/main/src/webhooks.ts

Having the TypeScript definitions with JSDoc comments would be a nice DX though, to have documentation built-in in the editor.