@atproto/xrpc-server 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +6 -1
- package/dist/index.js +14 -6
- package/dist/index.js.map +3 -3
- package/dist/rate-limiter.d.ts +3 -1
- package/package.json +12 -6
- package/src/rate-limiter.ts +10 -4
- package/src/server.ts +3 -2
- package/src/types.ts +7 -1
package/dist/rate-limiter.d.ts
CHANGED
|
@@ -5,13 +5,15 @@ export declare type RateLimiterOpts = {
|
|
|
5
5
|
durationMs: number;
|
|
6
6
|
points: number;
|
|
7
7
|
bypassSecret?: string;
|
|
8
|
+
bypassIps?: string[];
|
|
8
9
|
calcKey?: CalcKeyFn;
|
|
9
10
|
calcPoints?: CalcPointsFn;
|
|
10
11
|
failClosed?: boolean;
|
|
11
12
|
};
|
|
12
13
|
export declare class RateLimiter implements RateLimiterI {
|
|
13
14
|
limiter: RateLimiterAbstract;
|
|
14
|
-
private
|
|
15
|
+
private bypassSecret?;
|
|
16
|
+
private bypassIps?;
|
|
15
17
|
private failClosed?;
|
|
16
18
|
calcKey: CalcKeyFn;
|
|
17
19
|
calcPoints: CalcPointsFn;
|
package/package.json
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/xrpc-server",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"main": "dist/index.js",
|
|
3
|
+
"version": "0.3.2",
|
|
5
4
|
"license": "MIT",
|
|
5
|
+
"description": "atproto HTTP API (XRPC) server library",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"atproto",
|
|
8
|
+
"xrpc"
|
|
9
|
+
],
|
|
10
|
+
"homepage": "https://atproto.com",
|
|
6
11
|
"repository": {
|
|
7
12
|
"type": "git",
|
|
8
|
-
"url": "https://github.com/bluesky-social/atproto
|
|
13
|
+
"url": "https://github.com/bluesky-social/atproto",
|
|
9
14
|
"directory": "packages/xrpc-server"
|
|
10
15
|
},
|
|
16
|
+
"main": "dist/index.js",
|
|
11
17
|
"dependencies": {
|
|
12
18
|
"cbor-x": "^1.5.1",
|
|
13
19
|
"express": "^4.17.2",
|
|
@@ -17,9 +23,9 @@
|
|
|
17
23
|
"uint8arrays": "3.0.0",
|
|
18
24
|
"ws": "^8.12.0",
|
|
19
25
|
"zod": "^3.21.4",
|
|
20
|
-
"@atproto/common": "^0.3.
|
|
26
|
+
"@atproto/common": "^0.3.1",
|
|
21
27
|
"@atproto/crypto": "^0.2.2",
|
|
22
|
-
"@atproto/lexicon": "^0.2.
|
|
28
|
+
"@atproto/lexicon": "^0.2.2"
|
|
23
29
|
},
|
|
24
30
|
"devDependencies": {
|
|
25
31
|
"@types/express": "^4.17.13",
|
|
@@ -29,7 +35,7 @@
|
|
|
29
35
|
"get-port": "^6.1.2",
|
|
30
36
|
"multiformats": "^9.9.0",
|
|
31
37
|
"@atproto/crypto": "^0.2.2",
|
|
32
|
-
"@atproto/xrpc": "^0.3.
|
|
38
|
+
"@atproto/xrpc": "^0.3.2"
|
|
33
39
|
},
|
|
34
40
|
"scripts": {
|
|
35
41
|
"test": "jest",
|
package/src/rate-limiter.ts
CHANGED
|
@@ -20,6 +20,7 @@ export type RateLimiterOpts = {
|
|
|
20
20
|
durationMs: number
|
|
21
21
|
points: number
|
|
22
22
|
bypassSecret?: string
|
|
23
|
+
bypassIps?: string[]
|
|
23
24
|
calcKey?: CalcKeyFn
|
|
24
25
|
calcPoints?: CalcPointsFn
|
|
25
26
|
failClosed?: boolean
|
|
@@ -27,14 +28,16 @@ export type RateLimiterOpts = {
|
|
|
27
28
|
|
|
28
29
|
export class RateLimiter implements RateLimiterI {
|
|
29
30
|
public limiter: RateLimiterAbstract
|
|
30
|
-
private
|
|
31
|
+
private bypassSecret?: string
|
|
32
|
+
private bypassIps?: string[]
|
|
31
33
|
private failClosed?: boolean
|
|
32
34
|
public calcKey: CalcKeyFn
|
|
33
35
|
public calcPoints: CalcPointsFn
|
|
34
36
|
|
|
35
37
|
constructor(limiter: RateLimiterAbstract, opts: RateLimiterOpts) {
|
|
36
38
|
this.limiter = limiter
|
|
37
|
-
this.
|
|
39
|
+
this.bypassSecret = opts.bypassSecret
|
|
40
|
+
this.bypassIps = opts.bypassIps
|
|
38
41
|
this.calcKey = opts.calcKey ?? defaultKey
|
|
39
42
|
this.calcPoints = opts.calcPoints ?? defaultPoints
|
|
40
43
|
}
|
|
@@ -63,11 +66,14 @@ export class RateLimiter implements RateLimiterI {
|
|
|
63
66
|
opts?: { calcKey?: CalcKeyFn; calcPoints?: CalcPointsFn },
|
|
64
67
|
): Promise<RateLimiterStatus | RateLimitExceededError | null> {
|
|
65
68
|
if (
|
|
66
|
-
this.
|
|
67
|
-
ctx.req.header('x-ratelimit-bypass') === this.
|
|
69
|
+
this.bypassSecret &&
|
|
70
|
+
ctx.req.header('x-ratelimit-bypass') === this.bypassSecret
|
|
68
71
|
) {
|
|
69
72
|
return null
|
|
70
73
|
}
|
|
74
|
+
if (this.bypassIps && this.bypassIps.includes(ctx.req.ip)) {
|
|
75
|
+
return null
|
|
76
|
+
}
|
|
71
77
|
const key = opts?.calcKey ? opts.calcKey(ctx) : this.calcKey(ctx)
|
|
72
78
|
const points = opts?.calcPoints
|
|
73
79
|
? opts.calcPoints(ctx)
|
package/src/server.ts
CHANGED
|
@@ -405,7 +405,8 @@ export class Server {
|
|
|
405
405
|
? config.rateLimit
|
|
406
406
|
: [config.rateLimit]
|
|
407
407
|
this.routeRateLimiterFns[nsid] = []
|
|
408
|
-
for (
|
|
408
|
+
for (let i = 0; i < limits.length; i++) {
|
|
409
|
+
const limit = limits[i]
|
|
409
410
|
const { calcKey, calcPoints } = limit
|
|
410
411
|
if (isShared(limit)) {
|
|
411
412
|
const rateLimiter = this.sharedRateLimiters[limit.name]
|
|
@@ -420,7 +421,7 @@ export class Server {
|
|
|
420
421
|
} else {
|
|
421
422
|
const { durationMs, points } = limit
|
|
422
423
|
const rateLimiter = this.options.rateLimits?.creator({
|
|
423
|
-
keyPrefix: nsid
|
|
424
|
+
keyPrefix: `nsid-${i}`,
|
|
424
425
|
durationMs,
|
|
425
426
|
points,
|
|
426
427
|
calcKey,
|
package/src/types.ts
CHANGED
|
@@ -201,7 +201,13 @@ export class XRPCError extends Error {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
export function isHandlerError(v: unknown): v is HandlerError {
|
|
204
|
-
return
|
|
204
|
+
return (
|
|
205
|
+
!!v &&
|
|
206
|
+
typeof v === 'object' &&
|
|
207
|
+
typeof v['status'] === 'number' &&
|
|
208
|
+
(v['error'] === undefined || typeof v['error'] === 'string') &&
|
|
209
|
+
(v['message'] === undefined || typeof v['message'] === 'string')
|
|
210
|
+
)
|
|
205
211
|
}
|
|
206
212
|
|
|
207
213
|
export class InvalidRequestError extends XRPCError {
|