@orpc/bun 0.0.0 → 2.0.0-beta.8
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 +9 -8
- package/dist/index.d.mts +74 -3
- package/dist/index.d.ts +74 -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" />
|
|
@@ -117,25 +117,25 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
|
|
|
117
117
|
<table>
|
|
118
118
|
<tr>
|
|
119
119
|
<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>
|
|
120
|
+
<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
121
|
<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
122
|
<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
123
|
<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
124
|
<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
125
|
<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
126
|
</tr>
|
|
127
127
|
<tr>
|
|
128
|
+
<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
129
|
<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
130
|
<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
131
|
<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
132
|
<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
133
|
<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
134
|
<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
135
|
</tr>
|
|
136
136
|
<tr>
|
|
137
|
+
<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
138
|
<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
139
|
<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
140
|
</tr>
|
|
141
141
|
</table>
|
|
@@ -174,6 +174,7 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
|
|
|
174
174
|
<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
175
|
<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
176
|
<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>
|
|
177
|
+
<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
178
|
<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
179
|
<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
180
|
</p>
|
|
@@ -187,4 +188,4 @@ oRPC is inspired by existing solutions that prioritize type safety and developer
|
|
|
187
188
|
|
|
188
189
|
## License
|
|
189
190
|
|
|
190
|
-
Distributed under the MIT License. See [LICENSE](https://github.com/middleapi/orpc
|
|
191
|
+
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,5 +1,76 @@
|
|
|
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
|
+
prefix?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Serializer for serialize and deserialize payloads.
|
|
22
|
+
*
|
|
23
|
+
* @default RPCSerializer
|
|
24
|
+
*/
|
|
25
|
+
serializer?: undefined | Pick<RPCSerializer, keyof RPCSerializer>;
|
|
26
|
+
/**
|
|
27
|
+
* Configuration for event replay support.
|
|
28
|
+
*
|
|
29
|
+
* When enabled, published events are temporarily stored so new
|
|
30
|
+
* subscribers can resume from a previous position using `lastEventId`.
|
|
31
|
+
*
|
|
32
|
+
* @default { enabled: false }
|
|
33
|
+
*/
|
|
34
|
+
replay?: {
|
|
35
|
+
/**
|
|
36
|
+
* Whether event replay support is enabled.
|
|
37
|
+
*
|
|
38
|
+
* When enabled, published events are temporarily stored so new
|
|
39
|
+
* subscribers can resume from a previous position using `lastEventId`.
|
|
40
|
+
*
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
43
|
+
enabled: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* How long (in seconds) to retain events for replay.
|
|
46
|
+
*
|
|
47
|
+
* Expired events are cleaned up lazily for performance reasons, so
|
|
48
|
+
* some events may remain available slightly longer than this period.
|
|
49
|
+
*
|
|
50
|
+
* @default 300 (5 min)
|
|
51
|
+
*/
|
|
52
|
+
seconds?: number;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
declare class BunRedisPublisher<T extends Record<string, object>> extends Publisher<T> {
|
|
56
|
+
private readonly redis;
|
|
57
|
+
private subscriber;
|
|
58
|
+
private readonly prefix;
|
|
59
|
+
private readonly serializer;
|
|
60
|
+
private readonly replayEnabled;
|
|
61
|
+
private readonly replaySeconds;
|
|
62
|
+
/**
|
|
63
|
+
* The exactness of the `XTRIM` command.
|
|
64
|
+
* Used for testing purpose.
|
|
65
|
+
*/
|
|
66
|
+
private readonly xTrimExactness;
|
|
67
|
+
constructor(redis: RedisClient, options?: BunRedisPublisherOptions);
|
|
68
|
+
private readonly firstPublishTimeMap;
|
|
69
|
+
publish<K extends keyof T & string>(event: K, payload: T[K]): Promise<void>;
|
|
70
|
+
protected subscribeListener<K extends keyof T & string>(event: K, originalListener: (payload: T[K]) => void, { lastEventId, onError }?: PublisherSubscribeListenerOptions): Promise<() => Promise<void>>;
|
|
71
|
+
private serializePayload;
|
|
72
|
+
private deserializePayload;
|
|
73
|
+
}
|
|
3
74
|
|
|
4
75
|
interface BunRedisRateLimiterOptions {
|
|
5
76
|
/**
|
|
@@ -38,5 +109,5 @@ declare class BunRedisRateLimiter implements RateLimiter {
|
|
|
38
109
|
private resolveWeight;
|
|
39
110
|
}
|
|
40
111
|
|
|
41
|
-
export { BunRedisRateLimiter };
|
|
42
|
-
export type { BunRedisRateLimiterOptions };
|
|
112
|
+
export { BunRedisPublisher, BunRedisRateLimiter };
|
|
113
|
+
export type { BunRedisPublisherOptions, BunRedisRateLimiterOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,76 @@
|
|
|
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
|
+
prefix?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Serializer for serialize and deserialize payloads.
|
|
22
|
+
*
|
|
23
|
+
* @default RPCSerializer
|
|
24
|
+
*/
|
|
25
|
+
serializer?: undefined | Pick<RPCSerializer, keyof RPCSerializer>;
|
|
26
|
+
/**
|
|
27
|
+
* Configuration for event replay support.
|
|
28
|
+
*
|
|
29
|
+
* When enabled, published events are temporarily stored so new
|
|
30
|
+
* subscribers can resume from a previous position using `lastEventId`.
|
|
31
|
+
*
|
|
32
|
+
* @default { enabled: false }
|
|
33
|
+
*/
|
|
34
|
+
replay?: {
|
|
35
|
+
/**
|
|
36
|
+
* Whether event replay support is enabled.
|
|
37
|
+
*
|
|
38
|
+
* When enabled, published events are temporarily stored so new
|
|
39
|
+
* subscribers can resume from a previous position using `lastEventId`.
|
|
40
|
+
*
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
43
|
+
enabled: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* How long (in seconds) to retain events for replay.
|
|
46
|
+
*
|
|
47
|
+
* Expired events are cleaned up lazily for performance reasons, so
|
|
48
|
+
* some events may remain available slightly longer than this period.
|
|
49
|
+
*
|
|
50
|
+
* @default 300 (5 min)
|
|
51
|
+
*/
|
|
52
|
+
seconds?: number;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
declare class BunRedisPublisher<T extends Record<string, object>> extends Publisher<T> {
|
|
56
|
+
private readonly redis;
|
|
57
|
+
private subscriber;
|
|
58
|
+
private readonly prefix;
|
|
59
|
+
private readonly serializer;
|
|
60
|
+
private readonly replayEnabled;
|
|
61
|
+
private readonly replaySeconds;
|
|
62
|
+
/**
|
|
63
|
+
* The exactness of the `XTRIM` command.
|
|
64
|
+
* Used for testing purpose.
|
|
65
|
+
*/
|
|
66
|
+
private readonly xTrimExactness;
|
|
67
|
+
constructor(redis: RedisClient, options?: BunRedisPublisherOptions);
|
|
68
|
+
private readonly firstPublishTimeMap;
|
|
69
|
+
publish<K extends keyof T & string>(event: K, payload: T[K]): Promise<void>;
|
|
70
|
+
protected subscribeListener<K extends keyof T & string>(event: K, originalListener: (payload: T[K]) => void, { lastEventId, onError }?: PublisherSubscribeListenerOptions): Promise<() => Promise<void>>;
|
|
71
|
+
private serializePayload;
|
|
72
|
+
private deserializePayload;
|
|
73
|
+
}
|
|
3
74
|
|
|
4
75
|
interface BunRedisRateLimiterOptions {
|
|
5
76
|
/**
|
|
@@ -38,5 +109,5 @@ declare class BunRedisRateLimiter implements RateLimiter {
|
|
|
38
109
|
private resolveWeight;
|
|
39
110
|
}
|
|
40
111
|
|
|
41
|
-
export { BunRedisRateLimiter };
|
|
42
|
-
export type { BunRedisRateLimiterOptions };
|
|
112
|
+
export { BunRedisPublisher, BunRedisRateLimiter };
|
|
113
|
+
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.replayEnabled = options.replay?.enabled ?? false;
|
|
13
|
+
this.replaySeconds = options.replay?.seconds ?? 300;
|
|
14
|
+
this.subscriber = options.subscriber;
|
|
15
|
+
}
|
|
16
|
+
subscriber;
|
|
17
|
+
prefix;
|
|
18
|
+
serializer;
|
|
19
|
+
replayEnabled;
|
|
20
|
+
replaySeconds;
|
|
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.replayEnabled) {
|
|
32
|
+
const now = Date.now();
|
|
33
|
+
for (const [event2, firstPublishTime] of this.firstPublishTimeMap) {
|
|
34
|
+
if (firstPublishTime + this.replaySeconds * 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.replaySeconds * 1e3}-0`]),
|
|
43
|
+
// Use a 2x TTL so events published near the end of the replay window
|
|
44
|
+
// are not expired before the next window updates the key expiration.
|
|
45
|
+
this.redis.expire(redisKey, this.replaySeconds * 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 replayedIds = /* @__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 && replayedIds.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.replayEnabled && 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
|
+
replayedIds.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": "0.0.
|
|
4
|
+
"version": "2.0.0-beta.8",
|
|
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.0.25",
|
|
26
|
+
"@orpc/client": "2.0.0-beta.8",
|
|
27
|
+
"@orpc/publisher": "2.0.0-beta.8",
|
|
28
|
+
"@orpc/ratelimit": "2.0.0-beta.8",
|
|
29
|
+
"@orpc/server": "2.0.0-beta.8",
|
|
30
|
+
"@orpc/shared": "2.0.0-beta.8"
|
|
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
|
}
|