@molecule/api-emails-inbound-mailgun 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +535 -0
  2. package/package.json +10 -9
package/README.md ADDED
@@ -0,0 +1,535 @@
1
+ <!--
2
+ AUTO-GENERATED — DO NOT EDIT THIS FILE.
3
+ Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
4
+ Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
5
+ To change this document, edit the module-level JSDoc in src/index.ts.
6
+ Generated: 2026-08-04T01:48:03.372Z
7
+ -->
8
+
9
+ # @molecule/api-emails-inbound-mailgun
10
+
11
+ > **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
12
+ > It is written to be read by coding agents as much as by people, and is generated from this
13
+ > package's source — edit `src/index.ts` JSDoc, not this file.
14
+
15
+ Mailgun Routes inbound-email provider for molecule.dev.
16
+
17
+ Implements `@molecule/api-emails-inbound`'s `InboundEmailProvider`
18
+ interface against Mailgun's parsed-email POST format. Verifies the
19
+ `timestamp`/`token`/`signature` triple via HMAC-SHA256 against
20
+ `MAILGUN_API_KEY`, rejecting payloads older than the configured replay
21
+ window.
22
+
23
+ Outbound replies compose onto the bonded `@molecule/api-emails`
24
+ transport (typically `@molecule/api-emails-mailgun`) — this package does
25
+ not reimplement the SMTP path.
26
+
27
+ ## Quick Start
28
+
29
+ ```typescript
30
+ import { setProvider } from '@molecule/api-emails-inbound'
31
+ import { provider as mailgunRoutes } from '@molecule/api-emails-inbound-mailgun'
32
+
33
+ setProvider(mailgunRoutes)
34
+ ```
35
+
36
+ ## Type
37
+
38
+ `provider`
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ npm install @molecule/api-emails-inbound-mailgun @molecule/api-emails @molecule/api-emails-inbound @molecule/api-secrets
44
+ ```
45
+
46
+ ## API
47
+
48
+ ### Interfaces
49
+
50
+ #### `InboundEmail`
51
+
52
+ A normalized inbound email, produced by parsing a provider webhook
53
+ payload through {@link InboundEmailProvider.parseWebhookPayload}.
54
+
55
+ All providers (Mailgun Routes, SES Inbound, fixtures, etc.) return this
56
+ same shape so handler code can treat inbound mail uniformly. Provider
57
+ specifics (raw MIME, signing tokens, etc.) MUST NOT leak into this type.
58
+
59
+ ```typescript
60
+ interface InboundEmail {
61
+ /**
62
+ * Stable provider-supplied identifier for the message. Used for
63
+ * deduplication when the same webhook is retried.
64
+ */
65
+ id: string
66
+ /**
67
+ * Sender address (RFC 5322 mailbox), e.g. `'alice@example.com'`.
68
+ */
69
+ from: string
70
+ /**
71
+ * Primary recipient addresses (the values from the `To:` header).
72
+ */
73
+ to: string[]
74
+ /**
75
+ * Carbon-copy recipient addresses, if present.
76
+ */
77
+ cc?: string[]
78
+ /**
79
+ * Subject line, decoded to a plain string. May be empty.
80
+ */
81
+ subject: string
82
+ /**
83
+ * Plain-text body of the message, if present.
84
+ */
85
+ textBody?: string
86
+ /**
87
+ * HTML body of the message, if present.
88
+ */
89
+ htmlBody?: string
90
+ /**
91
+ * Decoded attachments. An empty array when the message has none.
92
+ */
93
+ attachments?: InboundEmailAttachment[]
94
+ /**
95
+ * All headers from the raw message, lowercased keys to canonicalize the
96
+ * many capitalizations that mail servers use. Multi-value headers
97
+ * (`Received:`, etc.) are joined with newlines or returned as arrays at
98
+ * provider discretion — see provider docs.
99
+ */
100
+ headers: Record<string, string | string[]>
101
+ /**
102
+ * Server-side timestamp the inbound provider received the message.
103
+ */
104
+ receivedAt: Date
105
+ /**
106
+ * Optional `Message-ID` header value for threading. Surfaced separately
107
+ * from {@link headers} because helpdesk handlers almost always need it.
108
+ */
109
+ messageId?: string
110
+ /**
111
+ * Optional `In-Reply-To` header value for threading replies into an
112
+ * existing ticket.
113
+ */
114
+ inReplyTo?: string
115
+ /**
116
+ * Optional `References` header values for threading.
117
+ */
118
+ references?: string[]
119
+ }
120
+ ```
121
+
122
+ #### `InboundEmailAttachment`
123
+
124
+ A binary attachment carried by an inbound email.
125
+
126
+ Providers normalize whatever multipart/MIME representation they receive
127
+ into this neutral shape. The body is base64-encoded so the type is
128
+ JSON-serializable across IPC, queue, and webhook boundaries.
129
+
130
+ ```typescript
131
+ interface InboundEmailAttachment {
132
+ /**
133
+ * The original filename as supplied by the sender, or a provider-derived
134
+ * fallback when the sender omitted one.
135
+ */
136
+ name: string
137
+ /**
138
+ * MIME type of the attachment (e.g. `'application/pdf'`, `'image/png'`).
139
+ * Defaults to `'application/octet-stream'` when the provider cannot
140
+ * determine the type.
141
+ */
142
+ contentType: string
143
+ /**
144
+ * Attachment payload, base64-encoded.
145
+ */
146
+ contentBase64: string
147
+ /**
148
+ * Optional size hint in bytes of the decoded payload. Providers MAY set
149
+ * this from upstream headers without decoding the payload themselves.
150
+ */
151
+ sizeBytes?: number
152
+ /**
153
+ * Optional Content-ID, used for inline images referenced from the HTML
154
+ * body via `cid:` URLs.
155
+ */
156
+ contentId?: string
157
+ }
158
+ ```
159
+
160
+ #### `InboundEmailProvider`
161
+
162
+ Inbound-email provider interface.
163
+
164
+ Implementations (Mailgun Routes, SES Inbound, etc.) live in separate
165
+ bond packages (`@molecule/api-emails-inbound-mailgun-routes`,
166
+ `@molecule/api-emails-inbound-ses`). The interface is deliberately
167
+ minimal: a webhook arrives at the host application's HTTP layer, the
168
+ raw headers and body are handed to the provider, and the provider
169
+ returns a normalized {@link InboundEmail}.
170
+
171
+ Signature verification is mandatory for any provider that runs against
172
+ a public webhook endpoint; {@link verifySignature} is the hook for
173
+ that. Providers without signed webhooks SHOULD return `false` rather
174
+ than `true` so callers can decide whether to accept unsigned mail.
175
+
176
+ ````typescript
177
+ interface InboundEmailProvider {
178
+ /**
179
+ * Parses the raw webhook payload (HTTP headers + body) into a
180
+ * normalized {@link InboundEmail}.
181
+ *
182
+ * @param headers - HTTP request headers received by the webhook
183
+ * endpoint. Lowercased keys are recommended but not required;
184
+ * implementations MUST handle either casing.
185
+ * @param body - Raw HTTP request body. May be a `Buffer` (e.g. from a
186
+ * raw body parser), a `string`, or an already-parsed object provided
187
+ * by an upstream JSON middleware.
188
+ * @returns The normalized inbound email.
189
+ */
190
+ parseWebhookPayload(
191
+ headers: Record<string, string | string[] | undefined>,
192
+ body: Buffer | string | Record<string, unknown>,
193
+ ): Promise<InboundEmail>
194
+ /**
195
+ * Verifies the signature of a webhook request, using whatever scheme
196
+ * the provider exposes (Mailgun HMAC, SES SNS subscription
197
+ * confirmation, etc.). Implementations MUST be constant-time when
198
+ * comparing secrets.
199
+ *
200
+ * A genuinely invalid webhook (forged, stale, malformed, tampered
201
+ * signature) resolves `false` — that is the normal, expected failure
202
+ * path and callers map it to a `401`. Implementations MAY instead THROW
203
+ * a tagged configuration error (e.g. via `configNotConfiguredError()`
204
+ * from `@molecule/api-secrets`) when the provider itself is
205
+ * misconfigured — for example a missing signing key/secret. This is a
206
+ * DISTINCT failure class from a `false` return: a misconfigured server
207
+ * is not the same problem as a forged request, and collapsing both into
208
+ * the same `false` makes a broken deployment indistinguishable from an
209
+ * attack, with no trace either way. `@molecule/api-emails-inbound-mailgun`
210
+ * follows this pattern — `verifySignature` throws the tagged
211
+ * `config.notConfigured` error when `MAILGUN_API_KEY` is unset, and
212
+ * resolves `false` for every other verification failure.
213
+ *
214
+ * @param headers - HTTP request headers received by the webhook
215
+ * endpoint.
216
+ * @param body - Raw HTTP request body. Implementations that need the
217
+ * exact bytes (e.g. for HMAC) MUST be passed a `Buffer`.
218
+ * @returns `true` when the signature is valid, `false` for an
219
+ * invalid/forged/stale/malformed webhook.
220
+ * @throws {Error} Implementations MAY throw a tagged configuration error
221
+ * when the provider is missing required configuration (e.g. an unset
222
+ * signing key) — a server misconfiguration, not an invalid request.
223
+ * @example
224
+ * ```typescript
225
+ * // In an HTTP handler bound to the inbound webhook URL:
226
+ * const ok = await verifySignature(req.headers, req.rawBody)
227
+ * if (!ok) return res.status(401).end()
228
+ * // A thrown configuration error (server misconfigured) is deliberately
229
+ * // NOT caught above — do not wrap this call in a try/catch that maps
230
+ * // every failure to the same 401. Let it propagate to standard error
231
+ * // middleware, which maps a tagged config error to a 503, distinct
232
+ * // from the 401 an invalid/forged webhook gets.
233
+ * ```
234
+ */
235
+ verifySignature(
236
+ headers: Record<string, string | string[] | undefined>,
237
+ body: Buffer | string,
238
+ ): Promise<boolean>
239
+ /**
240
+ * Optional: dispatches an outbound reply through the provider's own
241
+ * reply mechanism. Providers that do not support reply dispatch (e.g.
242
+ * pure inbound-only adapters) SHOULD omit this method; callers MUST
243
+ * use {@link InboundEmailProvider.supportsReply} to detect support.
244
+ *
245
+ * @param email - The original inbound email being replied to.
246
+ * @param reply - The reply payload.
247
+ * @returns Result of the dispatch.
248
+ */
249
+ replyTo?(email: InboundEmail, reply: InboundEmailReply): Promise<InboundEmailReplyResult>
250
+ /**
251
+ * Indicates whether the provider supports outbound reply dispatch via
252
+ * {@link replyTo}. Implementations SHOULD return a stable `true` /
253
+ * `false` based on their own configuration; the property is a function
254
+ * so providers can defer to runtime configuration if needed.
255
+ *
256
+ * @returns `true` when {@link replyTo} is implemented and ready to use.
257
+ */
258
+ supportsReply(): boolean
259
+ }
260
+ ````
261
+
262
+ #### `InboundEmailReply`
263
+
264
+ Outgoing reply produced by handler code in response to an
265
+ {@link InboundEmail}. Providers that support the optional
266
+ {@link InboundEmailProvider.replyTo} method translate this into whatever
267
+ outbound mechanism their upstream offers (Mailgun reply route, SES
268
+ SendEmail, etc.).
269
+
270
+ For providers that do NOT expose an outbound reply path, handler code
271
+ SHOULD fall back to the regular `@molecule/api-emails` outbound bond.
272
+
273
+ ```typescript
274
+ interface InboundEmailReply {
275
+ /**
276
+ * Subject line for the outbound reply. If omitted, providers SHOULD
277
+ * default to the original subject prefixed with `'Re: '` (locale-aware
278
+ * prefixing is the caller's responsibility).
279
+ */
280
+ subject?: string
281
+ /**
282
+ * Plain-text body of the reply, if any.
283
+ */
284
+ textBody?: string
285
+ /**
286
+ * HTML body of the reply, if any.
287
+ */
288
+ htmlBody?: string
289
+ /**
290
+ * Attachments to send with the reply.
291
+ */
292
+ attachments?: InboundEmailAttachment[]
293
+ /**
294
+ * Optional override for the `From:` address. Defaults to the address
295
+ * the original message was sent to (the inbound mailbox).
296
+ */
297
+ from?: string
298
+ /**
299
+ * Optional additional headers to set on the outbound message.
300
+ */
301
+ headers?: Record<string, string>
302
+ }
303
+ ```
304
+
305
+ #### `InboundEmailReplyResult`
306
+
307
+ Result of a successful reply dispatch via
308
+ {@link InboundEmailProvider.replyTo}.
309
+
310
+ ```typescript
311
+ interface InboundEmailReplyResult {
312
+ /**
313
+ * Provider-supplied identifier for the dispatched outbound message.
314
+ */
315
+ id: string
316
+ }
317
+ ```
318
+
319
+ ### Functions
320
+
321
+ #### `parseWebhookPayload(_headers, body)`
322
+
323
+ Parses a Mailgun Routes inbound webhook payload into a normalized
324
+ {@link InboundEmail}.
325
+
326
+ Mailgun POSTs `application/x-www-form-urlencoded` data with keys such as
327
+ `From`, `To`, `Cc`, `subject`, `body-plain`, `body-html`, `Message-Id`,
328
+ `In-Reply-To`, `References`, `attachment-count`, `attachment-N`, plus
329
+ the signing triple. We only extract domain-relevant fields here;
330
+ verification is done separately by {@link verifySignature}.
331
+
332
+ When `Message-Id` is absent, `id` falls back to
333
+ {@link deriveStableFallbackId} rather than the per-request signing
334
+ `token` — see that function's docs for why.
335
+
336
+ ```typescript
337
+ function parseWebhookPayload(
338
+ _headers: Record<string, string | string[] | undefined>,
339
+ body: string | Buffer<ArrayBufferLike> | Record<string, unknown>,
340
+ ): Promise<InboundEmail>
341
+ ```
342
+
343
+ - `_headers` — HTTP headers (unused — Mailgun puts everything in the body).
344
+ - `body` — The raw form-encoded body, a string, or an already-parsed object.
345
+
346
+ **Returns:** The normalized inbound email.
347
+
348
+ #### `replyTo(email, reply)`
349
+
350
+ Dispatches an outbound reply through the bonded `@molecule/api-emails`
351
+ transport. Mailgun's outbound API is already exposed via
352
+ `@molecule/api-emails-mailgun`, so we compose rather than reimplement.
353
+
354
+ The reply's `In-Reply-To` and `References` headers are populated from
355
+ the original message when present, so threading works in the recipient's
356
+ mail client.
357
+
358
+ ```typescript
359
+ function replyTo(email: InboundEmail, reply: InboundEmailReply): Promise<InboundEmailReplyResult>
360
+ ```
361
+
362
+ - `email` — The original inbound email being replied to.
363
+ - `reply` — The reply payload.
364
+
365
+ **Returns:** The reply dispatch result.
366
+
367
+ #### `supportsReply()`
368
+
369
+ Indicates that this provider supports outbound reply dispatch via
370
+ {@link replyTo}. The reply path requires the outbound
371
+ `@molecule/api-emails` bond to be wired with a transport — typically
372
+ `@molecule/api-emails-mailgun`.
373
+
374
+ ```typescript
375
+ function supportsReply(): boolean
376
+ ```
377
+
378
+ **Returns:** Always `true`.
379
+
380
+ #### `verifySignature(_headers, body)`
381
+
382
+ Verifies a Mailgun inbound webhook signature. Mailgun computes the
383
+ signature as `HMAC-SHA256(key=api_key, msg=timestamp + token)`, where
384
+ `+` is string concatenation (no separator). Implementations MUST be
385
+ constant-time and MUST reject stale timestamps.
386
+
387
+ The `body` parameter is the raw form-encoded body that carries the
388
+ signing fields. Header-only signing schemes are not supported by Mailgun
389
+ Routes.
390
+
391
+ Distinguishes SERVER MISCONFIGURATION from a genuinely invalid webhook:
392
+ an unset `MAILGUN_API_KEY` THROWS the tagged `config.notConfigured` error
393
+ (mapped by the API error middleware to a clean 503) instead of returning
394
+ `false`. Stale timestamps, missing signing fields, and a tampered
395
+ signature all still resolve to `false` (401) — those ARE the "this
396
+ request is not from Mailgun" class. Collapsing every failure mode into
397
+ the same `false` made a misconfigured server indistinguishable from
398
+ active forgery, with no trace either way (see
399
+ integration-audit-findings.md → [email] ambiguous-failure).
400
+
401
+ ```typescript
402
+ function verifySignature(
403
+ _headers: Record<string, string | string[] | undefined>,
404
+ body: string | Buffer<ArrayBufferLike>,
405
+ ): Promise<boolean>
406
+ ```
407
+
408
+ - `_headers` — HTTP headers (unused — Mailgun signs via form fields).
409
+ - `body` — Raw HTTP request body (form-encoded).
410
+
411
+ **Returns:** `true` when the signature verifies and the timestamp is fresh; `false` for a malformed/stale/forged webhook.
412
+
413
+ ### Constants
414
+
415
+ #### `mailgunInboundSecretDefinitions`
416
+
417
+ Secret definitions required by the Mailgun inbound-email bond.
418
+
419
+ ```typescript
420
+ const mailgunInboundSecretDefinitions: SecretDefinition[]
421
+ ```
422
+
423
+ #### `provider`
424
+
425
+ The Mailgun Routes inbound-email provider implementing the
426
+ {@link InboundEmailProvider} interface.
427
+
428
+ ```typescript
429
+ const provider: InboundEmailProvider
430
+ ```
431
+
432
+ ## Core Interface
433
+
434
+ Implements `@molecule/api-emails-inbound` interface.
435
+
436
+ ## Bond Wiring
437
+
438
+ Setup function to register this provider with the core interface:
439
+
440
+ ```typescript
441
+ import { setProvider } from '@molecule/api-emails-inbound'
442
+ import { provider } from '@molecule/api-emails-inbound-mailgun'
443
+
444
+ export function setupEmailsInboundMailgun(): void {
445
+ setProvider(provider)
446
+ }
447
+ ```
448
+
449
+ ## Injection Notes
450
+
451
+ ### Requirements
452
+
453
+ Peer dependencies:
454
+
455
+ - `@molecule/api-emails` ^1.0.1
456
+ - `@molecule/api-emails-inbound` ^1.0.1
457
+ - `@molecule/api-secrets` ^1.0.1
458
+
459
+ ### Environment Variables
460
+
461
+ - `MAILGUN_API_KEY` _(required)_ — Mailgun API key
462
+ - Setup: Mailgun dashboard → Settings → API Security → create/copy a sending API key.
463
+ - Get it here: [https://app.mailgun.com/settings/api_security](https://app.mailgun.com/settings/api_security)
464
+ - `MAILGUN_DOMAIN` _(required)_ — Mailgun sending domain
465
+ - Setup: Add and verify a sending domain in Mailgun (sandbox domains work for testing to authorized recipients).
466
+ - Get it here: [https://app.mailgun.com/mg/sending/domains](https://app.mailgun.com/mg/sending/domains)
467
+ - Example: `mg.example.com`
468
+ - `MAILGUN_INBOUND_REPLAY_WINDOW_SECONDS` _(optional)_ — Mailgun inbound replay window
469
+ - Setup: Max age (seconds) of accepted inbound webhook signatures — replay protection; the default is fine.
470
+ - Example: `300`
471
+
472
+ ### Runtime Dependencies
473
+
474
+ - `@molecule/api-emails`
475
+ - `@molecule/api-emails-inbound`
476
+ - `@molecule/api-secrets`
477
+
478
+ `verifySignature` THROWS the tagged `config.notConfigured` error (→ 503
479
+ via the API error middleware) when `MAILGUN_API_KEY` is unset, instead of
480
+ returning `false` like every other verification failure. Wire your
481
+ webhook handler to let that throw propagate to the error middleware —
482
+ catching it and mapping to the same 401 as a forged/stale webhook
483
+ re-introduces the "every failure looks the same" ambiguity this was
484
+ fixed to remove.
485
+
486
+ When an inbound message has no `Message-Id`, `id` is a deterministic
487
+ hash of the sender/original-Date-header/subject (NOT the per-request
488
+ Mailgun signing token, which changes on every retry) — so retries of an
489
+ id-less message still dedupe to the same id.
490
+
491
+ ## E2E Tests
492
+
493
+ Integration checklist — drive the real inbound endpoint (live preview, no
494
+ mocks), adapt each item to this app's actual inbox/ticket/thread flows, and
495
+ check every box off one by one. A box you can't check is an integration bug
496
+ to fix — not a skip. COUNTERPARTY: the app can't receive a real email in the
497
+ sandbox, so YOU play the mail provider — POST a realistic inbound-email
498
+ webhook to the app's inbound endpoint with `sandbox_fetch` (curl runs inside
499
+ the container). Model the payload on the BONDED provider's real format
500
+ (Mailgun: form fields `sender`/`recipient`/`subject`/`body-plain`/`body-html`/
501
+ `attachment-N` plus the `timestamp`/`token`/`signature` triple; SES/Postmark:
502
+ their JSON), and the happy-path POST must carry a VALID signature — compute it
503
+ the way the provider does (Mailgun signs HMAC-SHA256 of `timestamp+token` with
504
+ `MAILGUN_API_KEY` inside the replay window; read the key from the Environment
505
+ panel / `.env.molecule`). Never disable `verifySignature()` or mock
506
+ `parseWebhookPayload()` to go green — that proves nothing.
507
+
508
+ - [ ] A signed sample webhook to the inbound endpoint parses into the
509
+ normalized fields (from / to / subject / textBody / htmlBody) AND the app
510
+ ACTS on it — it files the mail into the right place (creates a ticket, a
511
+ comment on a thread, or a reply-thread) keyed off the recipient (`support@`)
512
+ or a plus-address / thread token (`reply+<id>@`). Verify the CREATED record
513
+ (a DB row, and it shows up in the UI) — not just a 200.
514
+ - [ ] Routing is correct: an email to `support@` opens a NEW ticket, while
515
+ `reply+<id>@` (or an `In-Reply-To` / `References` match) threads onto the
516
+ EXISTING one — each lands in the right user's / conversation's place, never
517
+ a stranger's.
518
+ - [ ] Attachments survive: an inbound message with an attachment has it
519
+ decoded from `attachments[].contentBase64` and stored on the app's OWN
520
+ storage (the uploads bond), not left as a provider link — the stored file
521
+ opens from the ticket.
522
+ - [ ] Retries don't duplicate: re-POST the SAME webhook (providers retry slow
523
+ / 5xx deliveries) and confirm handling is idempotent — one ticket, not two
524
+ (dedupe on `id` / `messageId`).
525
+ - [ ] Malformed / empty payloads (missing `body-plain`, no attachments, absent
526
+ headers) are handled without a crash — a clean response, not a 500 stack
527
+ trace.
528
+ - [ ] SECURITY — the endpoint is AUTHENTICATED: a forged POST with a bad or
529
+ missing signature (or a `timestamp` outside the replay window) is REJECTED
530
+ (401) and creates NO record, so an attacker can't inject mail into another
531
+ user's thread. A missing signing key is a DISTINCT 503, not a 401 — a
532
+ server misconfig must not masquerade as an accepted or forged webhook.
533
+ - [ ] SECURITY — the parsed `htmlBody` is sanitized before it is rendered
534
+ anywhere: a `<script>` / `onerror=` in an inbound body must NOT execute when
535
+ the ticket is viewed (no stored XSS from an inbound email body).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-emails-inbound-mailgun",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Mailgun Routes inbound email provider — parses inbound email webhook payloads into normalized InboundEmail.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -17,7 +17,8 @@
17
17
  }
18
18
  },
19
19
  "files": [
20
- "dist"
20
+ "dist",
21
+ "README.md"
21
22
  ],
22
23
  "keywords": [
23
24
  "molecule",
@@ -29,23 +30,23 @@
29
30
  ],
30
31
  "license": "Apache-2.0",
31
32
  "devDependencies": {
32
- "@molecule/api-emails": "1.0.0",
33
- "@molecule/api-emails-inbound": "1.0.0",
33
+ "@molecule/api-emails": "1.0.2",
34
+ "@molecule/api-emails-inbound": "1.0.2",
34
35
  "@types/node": "26.1.2",
35
36
  "typescript": "6.0.3",
36
- "vitest": "4.1.10"
37
+ "vitest": "4.1.11"
37
38
  },
38
39
  "peerDependencies": {
39
- "@molecule/api-emails": "^1.0.0",
40
- "@molecule/api-emails-inbound": "^1.0.0",
41
- "@molecule/api-secrets": "^1.0.0"
40
+ "@molecule/api-emails": "^1.0.1",
41
+ "@molecule/api-emails-inbound": "^1.0.1",
42
+ "@molecule/api-secrets": "^1.0.1"
42
43
  },
43
44
  "repository": {
44
45
  "type": "git",
45
46
  "url": "https://github.com/molecule-dev/molecule.git",
46
47
  "directory": "packages/api/bonds/emails-inbound/mailgun"
47
48
  },
48
- "homepage": "https://github.com/molecule-dev/molecule/tree/main/packages/api/bonds/emails-inbound/mailgun",
49
+ "homepage": "https://www.molecule.dev/packages/api-emails-inbound-mailgun",
49
50
  "bugs": "https://github.com/molecule-dev/molecule/issues",
50
51
  "publishConfig": {
51
52
  "access": "public"