@orpc/nest 2.0.0-beta.4 → 2.0.0-beta.41

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.
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Standard Server
3
+ Copyright (c) 2023 oRPC
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,14 +1,17 @@
1
1
  <h1 align="center">oRPC - Typesafe APIs Made Simple 🪄</h1>
2
2
 
3
3
  <div align="center">
4
- <a href="https://codecov.io/gh/middleapi/orpc-nest">
5
- <img alt="codecov" src="https://codecov.io/gh/middleapi/orpc-nest/branch/main/graph/badge.svg">
4
+ <a href="https://codecov.io/gh/middleapi/orpc">
5
+ <img alt="codecov" src="https://codecov.io/gh/middleapi/orpc/branch/main/graph/badge.svg">
6
6
  </a>
7
7
  <a href="https://www.npmjs.com/package/@orpc/nest">
8
8
  <img alt="weekly downloads" src="https://img.shields.io/npm/dw/%40orpc%2Fnest?logo=npm" />
9
9
  </a>
10
- <a href="https://github.com/middleapi/orpc-nest/blob/main/LICENCE">
11
- <img alt="MIT License" src="https://img.shields.io/github/license/middleapi/orpc-nest?logo=open-source-initiative" />
10
+ <a href="https://app.codspeed.io/middleapi/orpc?utm_source=badge">
11
+ <img alt="CodSpeed" src="https://img.shields.io/endpoint?url=https://codspeed.io/badge.json" />
12
+ </a>
13
+ <a href="https://github.com/middleapi/orpc/blob/main/LICENSE">
14
+ <img alt="MIT License" src="https://img.shields.io/github/license/middleapi/orpc?logo=open-source-initiative" />
12
15
  </a>
13
16
  <a href="https://discord.gg/TXEbwRBvQn">
14
17
  <img alt="Discord" src="https://img.shields.io/discord/1308966753044398161?color=7389D8&label&logo=discord&logoColor=ffffff" />
@@ -26,61 +29,93 @@ You can read the documentation [here](https://orpc.dev).
26
29
 
27
30
  **Core**
28
31
 
29
- - [@orpc/contract](https://www.npmjs.com/package/@orpc/contract): Define type-safe contracts for your API.
30
- - [@orpc/server](https://www.npmjs.com/package/@orpc/server): Implement your API or contract on the server.
31
- - [@orpc/client](https://www.npmjs.com/package/@orpc/client): Consume your API from the client with full type safety.
32
- - [@orpc/openapi](https://www.npmjs.com/package/@orpc/openapi): Bring OpenAPI compatibility to your APIs.
32
+ | Package | Purpose | Docs |
33
+ | -------------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
34
+ | [@orpc/contract](https://www.npmjs.com/package/@orpc/contract) | Define API contract as the single source of truth. | [Procedure Contract](https://orpc.dev/docs/contract/procedure), [Contract Router](https://orpc.dev/docs/contract/router), [Implementation](https://orpc.dev/docs/contract/implementation), [Generate from OpenAPI](https://orpc.dev/docs/contract/generate-from-openapi) |
35
+ | [@orpc/server](https://www.npmjs.com/package/@orpc/server) | Build APIs or implement contracts. | [Procedure](https://orpc.dev/docs/procedure), [Router](https://orpc.dev/docs/router), [Middleware](https://orpc.dev/docs/middleware), [Context](https://orpc.dev/docs/context), [RPC Handler](https://orpc.dev/docs/rpc/handler) |
36
+ | [@orpc/client](https://www.npmjs.com/package/@orpc/client) | Consume APIs with end-to-end type safety. | [Client-Side Clients](https://orpc.dev/docs/client/client-side), [Server-Side Clients](https://orpc.dev/docs/client/server-side), [RPC Link](https://orpc.dev/docs/rpc/link), [Error Handling](https://orpc.dev/docs/client/error-handling) |
37
+ | [@orpc/openapi](https://www.npmjs.com/package/@orpc/openapi) | Add OpenAPI compatibility to APIs. | [OpenAPI Handler](https://orpc.dev/docs/openapi/handler), [OpenAPI Link](https://orpc.dev/docs/openapi/link), [Specification](https://orpc.dev/docs/openapi/specification), [Scalar](https://orpc.dev/docs/openapi/scalar) |
33
38
 
34
39
  **Schema validation**
35
40
 
36
- - [@orpc/zod](https://www.npmjs.com/package/@orpc/zod): Integrate with [Zod](https://zod.dev/).
37
- - [@orpc/valibot](https://www.npmjs.com/package/@orpc/valibot): Integrate with [Valibot](https://valibot.dev/).
38
- - [@orpc/arktype](https://www.npmjs.com/package/@orpc/arktype): Integrate with [ArkType](https://arktype.io/).
41
+ | Package | Purpose | Docs |
42
+ | ------------------------------------------------------------ | ---------------------------------------------------------- | ----------------------------------------------------- |
43
+ | [@orpc/zod](https://www.npmjs.com/package/@orpc/zod) | JSON Schema converter for [Zod](https://zod.dev/). | [Zod](https://orpc.dev/docs/integrations/zod) |
44
+ | [@orpc/valibot](https://www.npmjs.com/package/@orpc/valibot) | JSON Schema converter for [Valibot](https://valibot.dev/). | [Valibot](https://orpc.dev/docs/integrations/valibot) |
45
+ | [@orpc/arktype](https://www.npmjs.com/package/@orpc/arktype) | JSON Schema converter for [ArkType](https://arktype.io/). | [ArkType](https://orpc.dev/docs/integrations/arktype) |
39
46
 
40
47
  **Built-in features**
41
48
 
42
- - [@orpc/publisher](https://www.npmjs.com/package/@orpc/publisher): Pub/Sub.
43
- - [@orpc/ratelimit](https://www.npmjs.com/package/@orpc/ratelimit): Rate limiting.
44
- - [@orpc/json-schema](https://www.npmjs.com/package/@orpc/json-schema): Smart coercion for OpenAPI requests.
49
+ | Package | Purpose | Docs |
50
+ | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
51
+ | [@orpc/publisher](https://www.npmjs.com/package/@orpc/publisher) | Pub/Sub with memory, Redis, and Upstash adapters. | [Publisher](https://orpc.dev/docs/helpers/publisher) |
52
+ | [@orpc/ratelimit](https://www.npmjs.com/package/@orpc/ratelimit) | Rate limiting with memory, Redis, and Upstash adapters. | [Rate Limit](https://orpc.dev/docs/helpers/ratelimit) |
53
+ | [@orpc/experimental-lock](https://www.npmjs.com/package/@orpc/experimental-lock) | Locking with memory, Redis, and Upstash adapters. | [Lock](https://orpc.dev/docs/helpers/lock) |
54
+ | [@orpc/hibernation](https://www.npmjs.com/package/@orpc/hibernation) | Leverage Hibernation APIs like [Cloudflare's Hibernation WebSocket](https://developers.cloudflare.com/durable-objects/best-practices/websockets/#durable-objects-hibernation-websocket-api). | [Hibernation](https://orpc.dev/docs/integrations/hibernation) |
55
+ | [@orpc/json-schema](https://www.npmjs.com/package/@orpc/json-schema) | Smart coercion for OpenAPI requests. | [Smart Coercion](https://orpc.dev/docs/plugins/smart-coercion) |
45
56
 
46
57
  **Framework & ecosystem integrations**
47
58
 
48
- - [@orpc/next](https://www.npmjs.com/package/@orpc/react): Use oRPC with [Next.js Server Functions](https://nextjs.org/docs/app/getting-started/mutating-data).
49
- - [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query): Integrate with [TanStack Query](https://tanstack.com/query/latest).
50
- - [@orpc/experimental-effect](https://www.npmjs.com/package/@orpc/experimental-effect): Integrate with [Effect](https://effect.website/).
51
- - [@orpc/nest](https://www.npmjs.com/package/@orpc/nest): Implement your contract with [NestJS](https://nestjs.com/).
59
+ | Package | Purpose | Docs |
60
+ | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
61
+ | [@orpc/next](https://www.npmjs.com/package/@orpc/next) | Integrate with [Next.js Server Functions](https://nextjs.org/docs/app/getting-started/mutating-data). | [Next.js](https://orpc.dev/docs/integrations/next) |
62
+ | [@orpc/ai-sdk](https://www.npmjs.com/package/@orpc/ai-sdk) | Turn contracts and procedures into [AI SDK](https://ai-sdk.dev/) tools. | [AI SDK](https://orpc.dev/docs/integrations/ai-sdk) |
63
+ | [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query) | Integrate with [TanStack Query](https://tanstack.com/query/latest). | [TanStack Query](https://orpc.dev/docs/integrations/tanstack-query) |
64
+ | [@orpc/pinia-colada](https://www.npmjs.com/package/@orpc/pinia-colada) | Integrate with [Pinia Colada](https://pinia-colada.esm.dev/). | [Pinia Colada](https://orpc.dev/docs/integrations/pinia-colada) |
65
+ | [@orpc/swr](https://www.npmjs.com/package/@orpc/swr) | Integrate with [SWR](https://swr.vercel.app/). | [SWR](https://orpc.dev/docs/integrations/swr) |
66
+ | [@orpc/experimental-msw](https://www.npmjs.com/package/@orpc/experimental-msw) | Mock procedures with [Mock Service Worker](https://mswjs.io/). | [MSW](https://orpc.dev/docs/integrations/msw) |
67
+ | [@orpc/experimental-effect](https://www.npmjs.com/package/@orpc/experimental-effect) | Integrate with [Effect](https://effect.website/). | [Effect](https://orpc.dev/docs/integrations/effect) |
68
+ | [@orpc/nest](https://www.npmjs.com/package/@orpc/nest) | Implement your contract with [NestJS](https://nestjs.com/). | [NestJS](https://orpc.dev/docs/integrations/nest) |
69
+ | [@orpc/node](https://www.npmjs.com/package/@orpc/node) | [Node.js](https://nodejs.org/) plugins for static file serving and large uploads. | [Static File](https://orpc.dev/docs/plugins/static-file), [Tmp File Upload](https://orpc.dev/docs/plugins/tmp-file-upload), [Batch Response Compression](https://orpc.dev/docs/plugins/batch-response-compression) |
70
+ | [@orpc/bun](https://www.npmjs.com/package/@orpc/bun) | Adapters for [Bun's Redis](https://bun.sh/). | [Publisher](https://orpc.dev/docs/helpers/publisher), [Rate Limit](https://orpc.dev/docs/helpers/ratelimit), [Lock](https://orpc.dev/docs/helpers/lock) |
71
+ | [@orpc/cloudflare](https://www.npmjs.com/package/@orpc/cloudflare) | Adapters for [Cloudflare Workers](https://developers.cloudflare.com/workers/). | [Publisher](https://orpc.dev/docs/helpers/publisher), [Rate Limit](https://orpc.dev/docs/helpers/ratelimit), [Lock](https://orpc.dev/docs/helpers/lock), [Traces](https://orpc.dev/docs/integrations/cloudflare-traces) |
72
+ | [@orpc/trpc](https://www.npmjs.com/package/@orpc/trpc) | Reuse existing [tRPC](https://trpc.io/) routers within oRPC. | [tRPC](https://orpc.dev/docs/integrations/trpc) |
52
73
 
53
74
  **Observability**
54
75
 
55
- - [@orpc/opentelemetry](https://www.npmjs.com/package/@orpc/opentelemetry): Instrument your API with [OpenTelemetry](https://opentelemetry.io/).
56
- - [@orpc/pino](https://www.npmjs.com/package/@orpc/pino): Log with [Pino](https://getpino.io/).
57
- - [@orpc/evlog](https://www.npmjs.com/package/@orpc/evlog): Log with [Evlog](https://evlog.dev/).
76
+ | Package | Purpose | Docs |
77
+ | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
78
+ | [@orpc/opentelemetry](https://www.npmjs.com/package/@orpc/opentelemetry) | Integrate with [OpenTelemetry](https://opentelemetry.io/) for distributed tracing. | [OpenTelemetry](https://orpc.dev/docs/integrations/opentelemetry) |
79
+ | [@orpc/pino](https://www.npmjs.com/package/@orpc/pino) | Integrate with [Pino](https://getpino.io/) for logging. | [Pino](https://orpc.dev/docs/integrations/pino) |
80
+ | [@orpc/evlog](https://www.npmjs.com/package/@orpc/evlog) | Integrate with [Evlog](https://evlog.dev/) for logging. | [Evlog](https://orpc.dev/docs/integrations/evlog) |
58
81
 
59
82
  ## Sponsors
60
83
 
61
- 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! 🚀
84
+ Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going through [GitHub Sponsors](https://github.com/sponsors/dinwwwh) or [Open Collective](https://opencollective.com/middleapi). Every bit helps! 🚀
85
+
86
+ <table>
87
+ <tr>
88
+ <td width="2000"><a href="https://screenshotone.com/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="The screenshot API for developers"><img src="https://avatars.githubusercontent.com/u/97035603?v=4" width="64" align="left" hspace="12" alt="ScreenshotOne.com"/><b>ScreenshotOne.com</b></a><br /><sub>The screenshot API for developers</sub></td>
89
+ </tr>
90
+ <tr>
91
+ <td width="2000"><a href="https://yuzu.health/careers?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="We&#39;re hiring NYC based engineers"><img src="https://avatars.githubusercontent.com/u/102488956?v=4" width="64" align="left" hspace="12" alt="Yuzu"/><b>Yuzu</b></a><br /><sub>We&#39;re hiring NYC based engineers</sub></td>
92
+ </tr>
93
+ <tr>
94
+ <td width="2000"><a href="https://misskey.io/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Decentralized microblogging SNS born on Earth"><img src="https://github.com/MisskeyIO.png" width="64" align="left" hspace="12" alt="MisskeyHQ"/><b>MisskeyHQ</b></a><br /><sub>Decentralized microblogging SNS born on Earth</sub></td>
95
+ </tr>
96
+ </table>
62
97
 
63
- ### 🏆 Platinum Sponsor
98
+ ### Special Sponsors
64
99
 
65
100
  <table>
66
101
  <tr>
67
- <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>
102
+ <td align="center"><a href="http://twitter.com/rauchg?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Guillermo Rauch"><img src="https://avatars.githubusercontent.com/u/13041?u=1ee8d111657cdd02ff6d253df00978d17ee6d722&amp;v=4" width="279" alt="Guillermo Rauch"/><br />Guillermo Rauch</a></td>
68
103
  </tr>
69
104
  </table>
70
105
 
71
- ### 🥈 Silver Sponsor
106
+ ### Premium Sponsors
72
107
 
73
108
  <table>
74
109
  <tr>
75
- <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>
110
+ <td align="center"><a href="https://github.com/nexa-ca?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Nexa"><img src="https://avatars.githubusercontent.com/u/199146462?v=4" width="209" alt="Nexa"/><br />Nexa</a></td>
76
111
  </tr>
77
112
  </table>
78
113
 
79
- ### Generous Sponsors
114
+ ### Organization Sponsors
80
115
 
81
116
  <table>
82
117
  <tr>
83
- <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>
118
+ <td align="center"><a href="https://lnmarkets.com/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="LN Markets"><img src="https://avatars.githubusercontent.com/u/70597625?v=4" width="167" alt="LN Markets"/><br />LN Markets</a></td>
84
119
  </tr>
85
120
  </table>
86
121
 
@@ -88,26 +123,27 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
88
123
 
89
124
  <table>
90
125
  <tr>
91
- <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>
92
- <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>
93
- <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>
94
- <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>
95
- <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>
96
- <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>
126
+ <td align="center"><a href="https://github.com/hrmcdonald?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Reece McDonald"><img src="https://avatars.githubusercontent.com/u/39349270?v=4" width="139" alt="Reece McDonald"/><br />Reece McDonald</a></td>
127
+ <td align="center"><a href="https://soymilk.party/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="あわわわとーにゅ"><img src="https://avatars.githubusercontent.com/u/17376330?u=de3353804be889f009f7e0a1582daf04d0ab292d&amp;v=4" width="139" alt="あわわわとーにゅ"/><br />あわわわとーにゅ</a></td>
128
+ <td align="center"><a href="https://github.com/nicognaW?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="nk"><img src="https://avatars.githubusercontent.com/u/66731869?u=4699bda3a9092d3ec34fbd959450767bcc8b8b6d&amp;v=4" width="139" alt="nk"/><br />nk</a></td>
129
+ <td align="center"><a href="https://supastarter.dev/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="supastarter"><img src="https://avatars.githubusercontent.com/u/110960143?v=4" width="139" alt="supastarter"/><br />supastarter</a></td>
130
+ <td align="center"><a href="https://github.com/herrfugbaum?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="herrfugbaum"><img src="https://avatars.githubusercontent.com/u/12859776?u=644dc1666d0220bc0468eb0de3c56b919f635b16&amp;v=4" width="139" alt="herrfugbaum"/><br />herrfugbaum</a></td>
131
+ <td align="center"><a href="https://laststance.io/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
97
132
  </tr>
98
133
  <tr>
99
- <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>
100
- <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>
101
- <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>
102
- <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>
103
- <td align="center"><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="139" alt="Andrew Peters"/><br />Andrew Peters</a></td>
104
- <td align="center"><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="139" alt="Ryan Vogel"/><br />Ryan Vogel</a></td>
134
+ <td align="center"><a href="https://cra.mr/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="David Cramer"><img src="https://avatars.githubusercontent.com/u/23610?v=4" width="139" alt="David Cramer"/><br />David Cramer</a></td>
135
+ <td align="center"><a href="https://valerii15298.github.io/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
136
+ <td align="center"><a href="https://letstri.dev/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
137
+ <td align="center"><a href="https://blacklight.sh/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
138
+ <td align="center"><a href="https://github.com/christ12938?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="christ12938"><img src="https://avatars.githubusercontent.com/u/25758598?v=4" width="139" alt="christ12938"/><br />christ12938</a></td>
139
+ <td align="center"><a href="https://github.com/Ryanjso?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
105
140
  </tr>
106
141
  <tr>
107
- <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>
108
- <td align="center"><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="139" alt="Peter Adam"/><br />Peter Adam</a></td>
109
- <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>
110
- <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>
142
+ <td align="center"><a href="https://github.com/itigoore01?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="shota"><img src="https://avatars.githubusercontent.com/u/11831107?u=c976a6dc7e055eb026304c46c99100ed22b0c8e0&amp;v=4" width="139" alt="shota"/><br />shota</a></td>
143
+ <td align="center"><a href="https://github.com/ellis-driscoll?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
144
+ <td align="center"><a href="https://github.com/hoangbn?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Hoang Nguyen"><img src="https://avatars.githubusercontent.com/u/38968280?u=c90084c6de65c56facabab7ba13a72a49ddbc3e4&amp;v=4" width="139" alt="Hoang Nguyen"/><br />Hoang Nguyen</a></td>
145
+ <td align="center"><a href="https://opencollective.com/guest-ac41de3b?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Orestis Ioannou"><img src="https://images.opencollective.com/guest-ac41de3b/avatar/460.png" width="139" alt="Orestis Ioannou"/><br />Orestis Ioannou</a></td>
146
+ <td align="center"><a href="https://automatio.ai/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Stefan Smiljkovic"><img src="https://avatars.githubusercontent.com/u/1984909?u=b7bf5bc40ed49df3c22f69d2da7b8d78709c49ed&amp;v=4" width="139" alt="Stefan Smiljkovic"/><br />Stefan Smiljkovic</a></td>
111
147
  </tr>
112
148
  </table>
113
149
 
@@ -115,67 +151,34 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
115
151
 
116
152
  <table>
117
153
  <tr>
118
- <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>
119
- <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>
120
- <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>
121
- <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>
122
- <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>
123
- <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>
124
- <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>
154
+ <td align="center"><a href="https://github.com/rhinodavid?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
155
+ <td align="center"><a href="https://github.com/IPv4Addr?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="IPv4Addr"><img src="https://avatars.githubusercontent.com/u/100147665?u=59996b72f69bb53063cb7e9ff8b8f898616cd94d&amp;v=4" width="119" alt="IPv4Addr"/><br />IPv4Addr</a></td>
156
+ <td align="center"><a href="https://robbevaes.be/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
157
+ <td align="center"><a href="https://github.com/aidansunbury?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Aidan Sunbury"><img src="https://avatars.githubusercontent.com/u/64103161?v=4" width="119" alt="Aidan Sunbury"/><br />Aidan Sunbury</a></td>
158
+ <td align="center"><a href="https://github.com/soonoo?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="soonoo"><img src="https://avatars.githubusercontent.com/u/5436405?u=5d0b4aa955c87e30e6bda7f0cccae5402da99528&amp;v=4" width="119" alt="soonoo"/><br />soonoo</a></td>
159
+ <td align="center"><a href="https://kevinporten.dev/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
160
+ <td align="center"><a href="https://github.com/pumpkinlink?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Denis"><img src="https://avatars.githubusercontent.com/u/11864620?u=5f47bbe6c65d0f6f5cf011021490238e4b0593d0&amp;v=4" width="119" alt="Denis"/><br />Denis</a></td>
125
161
  </tr>
126
162
  <tr>
127
- <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>
128
- <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>
129
- <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>
130
- <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>
131
- <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>
132
- <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>
133
- <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>
163
+ <td align="center"><a href="https://github.com/christopher-kapic?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
164
+ <td align="center"><a href="http://ballingt.com/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
165
+ <td align="center"><a href="https://lee-sam.com/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Sam"><img src="https://avatars.githubusercontent.com/u/102863520?u=3c89611f549d5070be232eb4532f690c8f2e7a65&amp;v=4" width="119" alt="Sam"/><br />Sam</a></td>
166
+ <td align="center"><a href="https://github.com/Titoine?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Titoine"><img src="https://avatars.githubusercontent.com/u/3514286?u=1bb1e86b0c99c8a1121372e56d51a177eea12191&amp;v=4" width="119" alt="Titoine"/><br />Titoine</a></td>
167
+ <td align="center"><a href="https://rigtch.fm/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
168
+ <td align="center"><a href="https://blog.cwang.io/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="hanayashiki"><img src="https://avatars.githubusercontent.com/u/26056783?u=06c3b9205a16fd41a871e82da1cc2a09306d53f5&amp;v=4" width="119" alt="hanayashiki"/><br />hanayashiki</a></td>
169
+ <td align="center"><a href="https://dubinets.io/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
134
170
  </tr>
135
171
  <tr>
136
- <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>
137
- <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=29e91400dbd4a9c217048a8f59562c4f740498e6&amp;v=4" width="119" alt="Andrey Gubanov"/><br />Andrey Gubanov</a></td>
172
+ <td align="center"><a href="https://kellychan.im/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
173
+ <td align="center"><a href="https://guyariely.com/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Guy Ariely"><img src="https://avatars.githubusercontent.com/u/42813496?u=edb6b7f563bf28e160a290832e7da57c0506f8ca&amp;v=4" width="119" alt="Guy Ariely"/><br />Guy Ariely</a></td>
174
+ <td align="center"><a href="https://paulsenon.com/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="PaulSenon"><img src="https://avatars.githubusercontent.com/u/19531087?u=6385741eb91d200b8c513ec6045482e301767ca6&amp;v=4" width="119" alt="PaulSenon"/><br />PaulSenon</a></td>
175
+ <td align="center"><a href="https://nakasyou.how/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Shotaro Nakamura"><img src="https://avatars.githubusercontent.com/u/79000684?u=f644df3f29f0e8677a90967115774564f1d9d6ab&amp;v=4" width="119" alt="Shotaro Nakamura"/><br />Shotaro Nakamura</a></td>
176
+ <td align="center"><a href="https://piscis.dev/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Alex"><img src="https://avatars.githubusercontent.com/u/326163?u=b245f368bd940cf51d08c0b6bf55f8257f359437&amp;v=4" width="119" alt="Alex"/><br />Alex</a></td>
177
+ <td align="center"><a href="https://opensource.gubanov.eu/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
138
178
  </tr>
139
179
  </table>
140
180
 
141
- ### Past Sponsors
142
-
143
- <p>
144
- <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>
145
- <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>
146
- <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>
147
- <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>
148
- <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>
149
- <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>
150
- <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>
151
- <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>
152
- <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>
153
- <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>
154
- <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>
155
- <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>
156
- <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>
157
- <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>
158
- <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>
159
- <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>
160
- <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>
161
- <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>
162
- <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>
163
- <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>
164
- <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>
165
- <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>
166
- <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>
167
- <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>
168
- <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>
169
- <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>
170
- <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>
171
- <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>
172
- <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>
173
- <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>
174
- <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>
175
- <a href="https://github.com/nattstack?ref=orpc" target="_blank" rel="noopener" title="nattstack"><img src="https://avatars.githubusercontent.com/u/31426677?u=fa9dbb8b3e66eb0ea3c88db5dc07f31c8c5418fe&amp;v=4" width="32" height="32" alt="nattstack" /></a>
176
- <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>
177
- <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>
178
- </p>
181
+ With thanks to [38 past sponsors](https://orpc.dev/sponsors#past-sponsors) who helped get oRPC here.
179
182
 
180
183
  ## References
181
184
 
@@ -186,4 +189,4 @@ oRPC is inspired by existing solutions that prioritize type safety and developer
186
189
 
187
190
  ## License
188
191
 
189
- Distributed under the MIT License. See [LICENSE](https://github.com/middleapi/orpc-nest/blob/main/LICENCE) for more information.
192
+ Distributed under the MIT License. See [LICENSE](https://github.com/middleapi/orpc/blob/main/LICENSE) for more information.
package/dist/index.d.mts CHANGED
@@ -1,27 +1,39 @@
1
- import { DynamicModule, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
1
+ import { ExecutionContext, DynamicModule, NestInterceptor, CallHandler } from '@nestjs/common';
2
2
  import { RouterContract } from '@orpc/contract';
3
3
  import { DefaultInitialContext, ContractedRouter } from '@orpc/server';
4
- import { Promisable } from '@orpc/shared';
4
+ import { Value, Promisable } from '@orpc/shared';
5
5
  import { Observable } from 'rxjs';
6
6
  import { OpenAPIHandlerCodecCoreOptions } from '@orpc/openapi/standard';
7
7
  import { StandardHandlerOptions } from '@orpc/server/standard';
8
- import { StandardLazyRequest } from '@standardserver/core';
9
- import { ToEventStreamOptions } from '@standardserver/node';
8
+ import { StandardLazyRequest } from '@standard-server/core';
9
+ import { ToEventStreamOptions } from '@standard-server/node';
10
10
  import { HttpAdapterHost } from '@nestjs/core';
11
11
 
12
12
  declare const ORPC_MODULE_CONFIG_SYMBOL: unique symbol;
13
+ /**
14
+ * A standard lazy request extended with NestJS route parameters,
15
+ * used as the request representation inside the `@orpc/nest` integration.
16
+ *
17
+ * @see {@link https://orpc.dev/docs/integrations/nest#toneststandardlazyrequest-option | Implement oRPC contract with NestJS - toNestStandardLazyRequest option}
18
+ */
19
+ interface NestStandardLazyRequest extends StandardLazyRequest {
20
+ /**
21
+ * Route parameters extracted from the request path.
22
+ */
23
+ params?: undefined | Record<string, string | string[]>;
24
+ }
13
25
  type ORPCModuleConfig = OpenAPIHandlerCodecCoreOptions<DefaultInitialContext> & StandardHandlerOptions<DefaultInitialContext> & (object extends DefaultInitialContext ? {
14
- context?: DefaultInitialContext;
26
+ context?: Value<Promisable<DefaultInitialContext>, [ctx: ExecutionContext]>;
15
27
  } : {
16
- context: DefaultInitialContext;
28
+ context: Value<Promisable<DefaultInitialContext>, [ctx: ExecutionContext]>;
17
29
  }) & {
18
30
  /**
19
- * Customize how convert next.js req and res to StandardLazyRequest,
20
- * You might need define this if you not using express or fastify adapters
31
+ * Customize how to convert NestJS `req` and `res` to {@link NestStandardLazyRequest}.
32
+ * You might need to define this if you are not using express or fastify adapters.
21
33
  */
22
- toStandardLazyRequest?: undefined | ((req: any, res: any) => StandardLazyRequest);
34
+ toNestStandardLazyRequest?: undefined | ((req: any, res: any) => NestStandardLazyRequest);
23
35
  /**
24
- * Options for how to convert the Standard Response to a Nest Response (returning value), like event iterator options, etc.
36
+ * Options for how to convert the Standard Response to a Nest Response (returning value), like event stream options, etc.
25
37
  */
26
38
  toNestResponse?: undefined | {
27
39
  /**
@@ -30,6 +42,13 @@ type ORPCModuleConfig = OpenAPIHandlerCodecCoreOptions<DefaultInitialContext> &
30
42
  eventStream?: undefined | ToEventStreamOptions;
31
43
  };
32
44
  };
45
+ /**
46
+ * NestJS module that configures the `@orpc/nest` integration via `forRoot`
47
+ * or `forRootAsync`, providing options such as initial context, plugins,
48
+ * and interceptors to `@Implement` handlers.
49
+ *
50
+ * @see {@link https://orpc.dev/docs/integrations/nest#configuration | Implement oRPC contract with NestJS - Configuration}
51
+ */
33
52
  declare class ORPCModule {
34
53
  static forRoot(config: ORPCModuleConfig): DynamicModule;
35
54
  static forRootAsync(options: {
@@ -39,15 +58,27 @@ declare class ORPCModule {
39
58
  }): DynamicModule;
40
59
  }
41
60
 
61
+ /**
62
+ * Decorator that implements an oRPC contract (procedure or router contract)
63
+ * on a NestJS controller method. It registers the corresponding NestJS routes
64
+ * and handles request decoding and response encoding for you.
65
+ *
66
+ * @remarks
67
+ * **Note**: Every procedure contract must define an `openapi.path` meta;
68
+ * use `populateRouterContractOpenAPIPaths` from `@orpc/openapi` to fill in missing paths.
69
+ * **Note**: The HTTP `QUERY` method requires NestJS v11.2+ (`QueryMethod`). Older NestJS versions throw; use `GET` instead.
70
+ *
71
+ * @see {@link https://orpc.dev/docs/integrations/nest#implement-your-contract | Implement oRPC contract with NestJS - Implement Your Contract}
72
+ */
42
73
  declare function Implement<T extends RouterContract>(contract: T): <U extends Promisable<ContractedRouter<T, DefaultInitialContext>>>(target: Record<PropertyKey, any>, propertyKey: string, descriptor: TypedPropertyDescriptor<(...args: any[]) => U>) => void;
43
74
  declare class ImplementInterceptor implements NestInterceptor {
44
75
  private readonly config;
45
76
  private readonly codec;
46
- private readonly toStandardLazyRequest;
77
+ private readonly toNestStandardLazyRequest;
47
78
  private readonly httpAdapterHost;
48
79
  constructor(config: ORPCModuleConfig | undefined, httpAdapterHost: HttpAdapterHost);
49
80
  intercept(ctx: ExecutionContext, next: CallHandler<any>): Observable<any>;
50
81
  }
51
82
 
52
83
  export { Implement as Impl, Implement, ImplementInterceptor, ORPCModule, ORPC_MODULE_CONFIG_SYMBOL };
53
- export type { ORPCModuleConfig };
84
+ export type { NestStandardLazyRequest, ORPCModuleConfig };
package/dist/index.d.ts CHANGED
@@ -1,27 +1,39 @@
1
- import { DynamicModule, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
1
+ import { ExecutionContext, DynamicModule, NestInterceptor, CallHandler } from '@nestjs/common';
2
2
  import { RouterContract } from '@orpc/contract';
3
3
  import { DefaultInitialContext, ContractedRouter } from '@orpc/server';
4
- import { Promisable } from '@orpc/shared';
4
+ import { Value, Promisable } from '@orpc/shared';
5
5
  import { Observable } from 'rxjs';
6
6
  import { OpenAPIHandlerCodecCoreOptions } from '@orpc/openapi/standard';
7
7
  import { StandardHandlerOptions } from '@orpc/server/standard';
8
- import { StandardLazyRequest } from '@standardserver/core';
9
- import { ToEventStreamOptions } from '@standardserver/node';
8
+ import { StandardLazyRequest } from '@standard-server/core';
9
+ import { ToEventStreamOptions } from '@standard-server/node';
10
10
  import { HttpAdapterHost } from '@nestjs/core';
11
11
 
12
12
  declare const ORPC_MODULE_CONFIG_SYMBOL: unique symbol;
13
+ /**
14
+ * A standard lazy request extended with NestJS route parameters,
15
+ * used as the request representation inside the `@orpc/nest` integration.
16
+ *
17
+ * @see {@link https://orpc.dev/docs/integrations/nest#toneststandardlazyrequest-option | Implement oRPC contract with NestJS - toNestStandardLazyRequest option}
18
+ */
19
+ interface NestStandardLazyRequest extends StandardLazyRequest {
20
+ /**
21
+ * Route parameters extracted from the request path.
22
+ */
23
+ params?: undefined | Record<string, string | string[]>;
24
+ }
13
25
  type ORPCModuleConfig = OpenAPIHandlerCodecCoreOptions<DefaultInitialContext> & StandardHandlerOptions<DefaultInitialContext> & (object extends DefaultInitialContext ? {
14
- context?: DefaultInitialContext;
26
+ context?: Value<Promisable<DefaultInitialContext>, [ctx: ExecutionContext]>;
15
27
  } : {
16
- context: DefaultInitialContext;
28
+ context: Value<Promisable<DefaultInitialContext>, [ctx: ExecutionContext]>;
17
29
  }) & {
18
30
  /**
19
- * Customize how convert next.js req and res to StandardLazyRequest,
20
- * You might need define this if you not using express or fastify adapters
31
+ * Customize how to convert NestJS `req` and `res` to {@link NestStandardLazyRequest}.
32
+ * You might need to define this if you are not using express or fastify adapters.
21
33
  */
22
- toStandardLazyRequest?: undefined | ((req: any, res: any) => StandardLazyRequest);
34
+ toNestStandardLazyRequest?: undefined | ((req: any, res: any) => NestStandardLazyRequest);
23
35
  /**
24
- * Options for how to convert the Standard Response to a Nest Response (returning value), like event iterator options, etc.
36
+ * Options for how to convert the Standard Response to a Nest Response (returning value), like event stream options, etc.
25
37
  */
26
38
  toNestResponse?: undefined | {
27
39
  /**
@@ -30,6 +42,13 @@ type ORPCModuleConfig = OpenAPIHandlerCodecCoreOptions<DefaultInitialContext> &
30
42
  eventStream?: undefined | ToEventStreamOptions;
31
43
  };
32
44
  };
45
+ /**
46
+ * NestJS module that configures the `@orpc/nest` integration via `forRoot`
47
+ * or `forRootAsync`, providing options such as initial context, plugins,
48
+ * and interceptors to `@Implement` handlers.
49
+ *
50
+ * @see {@link https://orpc.dev/docs/integrations/nest#configuration | Implement oRPC contract with NestJS - Configuration}
51
+ */
33
52
  declare class ORPCModule {
34
53
  static forRoot(config: ORPCModuleConfig): DynamicModule;
35
54
  static forRootAsync(options: {
@@ -39,15 +58,27 @@ declare class ORPCModule {
39
58
  }): DynamicModule;
40
59
  }
41
60
 
61
+ /**
62
+ * Decorator that implements an oRPC contract (procedure or router contract)
63
+ * on a NestJS controller method. It registers the corresponding NestJS routes
64
+ * and handles request decoding and response encoding for you.
65
+ *
66
+ * @remarks
67
+ * **Note**: Every procedure contract must define an `openapi.path` meta;
68
+ * use `populateRouterContractOpenAPIPaths` from `@orpc/openapi` to fill in missing paths.
69
+ * **Note**: The HTTP `QUERY` method requires NestJS v11.2+ (`QueryMethod`). Older NestJS versions throw; use `GET` instead.
70
+ *
71
+ * @see {@link https://orpc.dev/docs/integrations/nest#implement-your-contract | Implement oRPC contract with NestJS - Implement Your Contract}
72
+ */
42
73
  declare function Implement<T extends RouterContract>(contract: T): <U extends Promisable<ContractedRouter<T, DefaultInitialContext>>>(target: Record<PropertyKey, any>, propertyKey: string, descriptor: TypedPropertyDescriptor<(...args: any[]) => U>) => void;
43
74
  declare class ImplementInterceptor implements NestInterceptor {
44
75
  private readonly config;
45
76
  private readonly codec;
46
- private readonly toStandardLazyRequest;
77
+ private readonly toNestStandardLazyRequest;
47
78
  private readonly httpAdapterHost;
48
79
  constructor(config: ORPCModuleConfig | undefined, httpAdapterHost: HttpAdapterHost);
49
80
  intercept(ctx: ExecutionContext, next: CallHandler<any>): Observable<any>;
50
81
  }
51
82
 
52
83
  export { Implement as Impl, Implement, ImplementInterceptor, ORPCModule, ORPC_MODULE_CONFIG_SYMBOL };
53
- export type { ORPCModuleConfig };
84
+ export type { NestStandardLazyRequest, ORPCModuleConfig };
package/dist/index.mjs CHANGED
@@ -1,14 +1,15 @@
1
1
  import { Readable } from 'node:stream';
2
- import { Module, applyDecorators, Options, Delete, Patch, Put, Post, Get, Head, HttpCode, UseInterceptors, StreamableFile, HttpException, Injectable, Inject, Optional } from '@nestjs/common';
2
+ import * as NestCommon from '@nestjs/common';
3
+ import { Module, applyDecorators, UseInterceptors, HttpException, HttpCode, Options, Delete, Patch, Put, Post, Get, Head, StreamableFile, Injectable, Inject, Optional } from '@nestjs/common';
3
4
  import { HttpAdapterHost } from '@nestjs/core';
4
5
  import { ProcedureContract, getPathMeta } from '@orpc/contract';
5
6
  import { getOpenAPIMeta, DEFAULT_OPENAPI_METHOD, getDynamicPathParams } from '@orpc/openapi';
6
7
  import { OpenAPIHandlerCodecCore } from '@orpc/openapi/standard';
7
- import { DEFAULT_SUCCESS_STATUS, getRouter, unlazy, Procedure } from '@orpc/server';
8
+ import { unlazy, Procedure, DEFAULT_SUCCESS_STATUS, getRouter } from '@orpc/server';
8
9
  import { StandardHandler } from '@orpc/server/standard';
9
- import { mergeHttpPath, get, isAsyncIteratorObject, stringifyJSON } from '@orpc/shared';
10
- import { flattenStandardHeader, generateContentDisposition } from '@standardserver/core';
11
- import { toStandardLazyRequest, toEventStream } from '@standardserver/node';
10
+ import { value, isAsyncIteratorObject, stringifyJSON, mergeHttpPath, NullProtoObj } from '@orpc/shared';
11
+ import { flattenStandardHeader, generateContentDisposition } from '@standard-server/core';
12
+ import { toStandardLazyRequest, toEventStream } from '@standard-server/node';
12
13
  import { mergeMap } from 'rxjs';
13
14
 
14
15
  var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
@@ -65,6 +66,7 @@ var __decorateClass = (decorators, target, key, kind) => {
65
66
  return result;
66
67
  };
67
68
  var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
69
+ const QueryMethod = NestCommon.QueryMethod;
68
70
  const MethodDecoratorMap = {
69
71
  HEAD: Head,
70
72
  GET: Get,
@@ -76,56 +78,88 @@ const MethodDecoratorMap = {
76
78
  };
77
79
  function Implement(contract) {
78
80
  if (contract instanceof ProcedureContract) {
79
- const meta = getOpenAPIMeta(contract);
80
- if (meta?.path === void 0) {
81
- throw new TypeError(`
82
- @Implement decorator requires contract to have a 'openapi.path' meta.
83
- Please define one using '.meta(openapi({ path: '/example' }))'.
84
- Or use "populateRouterContractOpenAPIPaths" from "@orpc/openapi" utility to automatically fill in any missing paths.
85
- `);
86
- }
87
- const method = meta.method ?? DEFAULT_OPENAPI_METHOD;
88
- const path = toNestPattern(meta.prefix ? mergeHttpPath(meta.prefix, meta.path) : meta.path);
89
- const successStatus = meta.successStatus ?? DEFAULT_SUCCESS_STATUS;
90
81
  return (target, propertyKey, descriptor) => {
91
82
  applyDecorators(
92
- MethodDecoratorMap[method](path),
93
- HttpCode(successStatus),
83
+ toNestRouteDecorator(contract),
94
84
  UseInterceptors(ImplementInterceptor)
95
85
  )(target, propertyKey, descriptor);
96
86
  };
97
87
  }
98
88
  return (target, propertyKey, descriptor) => {
99
- for (const key in contract) {
100
- let methodName = `${propertyKey}_${key}`;
101
- let i = 0;
102
- while (methodName in target) {
103
- methodName = `${propertyKey}_${key}_${i++}`;
104
- }
105
- target[methodName] = async function(...args) {
106
- const router = await descriptor.value.apply(this, args);
107
- return getRouter(router, [key]);
108
- };
89
+ UseInterceptors(ImplementInterceptor)(target, propertyKey, descriptor);
90
+ implementRouterContract(contract, target, propertyKey, descriptor);
91
+ };
92
+ }
93
+ function toNestRouteDecorator(contract) {
94
+ const meta = getOpenAPIMeta(contract);
95
+ if (meta?.path === void 0) {
96
+ throw new TypeError(`
97
+ @Implement decorator requires contract to have a 'openapi.path' meta.
98
+ Please define one using '.meta(openapi({ path: '/example' }))'.
99
+ Or use "populateRouterContractOpenAPIPaths" from "@orpc/openapi" utility to automatically fill in any missing paths.
100
+ `);
101
+ }
102
+ const method = meta.method ?? DEFAULT_OPENAPI_METHOD;
103
+ const path = toNestPattern(meta.prefix ? mergeHttpPath(meta.prefix, meta.path) : meta.path);
104
+ const successStatus = meta.successStatus ?? DEFAULT_SUCCESS_STATUS;
105
+ if (method === "QUERY") {
106
+ if (!QueryMethod) {
107
+ throw new TypeError(`
108
+ @Implement decorator does not support the 'QUERY' HTTP method because the installed version of NestJS does not support it.
109
+ The 'QUERY' HTTP method requires NestJS v11.2 or later. Alternatively, use 'GET' method.
110
+ `);
111
+ }
112
+ return applyDecorators(
113
+ QueryMethod(path),
114
+ HttpCode(successStatus)
115
+ );
116
+ }
117
+ return applyDecorators(
118
+ MethodDecoratorMap[method](path),
119
+ HttpCode(successStatus)
120
+ );
121
+ }
122
+ function implementRouterContract(contract, target, propertyKey, descriptor) {
123
+ for (const [key, childContract] of Object.entries(contract)) {
124
+ let methodName = `${propertyKey}_${key}`;
125
+ let i = 0;
126
+ while (methodName in target) {
127
+ methodName = `${propertyKey}_${key}_${i++}`;
128
+ }
129
+ target[methodName] = async function(...args) {
130
+ const router = await descriptor.value.apply(this, args);
131
+ return getRouter(router, [key]);
132
+ };
133
+ Object.setPrototypeOf(target[methodName], descriptor.value);
134
+ queueMicrotask(() => {
109
135
  for (const p of Reflect.getOwnMetadataKeys(target, propertyKey)) {
110
136
  Reflect.defineMetadata(p, Reflect.getOwnMetadata(p, target, propertyKey), target, methodName);
111
137
  }
112
138
  for (const p of Reflect.getOwnMetadataKeys(target.constructor, propertyKey)) {
113
139
  Reflect.defineMetadata(p, Reflect.getOwnMetadata(p, target.constructor, propertyKey), target.constructor, methodName);
114
140
  }
115
- Implement(get(contract, [key]))(target, methodName, Object.getOwnPropertyDescriptor(target, methodName));
141
+ });
142
+ const childDescriptor = Object.getOwnPropertyDescriptor(target, methodName);
143
+ if (childContract instanceof ProcedureContract) {
144
+ const routeDecorator = toNestRouteDecorator(childContract);
145
+ queueMicrotask(() => {
146
+ routeDecorator(target, methodName, childDescriptor);
147
+ });
148
+ } else {
149
+ implementRouterContract(childContract, target, methodName, childDescriptor);
116
150
  }
117
- };
151
+ }
118
152
  }
119
153
  let ImplementInterceptor = class {
120
154
  config;
121
155
  codec;
122
- toStandardLazyRequest;
156
+ toNestStandardLazyRequest;
123
157
  httpAdapterHost;
124
158
  constructor(config, httpAdapterHost) {
125
159
  this.config = config ?? {};
126
160
  this.httpAdapterHost = httpAdapterHost;
127
161
  this.codec = new OpenAPIHandlerCodecCore(this.config);
128
- this.toStandardLazyRequest = this.config.toStandardLazyRequest ?? ((req, res) => {
162
+ this.toNestStandardLazyRequest = this.config.toNestStandardLazyRequest ?? ((req, res) => {
129
163
  const standardRequest = toStandardLazyRequest(
130
164
  "raw" in req ? req.raw : req,
131
165
  "raw" in res ? res.raw : res
@@ -133,6 +167,7 @@ let ImplementInterceptor = class {
133
167
  if (req.body !== void 0) {
134
168
  standardRequest.resolveBody = () => Promise.resolve(req.body);
135
169
  }
170
+ standardRequest.params = req.params;
136
171
  return standardRequest;
137
172
  });
138
173
  }
@@ -147,21 +182,21 @@ let ImplementInterceptor = class {
147
182
  }
148
183
  const req = ctx.switchToHttp().getRequest();
149
184
  const res = ctx.switchToHttp().getResponse();
150
- const standardRequest = this.toStandardLazyRequest(req, res);
185
+ const standardRequest = this.toNestStandardLazyRequest(req, res);
151
186
  const handler = new StandardHandler({
152
- resolveProcedure: () => Promise.resolve({
187
+ resolveProcedure: (request) => Promise.resolve({
153
188
  path: getPathMeta(procedure) ?? [],
154
189
  procedure,
155
190
  decodeInput: () => this.codec.decodeInput({
156
191
  procedure,
157
- params: toORPCOpenAPIParams(procedure, req.params)
158
- }, standardRequest)
192
+ params: toORPCOpenAPIParams(procedure, standardRequest.params)
193
+ }, request)
159
194
  }),
160
195
  encodeError: this.codec.encodeError.bind(this.codec),
161
196
  encodeOutput: this.codec.encodeOutput.bind(this.codec)
162
197
  }, this.config);
163
198
  const result = await handler.handle(standardRequest, {
164
- context: this.config.context ?? {}
199
+ context: await value(this.config.context ?? {}, ctx)
165
200
  });
166
201
  if (!result.matched) {
167
202
  throw new TypeError(
@@ -170,16 +205,16 @@ let ImplementInterceptor = class {
170
205
  }
171
206
  const httpAdapter = this.httpAdapterHost.httpAdapter;
172
207
  httpAdapter.status(res, result.response.status);
173
- for (const key in result.response.headers) {
174
- const value = result.response.headers[key];
175
- if (typeof value === "string") {
176
- httpAdapter.setHeader(res, key, value);
208
+ for (const key of Object.keys(result.response.headers)) {
209
+ const value2 = result.response.headers[key];
210
+ if (typeof value2 === "string") {
211
+ httpAdapter.setHeader(res, key, value2);
177
212
  } else {
178
- value?.forEach((value2, index) => {
213
+ value2?.forEach((value3, index) => {
179
214
  if (index === 0) {
180
- httpAdapter.setHeader(res, key, value2);
215
+ httpAdapter.setHeader(res, key, value3);
181
216
  } else {
182
- httpAdapter.appendHeader(res, key, value2);
217
+ httpAdapter.appendHeader(res, key, value3);
183
218
  }
184
219
  });
185
220
  }
@@ -187,27 +222,27 @@ let ImplementInterceptor = class {
187
222
  const body = result.response.body;
188
223
  if (body instanceof ReadableStream) {
189
224
  httpAdapter.setHeader(res, "standard-server", "octet-stream");
190
- return new StreamableFile(Readable.fromWeb(body), {
225
+ return toStreamableFile(Readable.fromWeb(body), standardRequest.signal, {
191
226
  type: flattenStandardHeader(result.response.headers["content-type"]) ?? "application/octet-stream"
192
227
  });
193
228
  }
194
229
  if (isAsyncIteratorObject(body)) {
195
- return new StreamableFile(toEventStream(body, this.config.toNestResponse?.eventStream), {
230
+ return toStreamableFile(toEventStream(body, this.config.toNestResponse?.eventStream), standardRequest.signal, {
196
231
  type: "text/event-stream"
197
232
  });
198
233
  }
199
234
  if (body instanceof Blob) {
200
235
  httpAdapter.setHeader(res, "standard-server", "file");
201
- return new StreamableFile(Readable.fromWeb(body.stream()), {
236
+ return toStreamableFile(Readable.fromWeb(body.stream()), standardRequest.signal, {
202
237
  type: body.type,
203
238
  disposition: flattenStandardHeader(result.response.headers["content-disposition"]) ?? generateContentDisposition(body instanceof File ? body.name : "blob"),
204
239
  // BunS3 can use NaN for the size
205
- length: Number.isNaN(body.size) ? void 0 : body.size
240
+ length: Number.isFinite(body.size) ? body.size : void 0
206
241
  });
207
242
  }
208
243
  if (body instanceof FormData) {
209
244
  const response = new Response(body);
210
- return new StreamableFile(Readable.fromWeb(response.body), {
245
+ return toStreamableFile(Readable.fromWeb(response.body), standardRequest.signal, {
211
246
  type: response.headers.get("content-type")
212
247
  });
213
248
  }
@@ -233,26 +268,39 @@ ImplementInterceptor = __decorateClass([
233
268
  __decorateParam(0, Optional()),
234
269
  __decorateParam(1, Inject(HttpAdapterHost))
235
270
  ], ImplementInterceptor);
236
- function flattenParamValue(value) {
237
- return Array.isArray(value) ? value.join("/") : value;
271
+ function toStreamableFile(stream, signal, options) {
272
+ if (signal?.aborted) {
273
+ stream.destroy();
274
+ } else {
275
+ signal?.addEventListener("abort", () => stream.destroy(), { once: true });
276
+ }
277
+ return new StreamableFile(stream, options);
278
+ }
279
+ function flattenParamValue(value2) {
280
+ return Array.isArray(value2) ? value2.join("/") : value2;
238
281
  }
239
282
  function toORPCOpenAPIParams(contract, params) {
240
283
  const meta = getOpenAPIMeta(contract);
241
- if (!params || meta?.path === void 0) {
242
- return void 0;
243
- }
244
- const dynamicParams = getDynamicPathParams(meta.prefix ? mergeHttpPath(meta.prefix, meta.path) : meta.path);
245
- if (!dynamicParams) {
284
+ if (!params || meta?.path === void 0 || Object.keys(params).length === 0) {
246
285
  return void 0;
247
286
  }
248
- return dynamicParams.reduce((acc, config) => {
249
- const value = config.allowsSlash ? flattenParamValue(params?.["*"] ?? params?.path) : flattenParamValue(params?.[config.parameterName]);
250
- if (value === void 0) {
251
- return acc;
287
+ const orpcParams = new NullProtoObj();
288
+ const restKey = Object.hasOwn(params, "*") ? "*" : "path";
289
+ for (const [key, value2] of Object.entries(params)) {
290
+ if (key === restKey) {
291
+ const restParams = getDynamicPathParams(
292
+ meta.prefix ? mergeHttpPath(meta.prefix, meta.path) : meta.path
293
+ )?.filter((c) => c.allowsSlash);
294
+ if (restParams?.length) {
295
+ for (const c of restParams) {
296
+ orpcParams[c.parameterName] = flattenParamValue(value2);
297
+ }
298
+ continue;
299
+ }
252
300
  }
253
- acc[config.parameterName] = value;
254
- return acc;
255
- }, {});
301
+ orpcParams[key] = flattenParamValue(value2);
302
+ }
303
+ return orpcParams;
256
304
  }
257
305
  function toNestPattern(path) {
258
306
  const params = getDynamicPathParams(path);
package/package.json CHANGED
@@ -1,14 +1,29 @@
1
1
  {
2
2
  "name": "@orpc/nest",
3
3
  "type": "module",
4
- "version": "2.0.0-beta.4",
4
+ "version": "2.0.0-beta.41",
5
+ "description": "NestJS integration for oRPC: implement typesafe contracts in NestJS controllers",
5
6
  "license": "MIT",
7
+ "funding": [
8
+ "https://github.com/sponsors/dinwwwh",
9
+ "https://opencollective.com/middleapi"
10
+ ],
6
11
  "homepage": "https://orpc.dev",
7
12
  "repository": {
8
13
  "type": "git",
9
- "url": "git+https://github.com/middleapi/orpc-nest.git",
14
+ "url": "git+https://github.com/middleapi/orpc.git",
10
15
  "directory": "packages/nest"
11
16
  },
17
+ "keywords": [
18
+ "orpc",
19
+ "nestjs",
20
+ "nest",
21
+ "contract-first",
22
+ "rpc",
23
+ "openapi",
24
+ "typescript",
25
+ "typesafe"
26
+ ],
12
27
  "sideEffects": false,
13
28
  "exports": {
14
29
  "./package.json": "./package.json",
@@ -37,26 +52,27 @@
37
52
  }
38
53
  },
39
54
  "dependencies": {
40
- "@orpc/client": "^2.0.0-beta.3",
41
- "@orpc/contract": "^2.0.0-beta.3",
42
- "@orpc/openapi": "^2.0.0-beta.3",
43
- "@orpc/server": "^2.0.0-beta.3",
44
- "@orpc/shared": "^2.0.0-beta.3",
45
- "@standardserver/core": "^0.0.25",
46
- "@standardserver/node": "^0.0.25"
55
+ "@orpc/client": "2.0.0-beta.41",
56
+ "@orpc/contract": "2.0.0-beta.41",
57
+ "@orpc/openapi": "2.0.0-beta.41",
58
+ "@orpc/server": "2.0.0-beta.41",
59
+ "@orpc/shared": "2.0.0-beta.41",
60
+ "@standard-server/core": "~0.10.0",
61
+ "@standard-server/node": "~0.10.0"
47
62
  },
48
63
  "devDependencies": {
49
64
  "@fastify/cookie": "^11.0.2",
50
- "@nestjs/common": "^11.1.27",
51
- "@nestjs/core": "^11.1.27",
52
- "@nestjs/platform-fastify": "^11.1.27",
65
+ "@nestjs/common": "^12.0.1",
66
+ "@nestjs/core": "^12.0.1",
67
+ "@nestjs/platform-express": "^12.0.1",
68
+ "@nestjs/platform-fastify": "^12.0.1",
69
+ "@nestjs/testing": "^12.0.1",
70
+ "@types/express": "^5.0.6",
53
71
  "express": "^5.2.1",
54
- "fastify": "^5.8.5",
55
- "rxjs": "^7.8.2",
56
- "supertest": "^7.2.2"
72
+ "fastify": "^5.12.1",
73
+ "rxjs": "^7.8.2"
57
74
  },
58
75
  "scripts": {
59
- "build": "unbuild",
60
76
  "type:check": "tsc -b"
61
77
  }
62
78
  }