@standardserver/fastify 0.6.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/LICENCE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Standard Server
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,264 @@
1
+ # @standardserver/fastify
2
+
3
+ <div align="center">
4
+ <a href="https://codecov.io/gh/middleapi/standardserver">
5
+ <img alt="codecov" src="https://codecov.io/gh/middleapi/standardserver/branch/main/graph/badge.svg">
6
+ </a>
7
+ <a href="https://www.npmjs.com/package/@standardserver/fastify">
8
+ <img alt="weekly downloads" src="https://img.shields.io/npm/dw/%40standardserver%2Ffastify?logo=npm" />
9
+ </a>
10
+ <a href="https://app.codspeed.io/middleapi/standardserver?utm_source=badge">
11
+ <img src="https://img.shields.io/endpoint?url=https://codspeed.io/badge.json" alt="CodSpeed" />
12
+ </a>
13
+ <a href="https://github.com/middleapi/standardserver/blob/main/LICENSE">
14
+ <img alt="MIT License" src="https://img.shields.io/github/license/middleapi/standardserver?logo=open-source-initiative" />
15
+ </a>
16
+ <a href="https://discord.gg/TXEbwRBvQn">
17
+ <img alt="Discord" src="https://img.shields.io/discord/1308966753044398161?color=7389D8&label&logo=discord&logoColor=ffffff" />
18
+ </a>
19
+ <a href="https://deepwiki.com/middleapi/standardserver">
20
+ <img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki">
21
+ </a>
22
+ </div>
23
+
24
+ `@standardserver/fastify` adapts Fastify request and reply objects to the transport-agnostic request and response model defined by Standard Server.
25
+
26
+ Standard Server provides a unified interface for client-server communication across HTTP and message-based transports. It lets you write handlers against the same request, response, body, and streaming primitives whether the underlying transport is the Fetch API, Node.js HTTP, HTTP/2, or a peer-style message channel.
27
+
28
+ This package is the Fastify adapter for that model. It builds on `@standardserver/node`, reusing the same body, URL, and abort-signal primitives, while routing the response back through Fastify's reply lifecycle so hooks, plugins, and serializers keep working. Both `Fastify()` and `Fastify({ http2: true })` instances are supported.
29
+
30
+ ## Entry Point
31
+
32
+ The package exports a single entry point:
33
+
34
+ | Export | Purpose |
35
+ | ------------------------- | ------------------------------------------------ |
36
+ | `@standardserver/fastify` | Fastify adapter helpers for requests and replies |
37
+
38
+ `fastify` is a peer dependency, so the adapter always uses the Fastify version installed in your project.
39
+
40
+ ## Package overview
41
+
42
+ The main entry point exposes two helpers and their option shapes:
43
+
44
+ | Group | Exports | Purpose |
45
+ | ----------------------- | ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
46
+ | Request and response | `toStandardLazyRequest()`, `sendStandardResponse()` | Adapt Fastify request and reply objects to Standard Server |
47
+ | Types and option shapes | `AnyFastifyRequest`, `AnyFastifyReply`, `FastifyRequest`, `FastifyReply`, `SendStandardResponseOptions` | Type handler inputs and serializer options |
48
+
49
+ Both helpers accept `AnyFastifyRequest` and `AnyFastifyReply`, which are `FastifyRequest` and `FastifyReply` widened over every raw server. That is what lets the same call site work for `Fastify()`, `Fastify({ http2: true })`, typed route generics, hooks, and encapsulated plugins alike.
50
+
51
+ Lower-level helpers such as `toStandardBody()`, `toNodeHttpBody()`, and `toEventStream()` are not re-exported here — import them from [`@standardserver/node`](../node/README.md) when you need them.
52
+
53
+ ## Server-side request handling
54
+
55
+ Use `toStandardLazyRequest()` to convert an incoming Fastify request into a `StandardLazyRequest`, then `sendStandardResponse()` to write the resulting `StandardResponse` back through the reply.
56
+
57
+ ```ts
58
+ import type { StandardLazyRequest, StandardResponse } from '@standardserver/core'
59
+ import { sendStandardResponse, toStandardLazyRequest } from '@standardserver/fastify'
60
+ import Fastify from 'fastify'
61
+
62
+ async function handle(request: StandardLazyRequest): Promise<StandardResponse> {
63
+ const body = await request.resolveBody()
64
+
65
+ return {
66
+ status: 200,
67
+ headers: { 'content-type': 'application/json' },
68
+ body: {
69
+ ok: true,
70
+ method: request.method,
71
+ url: request.url,
72
+ received: body,
73
+ },
74
+ }
75
+ }
76
+
77
+ const fastify = Fastify()
78
+
79
+ fastify.all('/*', async (req, reply) => {
80
+ const standardRequest = toStandardLazyRequest(req, reply)
81
+ const standardResponse = await handle(standardRequest)
82
+
83
+ await sendStandardResponse(reply, standardResponse, {/** options */})
84
+ })
85
+
86
+ await fastify.listen({ port: 3000 })
87
+ ```
88
+
89
+ `sendStandardResponse()` resolves once the response is fully flushed, and rejects if the underlying connection errors. Do not return a value from the route handler afterwards — Fastify would try to send a second response.
90
+
91
+ > [!TIP]
92
+ > When sending responses, you can pass additional options such as event-stream keep-alive.
93
+
94
+ ## Resolving Body
95
+
96
+ `resolveBody(hint?)` returns the body Fastify already parsed with its own content type parsers, if there is one. Otherwise it falls back to `toStandardBody()` from `@standardserver/node`, which determines how to parse the body using the following priority:
97
+
98
+ 1. If `hint?` is provided, use it as the `StandardBodyHint`.
99
+ 2. Otherwise, if the `standard-server` header is present, use it as the `StandardBodyHint`.
100
+ 3. Otherwise, if `content-type` is one of the common types, parse accordingly.
101
+ 4. Otherwise, if `content-length` exists, treat the body as `file`; if not, treat it as `octet-stream`.
102
+
103
+ Because Fastify's own parsers win, a `hint` only applies to bodies Fastify left unparsed. Fastify ships parsers for `application/json` and `text/plain`, and rejects every other content type with `415 Unsupported Media Type` unless you register one. To let the adapter own body parsing end to end, register a catch-all parser that leaves the body untouched:
104
+
105
+ ```ts
106
+ // optional: also drop fastify's built-in json and text/plain parsers
107
+ fastify.removeAllContentTypeParsers()
108
+
109
+ fastify.addContentTypeParser('*', (req, payload, done) => {
110
+ done(null, undefined)
111
+ })
112
+ ```
113
+
114
+ Register it inside an encapsulated plugin if you only want it to apply to the routes that serve Standard Server handlers.
115
+
116
+ > [!TIP]
117
+ > For efficient communication, set the `standard-server` header to explicitly hint the body type, especially for file or binary streaming. For example, if you upload a file with a common `content-type` such as `application/json` but omit the `standard-server` header, the server may interpret it as JSON and parse it unexpectedly.
118
+
119
+ ## Fastify behavior to be aware of
120
+
121
+ Fastify owns the reply lifecycle, so a few of its rules apply to the response the adapter writes:
122
+
123
+ - **Empty `content-type` is rejected.** A `Blob` or `File` without a type is sent with an empty `content-type` header, which Fastify answers with `415 Unsupported Media Type` before your handler runs. Normalize it first if clients may send one:
124
+
125
+ ```ts
126
+ fastify.addHook('onRequest', async (req) => {
127
+ if (req.headers['content-type'] === '') {
128
+ delete req.headers['content-type']
129
+ }
130
+ })
131
+ ```
132
+
133
+ - **JSON responses gain a charset.** Fastify rewrites any `content-type` whose media type contains `json` to include `; charset=utf-8`. The payload itself is never serialized twice, because the adapter always hands Fastify an already-encoded string or stream.
134
+ - **`set-cookie` is merged, not replaced.** Cookies set by plugins such as `@fastify/cookie` are kept, and the ones on your `StandardResponse` are appended to them. Every other header is overwritten.
135
+ - **Streams are managed by Fastify.** Streaming bodies are piped and destroyed by Fastify itself, including when the client aborts mid-response.
136
+
137
+ ## Learn more
138
+
139
+ For the higher-level project overview, see the root [Standard Server README](../../README.md).
140
+
141
+ For the Node.js primitives this adapter is built on, see the [Node.js adapter documentation](../node/README.md).
142
+
143
+ ## Sponsors
144
+
145
+ Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going here: [GitHub Sponsors](https://github.com/sponsors/dinwwwh). Every bit helps! 🚀
146
+
147
+ ### 🏆 Platinum Sponsor
148
+
149
+ <table>
150
+ <tr>
151
+ <td align="center"><a href="https://screenshotone.com/?ref=orpc" target="_blank" rel="noopener" title="ScreenshotOne.com"><img src="https://avatars.githubusercontent.com/u/97035603?v=4" width="279" alt="ScreenshotOne.com"/><br />ScreenshotOne.com</a></td>
152
+ </tr>
153
+ </table>
154
+
155
+ ### 🥈 Silver Sponsor
156
+
157
+ <table>
158
+ <tr>
159
+ <td align="center"><a href="https://misskey.io/?ref=orpc" target="_blank" rel="noopener" title="村上さん"><img src="https://avatars.githubusercontent.com/u/37681609?u=0dd4c7e4ba937cbb52b068c55914b1d8164dc0c7&amp;v=4" width="209" alt="村上さん"/><br />村上さん</a></td>
160
+ </tr>
161
+ </table>
162
+
163
+ ### Generous Sponsors
164
+
165
+ <table>
166
+ <tr>
167
+ <td align="center"><a href="https://github.com/ln-markets?ref=orpc" target="_blank" rel="noopener" title="LN Markets"><img src="https://avatars.githubusercontent.com/u/70597625?v=4" width="167" alt="LN Markets"/><br />LN Markets</a></td>
168
+ </tr>
169
+ </table>
170
+
171
+ ### Sponsors
172
+
173
+ <table>
174
+ <tr>
175
+ <td align="center"><a href="https://github.com/hrmcdonald?ref=orpc" target="_blank" rel="noopener" title="Reece McDonald"><img src="https://avatars.githubusercontent.com/u/39349270?v=4" width="139" alt="Reece McDonald"/><br />Reece McDonald</a></td>
176
+ <td align="center"><a href="https://github.com/nicognaW?ref=orpc" target="_blank" rel="noopener" title="nk"><img src="https://avatars.githubusercontent.com/u/66731869?u=4699bda3a9092d3ec34fbd959450767bcc8b8b6d&amp;v=4" width="139" alt="nk"/><br />nk</a></td>
177
+ <td align="center"><a href="https://github.com/supastarter?ref=orpc" target="_blank" rel="noopener" title="supastarter"><img src="https://avatars.githubusercontent.com/u/110960143?v=4" width="139" alt="supastarter"/><br />supastarter</a></td>
178
+ <td align="center"><a href="https://github.com/divmgl?ref=orpc" target="_blank" rel="noopener" title="Dexter Miguel"><img src="https://avatars.githubusercontent.com/u/5452298?u=645993204be8696c085ecf0d228c3062efe2ed65&amp;v=4" width="139" alt="Dexter Miguel"/><br />Dexter Miguel</a></td>
179
+ <td align="center"><a href="https://github.com/herrfugbaum?ref=orpc" target="_blank" rel="noopener" title="herrfugbaum"><img src="https://avatars.githubusercontent.com/u/12859776?u=644dc1666d0220bc0468eb0de3c56b919f635b16&amp;v=4" width="139" alt="herrfugbaum"/><br />herrfugbaum</a></td>
180
+ <td align="center"><a href="https://github.com/ryota-murakami?ref=orpc" target="_blank" rel="noopener" title="Ryota Murakami"><img src="https://avatars.githubusercontent.com/u/5501268?u=599389e03340734325726ca3f8f423c021d47d7f&amp;v=4" width="139" alt="Ryota Murakami"/><br />Ryota Murakami</a></td>
181
+ </tr>
182
+ <tr>
183
+ <td align="center"><a href="https://github.com/dcramer?ref=orpc" target="_blank" rel="noopener" title="David Cramer"><img src="https://avatars.githubusercontent.com/u/23610?v=4" width="139" alt="David Cramer"/><br />David Cramer</a></td>
184
+ <td align="center"><a href="https://github.com/valerii15298?ref=orpc" target="_blank" rel="noopener" title="Valerii Petryniak"><img src="https://avatars.githubusercontent.com/u/44531564?u=88ac74d9bacd20401518441907acad21063cd397&amp;v=4" width="139" alt="Valerii Petryniak"/><br />Valerii Petryniak</a></td>
185
+ <td align="center"><a href="https://github.com/letstri?ref=orpc" target="_blank" rel="noopener" title="Valerii Strilets"><img src="https://avatars.githubusercontent.com/u/13253748?u=c7b10399ccc8f8081e24db94ec32cd9858e86ac3&amp;v=4" width="139" alt="Valerii Strilets"/><br />Valerii Strilets</a></td>
186
+ <td align="center"><a href="https://github.com/K-Mistele?ref=orpc" target="_blank" rel="noopener" title="Kyle Mistele"><img src="https://avatars.githubusercontent.com/u/18430555?u=3afebeb81de666e35aaac3ed46f14159d7603ffb&amp;v=4" width="139" alt="Kyle Mistele"/><br />Kyle Mistele</a></td>
187
+ <td align="center"><a href="https://github.com/christ12938?ref=orpc" target="_blank" rel="noopener" title="christ12938"><img src="https://avatars.githubusercontent.com/u/25758598?v=4" width="139" alt="christ12938"/><br />christ12938</a></td>
188
+ <td align="center"><a href="https://github.com/Ryanjso?ref=orpc" target="_blank" rel="noopener" title="Ryan Soderberg"><img src="https://avatars.githubusercontent.com/u/39172778?u=5ed913c31d57e7221b75784abcad48c7ebddde27&amp;v=4" width="139" alt="Ryan Soderberg"/><br />Ryan Soderberg</a></td>
189
+ </tr>
190
+ <tr>
191
+ <td align="center"><a href="https://github.com/itigoore01?ref=orpc" target="_blank" rel="noopener" title="shota"><img src="https://avatars.githubusercontent.com/u/11831107?u=c976a6dc7e055eb026304c46c99100ed22b0c8e0&amp;v=4" width="139" alt="shota"/><br />shota</a></td>
192
+ <td align="center"><a href="https://github.com/ellis-driscoll?ref=orpc" target="_blank" rel="noopener" title="Ellis Driscoll"><img src="https://avatars.githubusercontent.com/u/70685966?u=c5f95bc33b5991d9744abe00052542e4a2ed3cb9&amp;v=4" width="139" alt="Ellis Driscoll"/><br />Ellis Driscoll</a></td>
193
+ </tr>
194
+ </table>
195
+
196
+ ### Backers
197
+
198
+ <table>
199
+ <tr>
200
+ <td align="center"><a href="https://github.com/rhinodavid?ref=orpc" target="_blank" rel="noopener" title="David Walsh"><img src="https://avatars.githubusercontent.com/u/5778036?u=b5521f07d2f88c3db2a0dae62b5f2f8357214af0&amp;v=4" width="119" alt="David Walsh"/><br />David Walsh</a></td>
201
+ <td align="center"><a href="https://github.com/Robbe95?ref=orpc" target="_blank" rel="noopener" title="Robbe Vaes"><img src="https://avatars.githubusercontent.com/u/44748019?u=e0232402c045ad4eac7cbd217f1f47e083103b89&amp;v=4" width="119" alt="Robbe Vaes"/><br />Robbe Vaes</a></td>
202
+ <td align="center"><a href="https://github.com/aidansunbury?ref=orpc" target="_blank" rel="noopener" title="Aidan Sunbury"><img src="https://avatars.githubusercontent.com/u/64103161?v=4" width="119" alt="Aidan Sunbury"/><br />Aidan Sunbury</a></td>
203
+ <td align="center"><a href="https://github.com/soonoo?ref=orpc" target="_blank" rel="noopener" title="soonoo"><img src="https://avatars.githubusercontent.com/u/5436405?u=5d0b4aa955c87e30e6bda7f0cccae5402da99528&amp;v=4" width="119" alt="soonoo"/><br />soonoo</a></td>
204
+ <td align="center"><a href="https://github.com/kporten?ref=orpc" target="_blank" rel="noopener" title="Kevin Porten"><img src="https://avatars.githubusercontent.com/u/1839345?u=dc2263d5cfe0d927ce1a0be04a1d55dd6b55405c&amp;v=4" width="119" alt="Kevin Porten"/><br />Kevin Porten</a></td>
205
+ <td align="center"><a href="https://github.com/pumpkinlink?ref=orpc" target="_blank" rel="noopener" title="Denis"><img src="https://avatars.githubusercontent.com/u/11864620?u=5f47bbe6c65d0f6f5cf011021490238e4b0593d0&amp;v=4" width="119" alt="Denis"/><br />Denis</a></td>
206
+ <td align="center"><a href="https://github.com/christopher-kapic?ref=orpc" target="_blank" rel="noopener" title="Christopher Kapic"><img src="https://avatars.githubusercontent.com/u/59740769?u=e7ad4b72b5bf6c9eb1644c26dbf3332a8f987377&amp;v=4" width="119" alt="Christopher Kapic"/><br />Christopher Kapic</a></td>
207
+ </tr>
208
+ <tr>
209
+ <td align="center"><a href="https://github.com/thomasballinger?ref=orpc" target="_blank" rel="noopener" title="Tom Ballinger"><img src="https://avatars.githubusercontent.com/u/458879?u=4b045ac75d721b6ac2b42a74d7d37f61f0414031&amp;v=4" width="119" alt="Tom Ballinger"/><br />Tom Ballinger</a></td>
210
+ <td align="center"><a href="https://github.com/SSam0419?ref=orpc" target="_blank" rel="noopener" title="Sam"><img src="https://avatars.githubusercontent.com/u/102863520?u=3c89611f549d5070be232eb4532f690c8f2e7a65&amp;v=4" width="119" alt="Sam"/><br />Sam</a></td>
211
+ <td align="center"><a href="https://github.com/Titoine?ref=orpc" target="_blank" rel="noopener" title="Titoine"><img src="https://avatars.githubusercontent.com/u/3514286?u=1bb1e86b0c99c8a1121372e56d51a177eea12191&amp;v=4" width="119" alt="Titoine"/><br />Titoine</a></td>
212
+ <td align="center"><a href="https://github.com/Mnigos?ref=orpc" target="_blank" rel="noopener" title="Igor Makowski"><img src="https://avatars.githubusercontent.com/u/56691628?u=ee8c879478f7c151b9156aef6c74243fa3e247a8&amp;v=4" width="119" alt="Igor Makowski"/><br />Igor Makowski</a></td>
213
+ <td align="center"><a href="https://github.com/hanayashiki?ref=orpc" target="_blank" rel="noopener" title="hanayashiki"><img src="https://avatars.githubusercontent.com/u/26056783?u=06c3b9205a16fd41a871e82da1cc2a09306d53f5&amp;v=4" width="119" alt="hanayashiki"/><br />hanayashiki</a></td>
214
+ <td align="center"><a href="https://github.com/ldub?ref=orpc" target="_blank" rel="noopener" title="Lev Dubinets"><img src="https://avatars.githubusercontent.com/u/3114081?u=f547f5d5012cab54851f1b1ad72d10e537f78fc2&amp;v=4" width="119" alt="Lev Dubinets"/><br />Lev Dubinets</a></td>
215
+ <td align="center"><a href="https://github.com/mr-kelly?ref=orpc" target="_blank" rel="noopener" title="Kelly Peilin Chan"><img src="https://avatars.githubusercontent.com/u/520852?u=6b0f7105f694e7b5cacf410a3f04c7044b469dc8&amp;v=4" width="119" alt="Kelly Peilin Chan"/><br />Kelly Peilin Chan</a></td>
216
+ </tr>
217
+ <tr>
218
+ <td align="center"><a href="https://github.com/piscis?ref=orpc" target="_blank" rel="noopener" title="Alex"><img src="https://avatars.githubusercontent.com/u/326163?u=b245f368bd940cf51d08c0b6bf55f8257f359437&amp;v=4" width="119" alt="Alex"/><br />Alex</a></td>
219
+ <td align="center"><a href="https://github.com/finom?ref=orpc" target="_blank" rel="noopener" title="Andrey Gubanov"><img src="https://avatars.githubusercontent.com/u/1082083?u=c5f2daf7ebece498e85c83367bb37b4e10e2649d&amp;v=4" width="119" alt="Andrey Gubanov"/><br />Andrey Gubanov</a></td>
220
+ </tr>
221
+ </table>
222
+
223
+ ### Past Sponsors
224
+
225
+ <p>
226
+ <a href="https://github.com/MrMaxie?ref=orpc" target="_blank" rel="noopener" title="Maxie"><img src="https://avatars.githubusercontent.com/u/3857836?u=5e6b57973d4385d655663ffdd836e487856f2984&amp;v=4" width="32" height="32" alt="Maxie" /></a>
227
+ <a href="https://github.com/Stijn-Timmer?ref=orpc" target="_blank" rel="noopener" title="Stijn Timmer"><img src="https://avatars.githubusercontent.com/u/100147665?u=106b2c18e9c98a61861b4ee7fc100f5b9906a6c9&amp;v=4" width="32" height="32" alt="Stijn Timmer" /></a>
228
+ <a href="https://github.com/u1-liquid?ref=orpc" target="_blank" rel="noopener" title="あわわわとーにゅ"><img src="https://avatars.githubusercontent.com/u/17376330?u=de3353804be889f009f7e0a1582daf04d0ab292d&amp;v=4" width="32" height="32" alt="あわわわとーにゅ" /></a>
229
+ <a href="https://github.com/zuplo?ref=orpc" target="_blank" rel="noopener" title="Zuplo"><img src="https://avatars.githubusercontent.com/u/85497839?v=4" width="32" height="32" alt="Zuplo" /></a>
230
+ <a href="https://github.com/motopods?ref=orpc" target="_blank" rel="noopener" title="motopods"><img src="https://avatars.githubusercontent.com/u/58200641?v=4" width="32" height="32" alt="motopods" /></a>
231
+ <a href="https://github.com/franciscohermida?ref=orpc" target="_blank" rel="noopener" title="Francisco Hermida"><img src="https://avatars.githubusercontent.com/u/483242?u=bbcbc80eb9d8781ff401f7dafc3b59cd7bea0561&amp;v=4" width="32" height="32" alt="Francisco Hermida" /></a>
232
+ <a href="https://github.com/theoludwig?ref=orpc" target="_blank" rel="noopener" title="Théo LUDWIG"><img src="https://avatars.githubusercontent.com/u/25207499?u=a6a9653725a2f574c07893748806668e0598cdbe&amp;v=4" width="32" height="32" alt="Théo LUDWIG" /></a>
233
+ <a href="https://github.com/abhay-ramesh?ref=orpc" target="_blank" rel="noopener" title="Abhay Ramesh"><img src="https://avatars.githubusercontent.com/u/66196314?u=c5c2b0327b26606c2efcfaf17046ab18c3d25c57&amp;v=4" width="32" height="32" alt="Abhay Ramesh" /></a>
234
+ <a href="https://github.com/shr-ink?ref=orpc" target="_blank" rel="noopener" title="shr.ink oü"><img src="https://avatars.githubusercontent.com/u/139700438?v=4" width="32" height="32" alt="shr.ink oü" /></a>
235
+ <a href="https://github.com/johngerome?ref=orpc" target="_blank" rel="noopener" title="0x4e32"><img src="https://avatars.githubusercontent.com/u/2002000?u=505e54608466ab53754f702973687b04c6424c1f&amp;v=4" width="32" height="32" alt="0x4e32" /></a>
236
+ <a href="https://github.com/yzuyr?ref=orpc" target="_blank" rel="noopener" title="Ryuz"><img src="https://avatars.githubusercontent.com/u/196539378?u=d38374588d219b6748b16406982f6559411466d4&amp;v=4" width="32" height="32" alt="Ryuz" /></a>
237
+ <a href="https://github.com/happyboy2022?ref=orpc" target="_blank" rel="noopener" title="happyboy"><img src="https://avatars.githubusercontent.com/u/103669586?u=65b49c4b893ed3703909fbb3a7a22313f3f9c121&amp;v=4" width="32" height="32" alt="happyboy" /></a>
238
+ <a href="https://github.com/YiCChi?ref=orpc" target="_blank" rel="noopener" title="yicchi"><img src="https://avatars.githubusercontent.com/u/86967274?u=6c2756f09fe15dd94d572f560e979cd157982852&amp;v=4" width="32" height="32" alt="yicchi" /></a>
239
+ <a href="https://github.com/cloudycotton?ref=orpc" target="_blank" rel="noopener" title="Saksham"><img src="https://avatars.githubusercontent.com/u/168998965?u=9b9634a5aed66a51c1b880663272725b00b92b14&amp;v=4" width="32" height="32" alt="Saksham" /></a>
240
+ <a href="https://github.com/hrynevychroman?ref=orpc" target="_blank" rel="noopener" title="Roman Hrynevych"><img src="https://avatars.githubusercontent.com/u/82209198?u=1a1d111ab3d589855b9cc8a7fefb1b5c6a4fbbaf&amp;v=4" width="32" height="32" alt="Roman Hrynevych" /></a>
241
+ <a href="https://github.com/rokitgg?ref=orpc" target="_blank" rel="noopener" title="rokitg"><img src="https://avatars.githubusercontent.com/u/125133357?u=06c74aefaa2236b06a2e5fba5a5c612339f45912&amp;v=4" width="32" height="32" alt="rokitg" /></a>
242
+ <a href="https://github.com/omarkhatibgg?ref=orpc" target="_blank" rel="noopener" title="Omar Khatib"><img src="https://avatars.githubusercontent.com/u/9054278?u=afbba7331b85c51b8eee4130f5fd31b1017dc919&amp;v=4" width="32" height="32" alt="Omar Khatib" /></a>
243
+ <a href="https://github.com/YuSabo90002?ref=orpc" target="_blank" rel="noopener" title="Yu-Sabo"><img src="https://avatars.githubusercontent.com/u/13120582?v=4" width="32" height="32" alt="Yu-Sabo" /></a>
244
+ <a href="https://github.com/bapspatil?ref=orpc" target="_blank" rel="noopener" title="Bapusaheb Patil"><img src="https://avatars.githubusercontent.com/u/16699418?u=6d9d8e0a64a6f91ca1c4d559c72d931172bdcbbd&amp;v=4" width="32" height="32" alt="Bapusaheb Patil" /></a>
245
+ <a href="https://github.com/ripgrim?ref=orpc" target="_blank" rel="noopener" title="grim"><img src="https://avatars.githubusercontent.com/u/75869731?u=b17c42ec2309552fdb822a86b25a2f99146a4d72&amp;v=4" width="32" height="32" alt="grim" /></a>
246
+ <a href="https://github.com/nelsonlaidev?ref=orpc" target="_blank" rel="noopener" title="Nelson Lai"><img src="https://avatars.githubusercontent.com/u/75498339?u=2fc0e0b95dd184c5ffb744df977cb15a18b60672&amp;v=4" width="32" height="32" alt="Nelson Lai" /></a>
247
+ <a href="https://github.com/nguyenlc1993?ref=orpc" target="_blank" rel="noopener" title="Lê Cao Nguyên"><img src="https://avatars.githubusercontent.com/u/13871971?u=83c8b69d9e35b589c4e1f066cc113b1d9461386f&amp;v=4" width="32" height="32" alt="Lê Cao Nguyên" /></a>
248
+ <a href="https://github.com/wobsoriano?ref=orpc" target="_blank" rel="noopener" title="Robert Soriano"><img src="https://avatars.githubusercontent.com/u/13049130?u=6d72104182e7c9ed25934815313fb69107332111&amp;v=4" width="32" height="32" alt="Robert Soriano" /></a>
249
+ <a href="https://github.com/andrewpeters9?ref=orpc" target="_blank" rel="noopener" title="Andrew Peters"><img src="https://avatars.githubusercontent.com/u/36251325?v=4" width="32" height="32" alt="Andrew Peters" /></a>
250
+ <a href="https://github.com/R44VC0RP?ref=orpc" target="_blank" rel="noopener" title="Ryan Vogel"><img src="https://avatars.githubusercontent.com/u/89211796?u=1857347b9787d8d8a7ea5bfc333f96be92d5a683&amp;v=4" width="32" height="32" alt="Ryan Vogel" /></a>
251
+ <a href="https://github.com/SKostyukovich?ref=orpc" target="_blank" rel="noopener" title="SKostyukovich"><img src="https://avatars.githubusercontent.com/u/10700067?v=4" width="32" height="32" alt="SKostyukovich" /></a>
252
+ <a href="https://github.com/peter-adam-dy?ref=orpc" target="_blank" rel="noopener" title="Peter Adam"><img src="https://avatars.githubusercontent.com/u/132129459?u=4f3dbbb3b443990b56acb7d6a5d11ed2c555f6db&amp;v=4" width="32" height="32" alt="Peter Adam" /></a>
253
+ <a href="https://github.com/FabworksHQ?ref=orpc" target="_blank" rel="noopener" title="Fabworks"><img src="https://avatars.githubusercontent.com/u/160179500?v=4" width="32" height="32" alt="Fabworks" /></a>
254
+ <a href="https://github.com/NovakAnton?ref=orpc" target="_blank" rel="noopener" title="Novak Antonijevic"><img src="https://avatars.githubusercontent.com/u/157126729?u=ae49fa22292d55c0434ff0ca008206155b18663b&amp;v=4" width="32" height="32" alt="Novak Antonijevic" /></a>
255
+ <a href="https://github.com/laduniestu?ref=orpc" target="_blank" rel="noopener" title="Laduni Estu Syalwa"><img src="https://avatars.githubusercontent.com/u/44757637?u=a2fc1ea8f7d827a96721176f79d30592d1c48059&amp;v=4" width="32" height="32" alt="Laduni Estu Syalwa" /></a>
256
+ <a href="https://github.com/yukimotochern?ref=orpc" target="_blank" rel="noopener" title="Chen, Zhi-Yuan"><img src="https://avatars.githubusercontent.com/u/20896173?u=945c33fc21725e4d566a0d02afc54b136ca1d67a&amp;v=4" width="32" height="32" alt="Chen, Zhi-Yuan" /></a>
257
+ <a href="https://github.com/illarionvk?ref=orpc" target="_blank" rel="noopener" title="Illarion Koperski"><img src="https://avatars.githubusercontent.com/u/5012724?u=7cfa13652f7ac5fb3c56d880e3eb3fbe40c3ea34&amp;v=4" width="32" height="32" alt="Illarion Koperski" /></a>
258
+ <a href="https://github.com/steelbrain?ref=orpc" target="_blank" rel="noopener" title="Anees Iqbal"><img src="https://avatars.githubusercontent.com/u/4278113?u=22b80b5399eed68ac76cd58b02961b0481f1db11&amp;v=4" width="32" height="32" alt="Anees Iqbal" /></a>
259
+ <a href="https://github.com/Scrumplex?ref=orpc" target="_blank" rel="noopener" title="Sefa Eyeoglu"><img src="https://avatars.githubusercontent.com/u/11587657?u=ab503582165c0bbff0cca47ce31c9450bb1553c9&amp;v=4" width="32" height="32" alt="Sefa Eyeoglu" /></a>
260
+ <a href="https://github.com/nattstack?ref=orpc" target="_blank" rel="noopener" title="natt"><img src="https://avatars.githubusercontent.com/u/31426677?u=fa9dbb8b3e66eb0ea3c88db5dc07f31c8c5418fe&amp;v=4" width="32" height="32" alt="natt" /></a>
261
+ <a href="https://github.com/ChromeGG?ref=orpc" target="_blank" rel="noopener" title="Adam Tkaczyk"><img src="https://avatars.githubusercontent.com/u/39050595?u=a58ca6042a6950e94e6e92442db76ef584279bc0&amp;v=4" width="32" height="32" alt="Adam Tkaczyk" /></a>
262
+ <a href="https://github.com/plancraft?ref=orpc" target="_blank" rel="noopener" title="plancraft"><img src="https://avatars.githubusercontent.com/u/46482287?v=4" width="32" height="32" alt="plancraft" /></a>
263
+ <a href="https://github.com/Nic13Gamer?ref=orpc" target="_blank" rel="noopener" title="Nicholas"><img src="https://avatars.githubusercontent.com/u/54724556?u=56a7ab430ce7a80d648ab6eba051d454a818ed0b&amp;v=4" width="32" height="32" alt="Nicholas" /></a>
264
+ </p>
@@ -0,0 +1,21 @@
1
+ import { StandardLazyRequest, StandardResponse } from '@standardserver/core';
2
+ import { FastifyReply, RouteGenericInterface, RawServerBase, FastifyRequest } from 'fastify';
3
+ import { ToNodeHttpBodyOptions } from '@standardserver/node';
4
+
5
+ /**
6
+ * A fastify request from any raw server (http, https, http2, http2 secure) and any route generic.
7
+ */
8
+ type AnyFastifyRequest = FastifyRequest<RouteGenericInterface, RawServerBase>;
9
+ /**
10
+ * A fastify reply from any raw server (http, https, http2, http2 secure) and any route generic.
11
+ */
12
+ type AnyFastifyReply = FastifyReply<RouteGenericInterface, RawServerBase>;
13
+
14
+ declare function toStandardLazyRequest(req: AnyFastifyRequest, reply: AnyFastifyReply): StandardLazyRequest;
15
+
16
+ interface SendStandardResponseOptions extends ToNodeHttpBodyOptions {
17
+ }
18
+ declare function sendStandardResponse(reply: AnyFastifyReply, standardResponse: StandardResponse, options?: SendStandardResponseOptions): Promise<void>;
19
+
20
+ export { sendStandardResponse, toStandardLazyRequest };
21
+ export type { AnyFastifyReply, AnyFastifyRequest, SendStandardResponseOptions };
@@ -0,0 +1,21 @@
1
+ import { StandardLazyRequest, StandardResponse } from '@standardserver/core';
2
+ import { FastifyReply, RouteGenericInterface, RawServerBase, FastifyRequest } from 'fastify';
3
+ import { ToNodeHttpBodyOptions } from '@standardserver/node';
4
+
5
+ /**
6
+ * A fastify request from any raw server (http, https, http2, http2 secure) and any route generic.
7
+ */
8
+ type AnyFastifyRequest = FastifyRequest<RouteGenericInterface, RawServerBase>;
9
+ /**
10
+ * A fastify reply from any raw server (http, https, http2, http2 secure) and any route generic.
11
+ */
12
+ type AnyFastifyReply = FastifyReply<RouteGenericInterface, RawServerBase>;
13
+
14
+ declare function toStandardLazyRequest(req: AnyFastifyRequest, reply: AnyFastifyReply): StandardLazyRequest;
15
+
16
+ interface SendStandardResponseOptions extends ToNodeHttpBodyOptions {
17
+ }
18
+ declare function sendStandardResponse(reply: AnyFastifyReply, standardResponse: StandardResponse, options?: SendStandardResponseOptions): Promise<void>;
19
+
20
+ export { sendStandardResponse, toStandardLazyRequest };
21
+ export type { AnyFastifyReply, AnyFastifyRequest, SendStandardResponseOptions };
package/dist/index.mjs ADDED
@@ -0,0 +1,48 @@
1
+ import { toAbortSignal, toStandardBody, toStandardMethod, toStandardUrl, toNodeHttpBody, canWriteToNodeResponse, getNodeResponseError } from '@standardserver/node';
2
+
3
+ function toStandardLazyRequest(req, reply) {
4
+ const signal = toAbortSignal(reply.raw);
5
+ return {
6
+ url: toStandardUrl(req.raw),
7
+ method: toStandardMethod(req.raw.method),
8
+ headers: req.headers,
9
+ resolveBody: async (hint) => {
10
+ if (req.body !== void 0) {
11
+ return req.body;
12
+ }
13
+ return toStandardBody(req.raw, { hint });
14
+ },
15
+ signal
16
+ };
17
+ }
18
+
19
+ async function sendStandardResponse(reply, standardResponse, options = {}) {
20
+ const [resBody, resHeaders] = toNodeHttpBody(standardResponse.body, standardResponse.headers, options);
21
+ return new Promise((resolve, reject) => {
22
+ if (!canWriteToNodeResponse(reply.raw)) {
23
+ const error = getNodeResponseError(reply.raw);
24
+ if (typeof resBody === "object" && !resBody.closed) {
25
+ resBody.on("error", reject);
26
+ resBody.destroy(error ?? void 0);
27
+ }
28
+ if (error) {
29
+ reject(error);
30
+ } else {
31
+ resolve();
32
+ }
33
+ return;
34
+ }
35
+ reply.raw.once("error", reject);
36
+ reply.raw.once("close", resolve);
37
+ reply.status(standardResponse.status);
38
+ for (const key in resHeaders) {
39
+ const value = resHeaders[key];
40
+ if (value !== void 0) {
41
+ reply.header(key, value);
42
+ }
43
+ }
44
+ reply.send(resBody);
45
+ });
46
+ }
47
+
48
+ export { sendStandardResponse, toStandardLazyRequest };
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@standardserver/fastify",
3
+ "type": "module",
4
+ "version": "0.6.0",
5
+ "license": "MIT",
6
+ "homepage": "https://standardserver.dev",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/middleapi/standardserver.git",
10
+ "directory": "packages/fastify"
11
+ },
12
+ "sideEffects": false,
13
+ "exports": {
14
+ "./package.json": "./package.json",
15
+ ".": {
16
+ "types": "./dist/index.d.mts",
17
+ "import": "./dist/index.mjs",
18
+ "default": "./dist/index.mjs"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "peerDependencies": {
25
+ "fastify": ">=5.6.1"
26
+ },
27
+ "dependencies": {
28
+ "@standardserver/core": "0.6.0",
29
+ "@standardserver/node": "0.6.0"
30
+ },
31
+ "devDependencies": {
32
+ "@fastify/cookie": "^11.1.2",
33
+ "@types/node": "^26.0.0",
34
+ "@types/supertest": "^6.0.3",
35
+ "fastify": "^5.11.0",
36
+ "supertest": "^7.1.4"
37
+ },
38
+ "scripts": {
39
+ "build": "unbuild",
40
+ "type:check": "tsc -b"
41
+ }
42
+ }