@orpc/bun 0.0.0 → 1.14.11
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 → LICENSE} +1 -1
- package/README.md +19 -13
- package/dist/index.d.mts +78 -3
- package/dist/index.d.ts +78 -3
- package/dist/index.mjs +123 -2
- package/package.json +12 -7
package/{LICENCE → LICENSE}
RENAMED
|
@@ -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,14 @@
|
|
|
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
|
|
5
|
-
<img alt="codecov" src="https://codecov.io/gh/middleapi/orpc
|
|
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/bun">
|
|
8
8
|
<img alt="weekly downloads" src="https://img.shields.io/npm/dw/%40orpc%2Fbun?logo=npm" />
|
|
9
9
|
</a>
|
|
10
|
-
<a href="https://github.com/middleapi/orpc
|
|
11
|
-
<img alt="MIT License" src="https://img.shields.io/github/license/middleapi/orpc
|
|
10
|
+
<a href="https://github.com/middleapi/orpc/blob/main/LICENCE">
|
|
11
|
+
<img alt="MIT License" src="https://img.shields.io/github/license/middleapi/orpc?logo=open-source-initiative" />
|
|
12
12
|
</a>
|
|
13
13
|
<a href="https://discord.gg/TXEbwRBvQn">
|
|
14
14
|
<img alt="Discord" src="https://img.shields.io/discord/1308966753044398161?color=7389D8&label&logo=discord&logoColor=ffffff" />
|
|
@@ -46,10 +46,15 @@ You can read the documentation [here](https://orpc.dev).
|
|
|
46
46
|
**Framework & ecosystem integrations**
|
|
47
47
|
|
|
48
48
|
- [@orpc/next](https://www.npmjs.com/package/@orpc/next): Integrate with [Next.js Server Functions](https://nextjs.org/docs/app/getting-started/mutating-data).
|
|
49
|
+
- [@orpc/ai-sdk](https://www.npmjs.com/package/@orpc/ai-sdk): Turn contracts and procedures into [AI SDK](https://ai-sdk.dev/) tools.
|
|
49
50
|
- [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query): Integrate with [TanStack Query](https://tanstack.com/query/latest).
|
|
51
|
+
- [@orpc/pinia-colada](https://www.npmjs.com/package/@orpc/pinia-colada): Integrate with [Pinia Colada](https://pinia-colada.esm.dev/).
|
|
52
|
+
- [@orpc/swr](https://www.npmjs.com/package/@orpc/swr): Integrate with [SWR](https://swr.vercel.app/).
|
|
50
53
|
- [@orpc/experimental-effect](https://www.npmjs.com/package/@orpc/experimental-effect): Integrate with [Effect](https://effect.website/).
|
|
51
54
|
- [@orpc/nest](https://www.npmjs.com/package/@orpc/nest): Implement your contract with [NestJS](https://nestjs.com/).
|
|
52
55
|
- [@orpc/bun](https://www.npmjs.com/package/@orpc/bun): Adapters for [Bun's Redis](https://bun.sh/).
|
|
56
|
+
- [@orpc/cloudflare](https://www.npmjs.com/package/@orpc/cloudflare): Adapters for [Cloudflare's RateLimit and Durable Objects](https://developers.cloudflare.com/workers/).
|
|
57
|
+
- [@orpc/trpc](https://www.npmjs.com/package/@orpc/trpc): Reuse existing [tRPC](https://trpc.io/) routers within oRPC.
|
|
53
58
|
|
|
54
59
|
**Observability**
|
|
55
60
|
|
|
@@ -101,13 +106,10 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
|
|
|
101
106
|
<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&v=4" width="139" alt="Valerii Petryniak"/><br />Valerii Petryniak</a></td>
|
|
102
107
|
<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&v=4" width="139" alt="Valerii Strilets"/><br />Valerii Strilets</a></td>
|
|
103
108
|
<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&v=4" width="139" alt="Kyle Mistele"/><br />Kyle Mistele</a></td>
|
|
104
|
-
<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>
|
|
105
|
-
<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&v=4" width="139" alt="Ryan Vogel"/><br />Ryan Vogel</a></td>
|
|
106
|
-
</tr>
|
|
107
|
-
<tr>
|
|
108
109
|
<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>
|
|
109
|
-
<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&v=4" width="139" alt="Peter Adam"/><br />Peter Adam</a></td>
|
|
110
110
|
<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&v=4" width="139" alt="Ryan Soderberg"/><br />Ryan Soderberg</a></td>
|
|
111
|
+
</tr>
|
|
112
|
+
<tr>
|
|
111
113
|
<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&v=4" width="139" alt="shota"/><br />shota</a></td>
|
|
112
114
|
</tr>
|
|
113
115
|
</table>
|
|
@@ -117,25 +119,25 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
|
|
|
117
119
|
<table>
|
|
118
120
|
<tr>
|
|
119
121
|
<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&v=4" width="119" alt="David Walsh"/><br />David Walsh</a></td>
|
|
122
|
+
<td align="center"><a href="https://github.com/Nic13Gamer?ref=orpc" target="_blank" rel="noopener" title="Nicholas"><img src="https://avatars.githubusercontent.com/u/54724556?u=56a7ab430ce7a80d648ab6eba051d454a818ed0b&v=4" width="119" alt="Nicholas"/><br />Nicholas</a></td>
|
|
120
123
|
<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&v=4" width="119" alt="Robbe Vaes"/><br />Robbe Vaes</a></td>
|
|
121
124
|
<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>
|
|
122
125
|
<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&v=4" width="119" alt="soonoo"/><br />soonoo</a></td>
|
|
123
126
|
<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&v=4" width="119" alt="Kevin Porten"/><br />Kevin Porten</a></td>
|
|
124
127
|
<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&v=4" width="119" alt="Denis"/><br />Denis</a></td>
|
|
125
|
-
<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&v=4" width="119" alt="Christopher Kapic"/><br />Christopher Kapic</a></td>
|
|
126
128
|
</tr>
|
|
127
129
|
<tr>
|
|
130
|
+
<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&v=4" width="119" alt="Christopher Kapic"/><br />Christopher Kapic</a></td>
|
|
128
131
|
<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&v=4" width="119" alt="Tom Ballinger"/><br />Tom Ballinger</a></td>
|
|
129
132
|
<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&v=4" width="119" alt="Sam"/><br />Sam</a></td>
|
|
130
133
|
<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&v=4" width="119" alt="Titoine"/><br />Titoine</a></td>
|
|
131
134
|
<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&v=4" width="119" alt="Igor Makowski"/><br />Igor Makowski</a></td>
|
|
132
135
|
<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&v=4" width="119" alt="hanayashiki"/><br />hanayashiki</a></td>
|
|
133
136
|
<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&v=4" width="119" alt="Lev Dubinets"/><br />Lev Dubinets</a></td>
|
|
134
|
-
<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&v=4" width="119" alt="Kelly Peilin Chan"/><br />Kelly Peilin Chan</a></td>
|
|
135
137
|
</tr>
|
|
136
138
|
<tr>
|
|
139
|
+
<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&v=4" width="119" alt="Kelly Peilin Chan"/><br />Kelly Peilin Chan</a></td>
|
|
137
140
|
<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&v=4" width="119" alt="Alex"/><br />Alex</a></td>
|
|
138
|
-
<td align="center"><a href="https://github.com/nattstack?ref=orpc" target="_blank" rel="noopener" title="nattstack"><img src="https://avatars.githubusercontent.com/u/31426677?u=fa9dbb8b3e66eb0ea3c88db5dc07f31c8c5418fe&v=4" width="119" alt="nattstack"/><br />nattstack</a></td>
|
|
139
141
|
<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&v=4" width="119" alt="Andrey Gubanov"/><br />Andrey Gubanov</a></td>
|
|
140
142
|
</tr>
|
|
141
143
|
</table>
|
|
@@ -166,7 +168,10 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
|
|
|
166
168
|
<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&v=4" width="32" height="32" alt="Nelson Lai" /></a>
|
|
167
169
|
<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&v=4" width="32" height="32" alt="Lê Cao Nguyên" /></a>
|
|
168
170
|
<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&v=4" width="32" height="32" alt="Robert Soriano" /></a>
|
|
171
|
+
<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>
|
|
172
|
+
<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&v=4" width="32" height="32" alt="Ryan Vogel" /></a>
|
|
169
173
|
<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>
|
|
174
|
+
<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&v=4" width="32" height="32" alt="Peter Adam" /></a>
|
|
170
175
|
<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>
|
|
171
176
|
<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&v=4" width="32" height="32" alt="Novak Antonijevic" /></a>
|
|
172
177
|
<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&v=4" width="32" height="32" alt="Laduni Estu Syalwa" /></a>
|
|
@@ -174,6 +179,7 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
|
|
|
174
179
|
<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&v=4" width="32" height="32" alt="Illarion Koperski" /></a>
|
|
175
180
|
<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&v=4" width="32" height="32" alt="Anees Iqbal" /></a>
|
|
176
181
|
<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&v=4" width="32" height="32" alt="Sefa Eyeoglu" /></a>
|
|
182
|
+
<a href="https://github.com/nattstack?ref=orpc" target="_blank" rel="noopener" title="natt"><img src="https://avatars.githubusercontent.com/u/31426677?u=fa9dbb8b3e66eb0ea3c88db5dc07f31c8c5418fe&v=4" width="32" height="32" alt="natt" /></a>
|
|
177
183
|
<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&v=4" width="32" height="32" alt="Adam Tkaczyk" /></a>
|
|
178
184
|
<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>
|
|
179
185
|
</p>
|
|
@@ -187,4 +193,4 @@ oRPC is inspired by existing solutions that prioritize type safety and developer
|
|
|
187
193
|
|
|
188
194
|
## License
|
|
189
195
|
|
|
190
|
-
Distributed under the MIT License. See [LICENSE](https://github.com/middleapi/orpc
|
|
196
|
+
Distributed under the MIT License. See [LICENSE](https://github.com/middleapi/orpc/blob/main/LICENCE) for more information.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,84 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Publisher, PublisherOptions, PublisherSubscribeListenerOptions } from '@orpc/publisher';
|
|
2
|
+
import { Promisable } from '@orpc/shared';
|
|
2
3
|
import { RedisClient } from 'bun';
|
|
4
|
+
import { RPCSerializer } from '@orpc/client';
|
|
5
|
+
import { RateLimiter, RateLimitOptions, RateLimitResult } from '@orpc/ratelimit';
|
|
6
|
+
|
|
7
|
+
interface BunRedisPublisherOptions extends PublisherOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Redis subscriber instance.
|
|
10
|
+
* Pub/Sub takes over the connection, so a client with subscriptions
|
|
11
|
+
* cannot execute commands and must use a dedicated connection.
|
|
12
|
+
*
|
|
13
|
+
* @default redis.duplicate() (lazily created on first listen)
|
|
14
|
+
*/
|
|
15
|
+
subscriber?: undefined | Promisable<RedisClient>;
|
|
16
|
+
/**
|
|
17
|
+
* The prefix to use for Redis keys.
|
|
18
|
+
*
|
|
19
|
+
* @default ''
|
|
20
|
+
*/
|
|
21
|
+
prefix?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Serializer for serialize and deserialize payloads.
|
|
24
|
+
*
|
|
25
|
+
* @default RPCSerializer
|
|
26
|
+
*/
|
|
27
|
+
serializer?: undefined | Pick<RPCSerializer, keyof RPCSerializer>;
|
|
28
|
+
/**
|
|
29
|
+
* Configuration for event resume support.
|
|
30
|
+
*
|
|
31
|
+
* When enabled, published events are temporarily stored so new
|
|
32
|
+
* subscribers can resume from a previous position using `lastEventId`.
|
|
33
|
+
*
|
|
34
|
+
* @default { enabled: false }
|
|
35
|
+
*/
|
|
36
|
+
resume?: {
|
|
37
|
+
/**
|
|
38
|
+
* Whether event resume support is enabled.
|
|
39
|
+
*
|
|
40
|
+
* When enabled, published events are temporarily stored so new
|
|
41
|
+
* subscribers can resume from a previous position using `lastEventId`.
|
|
42
|
+
*
|
|
43
|
+
* @default false
|
|
44
|
+
*/
|
|
45
|
+
enabled: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* How long (in seconds) to retain events for resume.
|
|
48
|
+
*
|
|
49
|
+
* Expired events are cleaned up lazily for performance reasons, so
|
|
50
|
+
* some events may remain available slightly longer than this period.
|
|
51
|
+
*
|
|
52
|
+
* @default 300 (5 min)
|
|
53
|
+
*/
|
|
54
|
+
seconds?: number;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
declare class BunRedisPublisher<T extends Record<string, object>> extends Publisher<T> {
|
|
58
|
+
private readonly redis;
|
|
59
|
+
private subscriber;
|
|
60
|
+
private readonly prefix;
|
|
61
|
+
private readonly serializer;
|
|
62
|
+
private readonly resumeEnabled;
|
|
63
|
+
private readonly resumeSeconds;
|
|
64
|
+
/**
|
|
65
|
+
* The exactness of the `XTRIM` command.
|
|
66
|
+
* Used for testing purpose.
|
|
67
|
+
*/
|
|
68
|
+
private readonly xTrimExactness;
|
|
69
|
+
constructor(redis: RedisClient, options?: BunRedisPublisherOptions);
|
|
70
|
+
private readonly firstPublishTimeMap;
|
|
71
|
+
publish<K extends keyof T & string>(event: K, payload: T[K]): Promise<void>;
|
|
72
|
+
protected subscribeListener<K extends keyof T & string>(event: K, originalListener: (payload: T[K]) => void, { lastEventId, onError }?: PublisherSubscribeListenerOptions): Promise<() => Promise<void>>;
|
|
73
|
+
private serializePayload;
|
|
74
|
+
private deserializePayload;
|
|
75
|
+
}
|
|
3
76
|
|
|
4
77
|
interface BunRedisRateLimiterOptions {
|
|
5
78
|
/**
|
|
6
79
|
* The prefix to use for Redis keys.
|
|
80
|
+
*
|
|
81
|
+
* @default ''
|
|
7
82
|
*/
|
|
8
83
|
prefix?: string;
|
|
9
84
|
/**
|
|
@@ -38,5 +113,5 @@ declare class BunRedisRateLimiter implements RateLimiter {
|
|
|
38
113
|
private resolveWeight;
|
|
39
114
|
}
|
|
40
115
|
|
|
41
|
-
export { BunRedisRateLimiter };
|
|
42
|
-
export type { BunRedisRateLimiterOptions };
|
|
116
|
+
export { BunRedisPublisher, BunRedisRateLimiter };
|
|
117
|
+
export type { BunRedisPublisherOptions, BunRedisRateLimiterOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,84 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Publisher, PublisherOptions, PublisherSubscribeListenerOptions } from '@orpc/publisher';
|
|
2
|
+
import { Promisable } from '@orpc/shared';
|
|
2
3
|
import { RedisClient } from 'bun';
|
|
4
|
+
import { RPCSerializer } from '@orpc/client';
|
|
5
|
+
import { RateLimiter, RateLimitOptions, RateLimitResult } from '@orpc/ratelimit';
|
|
6
|
+
|
|
7
|
+
interface BunRedisPublisherOptions extends PublisherOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Redis subscriber instance.
|
|
10
|
+
* Pub/Sub takes over the connection, so a client with subscriptions
|
|
11
|
+
* cannot execute commands and must use a dedicated connection.
|
|
12
|
+
*
|
|
13
|
+
* @default redis.duplicate() (lazily created on first listen)
|
|
14
|
+
*/
|
|
15
|
+
subscriber?: undefined | Promisable<RedisClient>;
|
|
16
|
+
/**
|
|
17
|
+
* The prefix to use for Redis keys.
|
|
18
|
+
*
|
|
19
|
+
* @default ''
|
|
20
|
+
*/
|
|
21
|
+
prefix?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Serializer for serialize and deserialize payloads.
|
|
24
|
+
*
|
|
25
|
+
* @default RPCSerializer
|
|
26
|
+
*/
|
|
27
|
+
serializer?: undefined | Pick<RPCSerializer, keyof RPCSerializer>;
|
|
28
|
+
/**
|
|
29
|
+
* Configuration for event resume support.
|
|
30
|
+
*
|
|
31
|
+
* When enabled, published events are temporarily stored so new
|
|
32
|
+
* subscribers can resume from a previous position using `lastEventId`.
|
|
33
|
+
*
|
|
34
|
+
* @default { enabled: false }
|
|
35
|
+
*/
|
|
36
|
+
resume?: {
|
|
37
|
+
/**
|
|
38
|
+
* Whether event resume support is enabled.
|
|
39
|
+
*
|
|
40
|
+
* When enabled, published events are temporarily stored so new
|
|
41
|
+
* subscribers can resume from a previous position using `lastEventId`.
|
|
42
|
+
*
|
|
43
|
+
* @default false
|
|
44
|
+
*/
|
|
45
|
+
enabled: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* How long (in seconds) to retain events for resume.
|
|
48
|
+
*
|
|
49
|
+
* Expired events are cleaned up lazily for performance reasons, so
|
|
50
|
+
* some events may remain available slightly longer than this period.
|
|
51
|
+
*
|
|
52
|
+
* @default 300 (5 min)
|
|
53
|
+
*/
|
|
54
|
+
seconds?: number;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
declare class BunRedisPublisher<T extends Record<string, object>> extends Publisher<T> {
|
|
58
|
+
private readonly redis;
|
|
59
|
+
private subscriber;
|
|
60
|
+
private readonly prefix;
|
|
61
|
+
private readonly serializer;
|
|
62
|
+
private readonly resumeEnabled;
|
|
63
|
+
private readonly resumeSeconds;
|
|
64
|
+
/**
|
|
65
|
+
* The exactness of the `XTRIM` command.
|
|
66
|
+
* Used for testing purpose.
|
|
67
|
+
*/
|
|
68
|
+
private readonly xTrimExactness;
|
|
69
|
+
constructor(redis: RedisClient, options?: BunRedisPublisherOptions);
|
|
70
|
+
private readonly firstPublishTimeMap;
|
|
71
|
+
publish<K extends keyof T & string>(event: K, payload: T[K]): Promise<void>;
|
|
72
|
+
protected subscribeListener<K extends keyof T & string>(event: K, originalListener: (payload: T[K]) => void, { lastEventId, onError }?: PublisherSubscribeListenerOptions): Promise<() => Promise<void>>;
|
|
73
|
+
private serializePayload;
|
|
74
|
+
private deserializePayload;
|
|
75
|
+
}
|
|
3
76
|
|
|
4
77
|
interface BunRedisRateLimiterOptions {
|
|
5
78
|
/**
|
|
6
79
|
* The prefix to use for Redis keys.
|
|
80
|
+
*
|
|
81
|
+
* @default ''
|
|
7
82
|
*/
|
|
8
83
|
prefix?: string;
|
|
9
84
|
/**
|
|
@@ -38,5 +113,5 @@ declare class BunRedisRateLimiter implements RateLimiter {
|
|
|
38
113
|
private resolveWeight;
|
|
39
114
|
}
|
|
40
115
|
|
|
41
|
-
export { BunRedisRateLimiter };
|
|
42
|
-
export type { BunRedisRateLimiterOptions };
|
|
116
|
+
export { BunRedisPublisher, BunRedisRateLimiter };
|
|
117
|
+
export type { BunRedisPublisherOptions, BunRedisRateLimiterOptions };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,125 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RPCSerializer } from '@orpc/client';
|
|
2
|
+
import { Publisher } from '@orpc/publisher';
|
|
3
|
+
import { stringifyJSON, parseEmptyableJSON, once, sleep } from '@orpc/shared';
|
|
4
|
+
import { unwrapEvent, withEventMeta, getEventMeta } from '@standardserver/core';
|
|
5
|
+
|
|
6
|
+
class BunRedisPublisher extends Publisher {
|
|
7
|
+
constructor(redis, options = {}) {
|
|
8
|
+
super(options);
|
|
9
|
+
this.redis = redis;
|
|
10
|
+
this.prefix = options.prefix ?? "";
|
|
11
|
+
this.serializer = options.serializer ?? new RPCSerializer();
|
|
12
|
+
this.resumeEnabled = options.resume?.enabled ?? false;
|
|
13
|
+
this.resumeSeconds = options.resume?.seconds ?? 300;
|
|
14
|
+
this.subscriber = options.subscriber;
|
|
15
|
+
}
|
|
16
|
+
subscriber;
|
|
17
|
+
prefix;
|
|
18
|
+
serializer;
|
|
19
|
+
resumeEnabled;
|
|
20
|
+
resumeSeconds;
|
|
21
|
+
/**
|
|
22
|
+
* The exactness of the `XTRIM` command.
|
|
23
|
+
* Used for testing purpose.
|
|
24
|
+
*/
|
|
25
|
+
xTrimExactness = "~";
|
|
26
|
+
firstPublishTimeMap = /* @__PURE__ */ new Map();
|
|
27
|
+
async publish(event, payload) {
|
|
28
|
+
const redisKey = `${this.prefix}${event}`;
|
|
29
|
+
const data = this.serializePayload(payload);
|
|
30
|
+
let id;
|
|
31
|
+
if (this.resumeEnabled) {
|
|
32
|
+
const now = Date.now();
|
|
33
|
+
for (const [event2, firstPublishTime] of this.firstPublishTimeMap) {
|
|
34
|
+
if (firstPublishTime + this.resumeSeconds * 1e3 < now) {
|
|
35
|
+
this.firstPublishTimeMap.delete(event2);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!this.firstPublishTimeMap.has(event)) {
|
|
39
|
+
this.firstPublishTimeMap.set(event, now);
|
|
40
|
+
const result = await Promise.all([
|
|
41
|
+
this.redis.send("XADD", [redisKey, "*", "data", stringifyJSON(data)]),
|
|
42
|
+
this.redis.send("XTRIM", [redisKey, "MINID", this.xTrimExactness, `${now - this.resumeSeconds * 1e3}-0`]),
|
|
43
|
+
// Use a 2x TTL so events published near the end of the resume window
|
|
44
|
+
// are not expired before the next window updates the key expiration.
|
|
45
|
+
this.redis.expire(redisKey, this.resumeSeconds * 2)
|
|
46
|
+
]);
|
|
47
|
+
id = result[0];
|
|
48
|
+
} else {
|
|
49
|
+
id = await this.redis.send("XADD", [redisKey, "*", "data", stringifyJSON(data)]);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
await this.redis.publish(redisKey, stringifyJSON({ data, id }));
|
|
53
|
+
}
|
|
54
|
+
async subscribeListener(event, originalListener, { lastEventId, onError } = {}) {
|
|
55
|
+
const redisKey = `${this.prefix}${event}`;
|
|
56
|
+
let pendingPayloads = [];
|
|
57
|
+
const resumedIds = /* @__PURE__ */ new Set();
|
|
58
|
+
const deduplicatingListener = (payload) => {
|
|
59
|
+
if (pendingPayloads) {
|
|
60
|
+
pendingPayloads.push(payload);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const id = getEventMeta(payload)?.id;
|
|
64
|
+
if (id !== void 0 && resumedIds.has(id)) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
originalListener(payload);
|
|
68
|
+
};
|
|
69
|
+
const redisListener = (message) => {
|
|
70
|
+
try {
|
|
71
|
+
const { id, data } = parseEmptyableJSON(message);
|
|
72
|
+
const payload = this.deserializePayload(id, data);
|
|
73
|
+
deduplicatingListener(payload);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
onError?.(error);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
this.subscriber ??= this.redis.duplicate();
|
|
79
|
+
const subscriber = await this.subscriber;
|
|
80
|
+
try {
|
|
81
|
+
const subscribePromise = subscriber.subscribe(redisKey, redisListener);
|
|
82
|
+
try {
|
|
83
|
+
if (this.resumeEnabled && lastEventId !== void 0) {
|
|
84
|
+
const results = await this.redis.send("XREAD", ["STREAMS", redisKey, lastEventId]);
|
|
85
|
+
if (results && results[redisKey]) {
|
|
86
|
+
const messages = results[redisKey];
|
|
87
|
+
for (const [id, message] of messages) {
|
|
88
|
+
const rawData = message[1];
|
|
89
|
+
const data = parseEmptyableJSON(rawData);
|
|
90
|
+
const payload = this.deserializePayload(id, data);
|
|
91
|
+
resumedIds.add(id);
|
|
92
|
+
originalListener(payload);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} finally {
|
|
97
|
+
const pending = pendingPayloads;
|
|
98
|
+
pendingPayloads = void 0;
|
|
99
|
+
for (const payload of pending) {
|
|
100
|
+
deduplicatingListener(payload);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
await subscribePromise;
|
|
104
|
+
} catch (error) {
|
|
105
|
+
await subscriber.unsubscribe(redisKey, redisListener);
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
return once(async () => {
|
|
109
|
+
await subscriber.unsubscribe(redisKey, redisListener);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
serializePayload(payload) {
|
|
113
|
+
const [original, meta] = unwrapEvent(payload);
|
|
114
|
+
return { payload: this.serializer.serialize(original, { useFormDataForBlobFields: false }), meta };
|
|
115
|
+
}
|
|
116
|
+
deserializePayload(id, { payload, meta }) {
|
|
117
|
+
return withEventMeta(
|
|
118
|
+
this.serializer.deserialize(payload),
|
|
119
|
+
id === void 0 ? { ...meta } : { ...meta, id }
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
2
123
|
|
|
3
124
|
const FIXED_WINDOW_RATELIMIT_SCRIPT = `
|
|
4
125
|
local key = KEYS[1]
|
|
@@ -88,4 +209,4 @@ class BunRedisRateLimiter {
|
|
|
88
209
|
}
|
|
89
210
|
}
|
|
90
211
|
|
|
91
|
-
export { BunRedisRateLimiter };
|
|
212
|
+
export { BunRedisPublisher, BunRedisRateLimiter };
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orpc/bun",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "1.14.11",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://orpc.dev",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/middleapi/orpc
|
|
9
|
+
"url": "git+https://github.com/middleapi/orpc.git",
|
|
10
10
|
"directory": "packages/bun"
|
|
11
11
|
},
|
|
12
12
|
"sideEffects": false,
|
|
@@ -22,16 +22,21 @@
|
|
|
22
22
|
"dist"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@
|
|
26
|
-
"@orpc/
|
|
27
|
-
"@orpc/
|
|
28
|
-
"@orpc/
|
|
25
|
+
"@standardserver/core": "^0.5.0",
|
|
26
|
+
"@orpc/client": "1.14.11",
|
|
27
|
+
"@orpc/ratelimit": "1.14.11",
|
|
28
|
+
"@orpc/publisher": "1.14.11",
|
|
29
|
+
"@orpc/server": "1.14.11",
|
|
30
|
+
"@orpc/shared": "1.14.11"
|
|
29
31
|
},
|
|
30
32
|
"devDependencies": {
|
|
33
|
+
"@types/bun": "^1.3.14",
|
|
31
34
|
"redis": "^6.0.1"
|
|
32
35
|
},
|
|
33
36
|
"scripts": {
|
|
34
37
|
"build": "unbuild",
|
|
35
|
-
"type:check": "tsc -b"
|
|
38
|
+
"type:check": "tsc -b",
|
|
39
|
+
"test": "bun --env-file=../../.env test",
|
|
40
|
+
"test:coverage": "bun --env-file=../../.env test --coverage"
|
|
36
41
|
}
|
|
37
42
|
}
|