@xenterprises/fastify-xemail 1.1.1 → 1.3.0

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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,61 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@xenterprises/fastify-xemail` are documented here.
4
+
5
+ ## Unreleased
6
+
7
+ ## [1.3.0] - 2026-09-07
8
+
9
+ ### Added
10
+
11
+ - **Postmark provider** (`provider: 'postmark'`): `send`, `sendTemplate`,
12
+ `sendWithAttachments`, `sendBulk`, and `sendPersonalizedBulk` are backed by the
13
+ Postmark API (via the `postmark` package). Postmark is the migration target;
14
+ SendGrid is now legacy. The default remains `'sendgrid'`, so existing
15
+ registrations are unchanged.
16
+ - New `provider` registration option (`'sendgrid' | 'postmark'`), validated
17
+ fail-fast at registration.
18
+ - `messageStream` extra option for Postmark message streams.
19
+ - `test/xEmail.postmark.test.js` — Postmark tests mocking
20
+ `postmark.ServerClient.prototype` with `mock.method()`, fully offline.
21
+
22
+ ### Changed
23
+
24
+ - The plugin internals are split into provider modules:
25
+ `src/providers/sendgrid.js` (existing implementation, unchanged behavior) and
26
+ `src/providers/postmark.js` (new). `src/xEmail.js` now only validates options
27
+ and selects the provider.
28
+ - Under `provider: 'postmark'`, the SendGrid-only methods (`validate`,
29
+ `addContact`, `searchContact`, `deleteContact`, `createList`, `getLists`,
30
+ `deleteList`) are still present on the decorator but throw
31
+ `[xEmail] '<method>()' is not supported by provider 'postmark'.`
32
+
33
+ ## [1.2.0] - 2026-07-27
34
+
35
+ ### Breaking changes
36
+
37
+ - **Registration error messages changed format.** Missing/invalid `apiKey` and
38
+ `fromEmail` now throw `xemail: option \`<name>\` must be a string, e.g.
39
+ \`app.register(xEmail, { ... })\`` instead of `[xEmail] '<name>' (string) is required.`
40
+ (Suite-wide error-format standard; code matching on the old message text must be updated.)
41
+ - **`fp()` metadata changed**: plugin name is now `xemail` (was `xEmail`) and the
42
+ Fastify constraint is `5.x` (was `>=5.0.0`). Affects duplicate-registration
43
+ detection and `fastify-plugin` metadata only.
44
+
45
+ ### Added
46
+
47
+ - TypeScript declarations are now reachable by consumers: `package.json` gains a
48
+ top-level `"types": "./index.d.ts"` and a `types` condition in `exports["."]`.
49
+ Declaration content is unchanged.
50
+ - New fail-fast validation: `fromName` must be a string when provided and `active`
51
+ must be a boolean when provided.
52
+ - Tests asserting the plugin is env-independent (no `process.env` reads; options
53
+ are the only configuration source).
54
+
55
+ ### Changed
56
+
57
+ - Tooling migrated to Biome 2.5.5 (`lint`/`format` scripts); test script now uses
58
+ the `test/**/*.test.js` glob.
59
+ - README rewritten to the suite README contract; `docs/INTEGRATION.md` examples
60
+ corrected to use the `fastify.xEmail` decorator.
61
+ - Dependency updates via `npm audit fix` — 0 known vulnerabilities.
package/README.md CHANGED
@@ -1,14 +1,22 @@
1
1
  # @xenterprises/fastify-xemail
2
2
 
3
- Fastify plugin for SendGrid email — send transactional emails, template emails, bulk messages, validate addresses, and manage marketing contacts and lists.
3
+ Fastify 5 plugin for email via **Postmark** or **SendGrid** (legacy) — send transactional, template, attachment, and bulk emails through one `fastify.xEmail` decorator. SendGrid additionally supports address validation and Marketing contacts/lists. For Fastify apps that need email with the least possible wiring.
4
4
 
5
- ## Installation
5
+ > **Migration note:** SendGrid support is legacy. New integrations should use
6
+ > `provider: 'postmark'`; existing SendGrid registrations keep working unchanged.
7
+
8
+ ## Install
6
9
 
7
10
  ```bash
8
- npm install @xenterprises/fastify-xemail
11
+ npm install @xenterprises/fastify-xemail fastify@5
9
12
  ```
10
13
 
11
- ## Usage
14
+ `fastify@^5.0.0` is a peer dependency.
15
+
16
+ TypeScript declarations ship with the package — importing the plugin types the
17
+ `fastify.xEmail` decorator automatically (`index.d.ts`).
18
+
19
+ ## Minimal example
12
20
 
13
21
  ```javascript
14
22
  import Fastify from 'fastify';
@@ -17,12 +25,11 @@ import xEmail from '@xenterprises/fastify-xemail';
17
25
  const fastify = Fastify();
18
26
 
19
27
  await fastify.register(xEmail, {
20
- apiKey: process.env.SENDGRID_API_KEY,
21
- fromEmail: process.env.SENDGRID_FROM_EMAIL,
22
- fromName: 'My App', // optional
28
+ provider: 'postmark', // or 'sendgrid' (legacy default)
29
+ apiKey: 'your-postmark-server-token',
30
+ fromEmail: 'noreply@example.com',
23
31
  });
24
32
 
25
- // Send a simple email
26
33
  await fastify.xEmail.send(
27
34
  'user@example.com',
28
35
  'Welcome!',
@@ -30,168 +37,137 @@ await fastify.xEmail.send(
30
37
  );
31
38
  ```
32
39
 
40
+ The plugin reads **no environment variables**. All configuration arrives via the
41
+ register options object; reading `process.env.POSTMARK_SERVER_TOKEN` and passing
42
+ it in is the consumer's job.
43
+
44
+ ## Providers
45
+
46
+ | Provider | Status | Sending methods | `validate`, contacts, lists |
47
+ |----------|--------|-----------------|------------------------------|
48
+ | `postmark` | Migration target | `send`, `sendTemplate`, `sendWithAttachments`, `sendBulk`, `sendPersonalizedBulk` | Throw "not supported by provider 'postmark'" |
49
+ | `sendgrid` | Legacy (default) | All sending methods | Fully supported |
50
+
51
+ Postmark's API has no equivalents for email validation or contact/list
52
+ management, so those methods exist in the decorator under Postmark but throw
53
+ `[xEmail] '<method>()' is not supported by provider 'postmark'.`
54
+
33
55
  ## Options
34
56
 
35
57
  | Name | Type | Default | Required | Description |
36
58
  |------|------|---------|----------|-------------|
37
- | `apiKey` | `string` | | Yes | SendGrid API key |
59
+ | `provider` | `'sendgrid' \| 'postmark'` | `'sendgrid'` | No | Email provider. `sendgrid` is legacy; `postmark` is the migration target |
60
+ | `apiKey` | `string` | — | Yes | SendGrid API key (needs Mail Send; Marketing APIs for contact/list methods) or Postmark server API token |
38
61
  | `fromEmail` | `string` | — | Yes | Verified sender email address |
39
62
  | `fromName` | `string` | — | No | Sender display name |
40
- | `active` | `boolean` | `true` | No | Set `false` to disable the plugin entirely |
63
+ | `active` | `boolean` | `true` | No | Set `false` to disable the plugin entirely (no decorator is added) |
41
64
 
42
- ## Decorated Methods
65
+ Invalid options fail fast at registration with errors like:
43
66
 
44
- All methods are available on `fastify.xEmail`.
67
+ ```
68
+ xemail: option `apiKey` must be a string, e.g. `app.register(xEmail, { apiKey: 'SG.your-api-key' })`
69
+ ```
45
70
 
46
- ### `send(to, subject, html, text?, extraOptions?)`
71
+ ## Decorators
47
72
 
48
- Send an email. Plain text is auto-generated from HTML if omitted.
73
+ The plugin adds one decorator: `fastify.xEmail`. No request decorators.
49
74
 
50
- ```javascript
51
- const result = await fastify.xEmail.send('user@example.com', 'Hello', '<p>Hi</p>');
52
- // { success: true, statusCode: 202, messageId: 'xxx' }
53
- ```
75
+ ### `send(to, subject, html, text?, extraOptions?)`
54
76
 
55
- ### `sendTemplate(to, subject, templateId, dynamicData?, extraOptions?)`
77
+ Send an email. Plain text is auto-generated from the HTML if `text` is omitted.
78
+ Under SendGrid, `extraOptions` is merged into the message (e.g. `replyTo`, `cc`,
79
+ `categories`). Under Postmark, `extraOptions` accepts `replyTo`, `cc`, `bcc`,
80
+ `headers`, and `messageStream` (mapped to Postmark's PascalCase fields).
81
+ Returns `{ success, statusCode, messageId }` (Postmark reports a fixed
82
+ `statusCode: 200` on success and throws on failure).
56
83
 
57
- Send using a SendGrid dynamic template.
84
+ ### `sendTemplate(to, subject, templateId, dynamicData?, extraOptions?)`
58
85
 
59
- ```javascript
60
- await fastify.xEmail.sendTemplate(
61
- 'user@example.com',
62
- 'Welcome',
63
- 'd-abc123def456',
64
- { firstName: 'Tim', actionUrl: 'https://example.com/verify' }
65
- );
66
- ```
86
+ Send using a provider template. SendGrid: `templateId` is the dynamic template
87
+ ID (`d-xxx`) and `dynamicData` is sent as `dynamicTemplateData`. Postmark:
88
+ `templateId` is a template alias (string) or numeric template ID and
89
+ `dynamicData` becomes the `TemplateModel`. The subject is always included in the
90
+ template data. Returns `{ success, statusCode, messageId }`.
67
91
 
68
92
  ### `sendWithAttachments(to, subject, html, attachments)`
69
93
 
70
- Send an email with file attachments. Each attachment needs `content` (base64), `filename`, and `type` (MIME).
71
-
72
- ```javascript
73
- await fastify.xEmail.sendWithAttachments(
74
- 'user@example.com',
75
- 'Your Invoice',
76
- '<p>See attached.</p>',
77
- [{ content: base64String, filename: 'invoice.pdf', type: 'application/pdf' }]
78
- );
79
- ```
94
+ Send an email with attachments. Each attachment needs `content` (base64), `filename`,
95
+ and `type` (MIME type); `disposition` defaults to `'attachment'`. Returns
96
+ `{ success, statusCode, messageId }`.
80
97
 
81
98
  ### `sendBulk(to, subject, html)`
82
99
 
83
- Send the same email to multiple recipients at once.
84
-
85
- ```javascript
86
- await fastify.xEmail.sendBulk(
87
- ['a@example.com', 'b@example.com'],
88
- 'Announcement',
89
- '<p>Big news!</p>'
90
- );
91
- // { success: true, count: 2, statusCode: 202 }
92
- ```
100
+ Send the same email to an array of recipients. SendGrid uses one
101
+ `sgMail.sendMultiple` call; Postmark sends one email per recipient in chunks of
102
+ 500 concurrent requests. Returns `{ success, count, statusCode }`.
93
103
 
94
104
  ### `sendPersonalizedBulk(messages)`
95
105
 
96
- Send different content to each recipient. Returns per-recipient results including partial failures.
97
-
98
- ```javascript
99
- const results = await fastify.xEmail.sendPersonalizedBulk([
100
- { to: 'a@example.com', subject: 'Hi A', html: '<p>Hello A</p>' },
101
- { to: 'b@example.com', subject: 'Hi B', html: '<p>Hello B</p>' },
102
- ]);
103
- // [{ success: true, to: 'a@example.com', statusCode: 202 }, ...]
104
- ```
105
-
106
- ### `validate(email)`
106
+ Send different content per recipient. `messages` is an array of
107
+ `{ to, subject, html, text? }`. Never throws on individual failures — returns
108
+ one result per recipient: `{ success: true, to, statusCode }` or
109
+ `{ success: false, to, error }`. Postmark uses the batch endpoint (chunked at
110
+ 500 messages); a failure of the whole batch call marks that chunk's recipients
111
+ as failed instead of throwing.
107
112
 
108
- Validate an email address using the SendGrid Email Validation API. Returns a soft result on API errors instead of throwing.
113
+ ### `validate(email)` SendGrid only
109
114
 
110
- ```javascript
111
- const result = await fastify.xEmail.validate('user@example.com');
112
- // { email: '...', valid: true, verdict: 'Valid', score: 0.95, result: {...} }
113
- ```
115
+ Validate an address via the SendGrid Email Validation API. Returns
116
+ `{ email, valid, verdict, score, result }`. On API failure it returns a soft result
117
+ `{ email, valid: false, verdict: 'Unknown', error }` instead of throwing.
118
+ Throws under `provider: 'postmark'`.
114
119
 
115
- ### `addContact(email, data?, listIds?)`
120
+ ### `addContact(email, data?, listIds?)` — SendGrid only
116
121
 
117
- Add or update a contact in SendGrid Marketing. Accepts both `firstName`/`lastName` and `first_name`/`last_name`.
122
+ Add or update a SendGrid Marketing contact. `data` accepts `firstName`/`lastName`
123
+ (or `first_name`/`last_name`) and `customFields` (spread into the contact);
124
+ `listIds` is an array of list IDs. Returns `{ success, jobId, email }`.
118
125
 
119
- ```javascript
120
- await fastify.xEmail.addContact('user@example.com', {
121
- firstName: 'Tim',
122
- lastName: 'Smith',
123
- customFields: { w1_T: 'premium' }
124
- }, ['list-id-1']);
125
- // { success: true, jobId: '...', email: '...' }
126
- ```
126
+ ### `searchContact(email)` — SendGrid only
127
127
 
128
- ### `searchContact(email)`
129
-
130
- Search for a contact by email.
131
-
132
- ```javascript
133
- const result = await fastify.xEmail.searchContact('user@example.com');
134
- // { found: true, contact: { id: '...', email: '...', ... } }
135
- ```
136
-
137
- ### `deleteContact(contactId)`
138
-
139
- Delete a contact by ID. Returns `true` on success.
140
-
141
- ### `createList(name)`
142
-
143
- Create a new marketing contact list.
144
-
145
- ```javascript
146
- const result = await fastify.xEmail.createList('Newsletter');
147
- // { success: true, list: { id: '...', name: 'Newsletter' } }
148
- ```
128
+ Search for a contact by email. Returns `{ found: true, contact }` or `{ found: false }`.
149
129
 
150
- ### `getLists()`
130
+ ### `deleteContact(contactId)` — SendGrid only
151
131
 
152
- Get all contact lists. Returns an array.
132
+ Delete a contact by ID. Returns `true` on success (HTTP 200/202), `false` otherwise.
153
133
 
154
- ### `deleteList(listId)`
134
+ ### `createList(name)` — SendGrid only
155
135
 
156
- Delete a contact list by ID. Returns `true` on success.
136
+ Create a marketing contact list. Returns `{ success, list }`.
157
137
 
158
- ## Environment Variables
138
+ ### `getLists()` — SendGrid only
159
139
 
160
- | Name | Required | Description |
161
- |------|----------|-------------|
162
- | `SENDGRID_API_KEY` | Yes | SendGrid API key with Mail Send permissions |
163
- | `SENDGRID_FROM_EMAIL` | Yes | Verified sender email address |
164
- | `SENDGRID_FROM_NAME` | No | Sender display name |
140
+ Get all contact lists. Returns an array (empty when none exist).
165
141
 
166
- ## Error Reference
142
+ ### `deleteList(listId)` — SendGrid only
167
143
 
168
- All errors are prefixed with `[xEmail]` for easy identification in logs.
144
+ Delete a list by ID. Returns `true` on success (HTTP 200/202/204), `false` otherwise.
169
145
 
170
- | Error | When |
171
- |-------|------|
172
- | `[xEmail] 'apiKey' (string) is required.` | Missing or non-string `apiKey` at registration |
173
- | `[xEmail] 'fromEmail' (string) is required.` | Missing or non-string `fromEmail` at registration |
174
- | `[xEmail] 'to' is required for send().` | Calling `send()` without a recipient |
175
- | `[xEmail] 'subject' is required for send().` | Calling `send()` without a subject |
176
- | `[xEmail] 'html' is required for send().` | Calling `send()` without HTML content |
177
- | `[xEmail] 'templateId' is required for sendTemplate().` | Missing template ID |
178
- | `[xEmail] 'attachments' must be a non-empty array.` | Empty or non-array attachments |
179
- | `[xEmail] 'to' must be a non-empty array for sendBulk().` | Non-array or empty array for bulk |
180
- | `[xEmail] 'messages' must be a non-empty array for sendPersonalizedBulk().` | Empty messages array |
181
- | `[xEmail] 'email' (string) is required for validate().` | Missing email for validation |
182
- | `[xEmail] Failed to send email: <reason>` | SendGrid API rejection on send |
183
- | `[xEmail] Failed to add contact: <reason>` | SendGrid API rejection on contact add |
146
+ ## Routes
184
147
 
185
- ## How It Works
148
+ None. This plugin adds no routes.
186
149
 
187
- The plugin initializes both `@sendgrid/mail` (for transactional emails) and `@sendgrid/client` (for the Marketing and Validation APIs) with the provided API key. It decorates the Fastify instance with `fastify.xEmail`, an object containing all email and contact management methods.
150
+ ## Error behavior
188
151
 
189
- Each method validates its required parameters before making any API call. Transactional methods (`send`, `sendTemplate`, `sendWithAttachments`, `sendBulk`) use `sgMail`, while marketing and validation methods (`validate`, `addContact`, `searchContact`, `deleteContact`, `createList`, `getLists`, `deleteList`) use `sgClient` with direct REST calls.
152
+ - **Registration** throws fail-fast `Error`s naming the plugin and the option, with a
153
+ registration example (see Options above).
154
+ - **Method argument validation** throws synchronously-rejecting `Error`s prefixed with
155
+ `[xEmail]`, e.g. `[xEmail] 'to' is required for send().`
156
+ - **SendGrid API failures** are logged via `fastify.log.error` (structured error, never
157
+ the API key) and re-thrown wrapped: `[xEmail] Failed to send email: <reason>`.
158
+ `validate()` is the exception — it returns a soft result instead of throwing, since
159
+ validation failures are expected in normal operation. Postmark failures are wrapped
160
+ the same way.
161
+ - **SendGrid-only methods under Postmark** throw
162
+ `[xEmail] '<method>()' is not supported by provider 'postmark'.`
163
+ - With `active: false` the plugin returns before registering anything, so
164
+ `fastify.xEmail` is `undefined`.
190
165
 
191
- Errors from SendGrid are caught, logged via `fastify.log.error` (with structured error objects, never credentials), and re-thrown with a descriptive `[xEmail]` prefix. The `validate()` method is an exception — it returns a soft error result instead of throwing, since validation failures are expected in normal operation.
166
+ ## Requirements
192
167
 
193
- Setting `active: false` causes the plugin to return immediately without decorating, which is useful for disabling email in test environments.
168
+ - Node.js >= 20
169
+ - Fastify ^5.0.0 (peer dependency)
194
170
 
195
171
  ## License
196
172
 
197
- UNLICENSED
173
+ Proprietary — All Rights Reserved, X Enterprises. See `LICENSE`.
package/index.d.ts CHANGED
@@ -1,17 +1,19 @@
1
1
  /**
2
- * xEmail - Fastify Plugin for SendGrid Email
2
+ * xEmail - Fastify Plugin for Email (Postmark + SendGrid legacy)
3
3
  * @module @xenterprises/fastify-xemail
4
4
  */
5
5
 
6
6
  import { FastifyPluginAsync } from 'fastify';
7
7
 
8
- /** Additional SendGrid mail options passed through to the API. */
8
+ /** Additional mail options passed through to the provider API. */
9
9
  export interface EmailExtraOptions {
10
10
  replyTo?: string;
11
11
  bcc?: string | string[];
12
12
  cc?: string | string[];
13
13
  categories?: string[];
14
14
  headers?: Record<string, string>;
15
+ /** Postmark message stream (e.g. 'outbound'); Postmark provider only */
16
+ messageStream?: string;
15
17
  [key: string]: unknown;
16
18
  }
17
19
 
@@ -98,22 +100,34 @@ export interface PersonalizedMessage {
98
100
  /** All methods decorated onto fastify.xEmail. */
99
101
  export interface XEmailService {
100
102
  send(to: string | string[], subject: string, html: string, text?: string | null, extraOptions?: EmailExtraOptions): Promise<EmailSendResult>;
101
- sendTemplate(to: string | string[], subject: string, templateId: string, dynamicData?: Record<string, unknown>, extraOptions?: EmailExtraOptions): Promise<EmailSendResult>;
103
+ sendTemplate(to: string | string[], subject: string, templateId: string | number, dynamicData?: Record<string, unknown>, extraOptions?: EmailExtraOptions): Promise<EmailSendResult>;
102
104
  sendWithAttachments(to: string | string[], subject: string, html: string, attachments: EmailAttachment[]): Promise<EmailSendResult>;
103
105
  sendBulk(to: string[], subject: string, html: string): Promise<EmailBulkResult>;
104
106
  sendPersonalizedBulk(messages: PersonalizedMessage[]): Promise<EmailPersonalizedResult[]>;
107
+ /** SendGrid only — throws under provider 'postmark'. */
105
108
  validate(email: string): Promise<EmailValidationResult>;
109
+ /** SendGrid only — throws under provider 'postmark'. */
106
110
  addContact(email: string, data?: ContactData, listIds?: string[]): Promise<EmailAddContactResult>;
111
+ /** SendGrid only — throws under provider 'postmark'. */
107
112
  searchContact(email: string): Promise<EmailSearchContactResult>;
113
+ /** SendGrid only — throws under provider 'postmark'. */
108
114
  deleteContact(contactId: string): Promise<boolean>;
115
+ /** SendGrid only — throws under provider 'postmark'. */
109
116
  createList(name: string): Promise<EmailCreateListResult>;
117
+ /** SendGrid only — throws under provider 'postmark'. */
110
118
  getLists(): Promise<Record<string, unknown>[]>;
119
+ /** SendGrid only — throws under provider 'postmark'. */
111
120
  deleteList(listId: string): Promise<boolean>;
112
121
  }
113
122
 
114
123
  /** Plugin configuration options. */
115
124
  export interface XEmailPluginOptions {
116
- /** SendGrid API key (required) */
125
+ /**
126
+ * Email provider: 'sendgrid' (legacy, default) or 'postmark' (migration target).
127
+ * @default 'sendgrid'
128
+ */
129
+ provider?: 'sendgrid' | 'postmark';
130
+ /** Provider API key: SendGrid API key or Postmark server token (required) */
117
131
  apiKey: string;
118
132
  /** Verified sender email address (required) */
119
133
  fromEmail: string;
package/package.json CHANGED
@@ -1,14 +1,20 @@
1
1
  {
2
2
  "name": "@xenterprises/fastify-xemail",
3
3
  "type": "module",
4
- "version": "1.1.1",
5
- "description": "Fastify plugin for SendGrid email integration — transactional emails, templates, bulk sending, validation, and contact management.",
4
+ "version": "1.3.0",
5
+ "description": "Fastify plugin for email via Postmark or SendGrid (legacy) — transactional emails, templates, bulk sending, validation, and contact management.",
6
6
  "main": "src/xEmail.js",
7
+ "types": "./index.d.ts",
7
8
  "exports": {
8
- ".": "./src/xEmail.js"
9
+ ".": {
10
+ "types": "./index.d.ts",
11
+ "default": "./src/xEmail.js"
12
+ }
9
13
  },
10
14
  "scripts": {
11
- "test": "node --test test/xEmail.test.js"
15
+ "test": "node --test 'test/**/*.test.js'",
16
+ "lint": "biome check src/ test/",
17
+ "format": "biome format --write src/ test/"
12
18
  },
13
19
  "engines": {
14
20
  "node": ">=20.0.0",
@@ -16,6 +22,7 @@
16
22
  },
17
23
  "keywords": [
18
24
  "fastify",
25
+ "postmark",
19
26
  "sendgrid",
20
27
  "email",
21
28
  "plugin"
@@ -23,13 +30,15 @@
23
30
  "author": "Tim Mushen",
24
31
  "license": "SEE LICENSE IN LICENSE",
25
32
  "devDependencies": {
33
+ "@biomejs/biome": "2.5.5",
26
34
  "@types/node": "^22.7.4",
27
35
  "fastify": "^5.1.0"
28
36
  },
29
37
  "dependencies": {
30
38
  "@sendgrid/client": "^8.1.3",
31
39
  "@sendgrid/mail": "^8.1.3",
32
- "fastify-plugin": "^5.0.0"
40
+ "fastify-plugin": "^5.0.0",
41
+ "postmark": "^4.0.7"
33
42
  },
34
43
  "peerDependencies": {
35
44
  "fastify": "^5.0.0"