@atproto/xrpc-server 0.4.4-next.0 → 0.4.4

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.
Files changed (74) hide show
  1. package/CHANGELOG.md +4 -6
  2. package/babel.config.js +1 -0
  3. package/build.js +14 -0
  4. package/dist/auth.d.ts +1 -2
  5. package/dist/index.d.ts +0 -1
  6. package/dist/index.js +53682 -25
  7. package/dist/index.js.map +7 -1
  8. package/dist/logger.d.ts +0 -1
  9. package/dist/rate-limiter.d.ts +0 -1
  10. package/dist/server.d.ts +4 -5
  11. package/dist/stream/frames.d.ts +1 -2
  12. package/dist/stream/index.d.ts +0 -1
  13. package/dist/stream/logger.d.ts +0 -1
  14. package/dist/stream/server.d.ts +0 -2
  15. package/dist/stream/stream.d.ts +0 -1
  16. package/dist/stream/subscription.d.ts +0 -2
  17. package/dist/stream/types.d.ts +0 -1
  18. package/dist/stream/websocket-keepalive.d.ts +0 -2
  19. package/dist/types.d.ts +0 -2
  20. package/dist/util.d.ts +0 -1
  21. package/jest.config.js +3 -4
  22. package/package.json +11 -10
  23. package/src/auth.ts +1 -1
  24. package/src/server.ts +11 -11
  25. package/src/stream/frames.ts +1 -1
  26. package/src/stream/websocket-keepalive.ts +1 -2
  27. package/tests/bodies.test.ts +4 -4
  28. package/tests/errors.test.ts +1 -1
  29. package/tsconfig.build.json +2 -6
  30. package/tsconfig.json +11 -3
  31. package/dist/auth.d.ts.map +0 -1
  32. package/dist/auth.js +0 -124
  33. package/dist/auth.js.map +0 -1
  34. package/dist/index.d.ts.map +0 -1
  35. package/dist/logger.d.ts.map +0 -1
  36. package/dist/logger.js +0 -7
  37. package/dist/logger.js.map +0 -1
  38. package/dist/rate-limiter.d.ts.map +0 -1
  39. package/dist/rate-limiter.js +0 -166
  40. package/dist/rate-limiter.js.map +0 -1
  41. package/dist/server.d.ts.map +0 -1
  42. package/dist/server.js +0 -472
  43. package/dist/server.js.map +0 -1
  44. package/dist/stream/frames.d.ts.map +0 -1
  45. package/dist/stream/frames.js +0 -141
  46. package/dist/stream/frames.js.map +0 -1
  47. package/dist/stream/index.d.ts.map +0 -1
  48. package/dist/stream/index.js +0 -22
  49. package/dist/stream/index.js.map +0 -1
  50. package/dist/stream/logger.d.ts.map +0 -1
  51. package/dist/stream/logger.js +0 -7
  52. package/dist/stream/logger.js.map +0 -1
  53. package/dist/stream/server.d.ts.map +0 -1
  54. package/dist/stream/server.js +0 -70
  55. package/dist/stream/server.js.map +0 -1
  56. package/dist/stream/stream.d.ts.map +0 -1
  57. package/dist/stream/stream.js +0 -44
  58. package/dist/stream/stream.js.map +0 -1
  59. package/dist/stream/subscription.d.ts.map +0 -1
  60. package/dist/stream/subscription.js +0 -80
  61. package/dist/stream/subscription.js.map +0 -1
  62. package/dist/stream/types.d.ts.map +0 -1
  63. package/dist/stream/types.js +0 -47
  64. package/dist/stream/types.js.map +0 -1
  65. package/dist/stream/websocket-keepalive.d.ts.map +0 -1
  66. package/dist/stream/websocket-keepalive.js +0 -160
  67. package/dist/stream/websocket-keepalive.js.map +0 -1
  68. package/dist/types.d.ts.map +0 -1
  69. package/dist/types.js +0 -163
  70. package/dist/types.js.map +0 -1
  71. package/dist/util.d.ts.map +0 -1
  72. package/dist/util.js +0 -263
  73. package/dist/util.js.map +0 -1
  74. package/tsconfig.tests.json +0 -7
@@ -1,166 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getTightestLimit = exports.setResHeaders = exports.consumeMany = exports.formatLimiterStatus = exports.RateLimiter = void 0;
4
- const rate_limiter_flexible_1 = require("rate-limiter-flexible");
5
- const logger_1 = require("./logger");
6
- const types_1 = require("./types");
7
- class RateLimiter {
8
- constructor(limiter, opts) {
9
- Object.defineProperty(this, "limiter", {
10
- enumerable: true,
11
- configurable: true,
12
- writable: true,
13
- value: void 0
14
- });
15
- Object.defineProperty(this, "bypassSecret", {
16
- enumerable: true,
17
- configurable: true,
18
- writable: true,
19
- value: void 0
20
- });
21
- Object.defineProperty(this, "bypassIps", {
22
- enumerable: true,
23
- configurable: true,
24
- writable: true,
25
- value: void 0
26
- });
27
- Object.defineProperty(this, "failClosed", {
28
- enumerable: true,
29
- configurable: true,
30
- writable: true,
31
- value: void 0
32
- });
33
- Object.defineProperty(this, "calcKey", {
34
- enumerable: true,
35
- configurable: true,
36
- writable: true,
37
- value: void 0
38
- });
39
- Object.defineProperty(this, "calcPoints", {
40
- enumerable: true,
41
- configurable: true,
42
- writable: true,
43
- value: void 0
44
- });
45
- this.limiter = limiter;
46
- this.bypassSecret = opts.bypassSecret;
47
- this.bypassIps = opts.bypassIps;
48
- this.calcKey = opts.calcKey ?? defaultKey;
49
- this.calcPoints = opts.calcPoints ?? defaultPoints;
50
- }
51
- static memory(opts) {
52
- const limiter = new rate_limiter_flexible_1.RateLimiterMemory({
53
- keyPrefix: opts.keyPrefix,
54
- duration: Math.floor(opts.durationMs / 1000),
55
- points: opts.points,
56
- });
57
- return new RateLimiter(limiter, opts);
58
- }
59
- static redis(storeClient, opts) {
60
- const limiter = new rate_limiter_flexible_1.RateLimiterRedis({
61
- storeClient,
62
- keyPrefix: opts.keyPrefix,
63
- duration: Math.floor(opts.durationMs / 1000),
64
- points: opts.points,
65
- });
66
- return new RateLimiter(limiter, opts);
67
- }
68
- async consume(ctx, opts) {
69
- if (this.bypassSecret &&
70
- ctx.req.header('x-ratelimit-bypass') === this.bypassSecret) {
71
- return null;
72
- }
73
- if (this.bypassIps && this.bypassIps.includes(ctx.req.ip)) {
74
- return null;
75
- }
76
- const key = opts?.calcKey ? opts.calcKey(ctx) : this.calcKey(ctx);
77
- if (key === null) {
78
- return null;
79
- }
80
- const points = opts?.calcPoints
81
- ? opts.calcPoints(ctx)
82
- : this.calcPoints(ctx);
83
- if (points < 1) {
84
- return null;
85
- }
86
- try {
87
- const res = await this.limiter.consume(key, points);
88
- return (0, exports.formatLimiterStatus)(this.limiter, res);
89
- }
90
- catch (err) {
91
- // yes this library rejects with a res not an error
92
- if (err instanceof rate_limiter_flexible_1.RateLimiterRes) {
93
- const status = (0, exports.formatLimiterStatus)(this.limiter, err);
94
- return new types_1.RateLimitExceededError(status);
95
- }
96
- else {
97
- if (this.failClosed) {
98
- throw err;
99
- }
100
- logger_1.logger.error({
101
- err,
102
- keyPrefix: this.limiter.keyPrefix,
103
- points: this.limiter.points,
104
- duration: this.limiter.duration,
105
- }, 'rate limiter failed to consume points');
106
- return null;
107
- }
108
- }
109
- }
110
- }
111
- exports.RateLimiter = RateLimiter;
112
- const formatLimiterStatus = (limiter, res) => {
113
- return {
114
- limit: limiter.points,
115
- duration: limiter.duration,
116
- remainingPoints: res.remainingPoints,
117
- msBeforeNext: res.msBeforeNext,
118
- consumedPoints: res.consumedPoints,
119
- isFirstInDuration: res.isFirstInDuration,
120
- };
121
- };
122
- exports.formatLimiterStatus = formatLimiterStatus;
123
- const consumeMany = async (ctx, fns) => {
124
- if (fns.length === 0)
125
- return null;
126
- const results = await Promise.all(fns.map((fn) => fn(ctx)));
127
- const tightestLimit = (0, exports.getTightestLimit)(results);
128
- if (tightestLimit === null) {
129
- return null;
130
- }
131
- else if (tightestLimit instanceof types_1.RateLimitExceededError) {
132
- (0, exports.setResHeaders)(ctx, tightestLimit.status);
133
- return tightestLimit;
134
- }
135
- else {
136
- (0, exports.setResHeaders)(ctx, tightestLimit);
137
- return tightestLimit;
138
- }
139
- };
140
- exports.consumeMany = consumeMany;
141
- const setResHeaders = (ctx, status) => {
142
- ctx.res.setHeader('RateLimit-Limit', status.limit);
143
- ctx.res.setHeader('RateLimit-Remaining', status.remainingPoints);
144
- ctx.res.setHeader('RateLimit-Reset', Math.floor((Date.now() + status.msBeforeNext) / 1000));
145
- ctx.res.setHeader('RateLimit-Policy', `${status.limit};w=${status.duration}`);
146
- };
147
- exports.setResHeaders = setResHeaders;
148
- const getTightestLimit = (resps) => {
149
- let lowest = null;
150
- for (const resp of resps) {
151
- if (resp === null)
152
- continue;
153
- if (resp instanceof types_1.RateLimitExceededError)
154
- return resp;
155
- if (lowest === null || resp.remainingPoints < lowest.remainingPoints) {
156
- lowest = resp;
157
- }
158
- }
159
- return lowest;
160
- };
161
- exports.getTightestLimit = getTightestLimit;
162
- // when using a proxy, ensure headers are getting forwarded correctly: `app.set('trust proxy', true)`
163
- // https://expressjs.com/en/guide/behind-proxies.html
164
- const defaultKey = (ctx) => ctx.req.ip;
165
- const defaultPoints = () => 1;
166
- //# sourceMappingURL=rate-limiter.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":";;;AAAA,iEAK8B;AAC9B,qCAAiC;AACjC,mCAQgB;AAahB,MAAa,WAAW;IAQtB,YAAY,OAA4B,EAAE,IAAqB;QAPxD;;;;;WAA4B;QAC3B;;;;;WAAqB;QACrB;;;;;WAAoB;QACpB;;;;;WAAoB;QACrB;;;;;WAAkB;QAClB;;;;;WAAwB;QAG7B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAA;QACrC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAA;QAC/B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,UAAU,CAAA;QACzC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,aAAa,CAAA;IACpD,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,IAAqB;QACjC,MAAM,OAAO,GAAG,IAAI,yCAAiB,CAAC;YACpC,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YAC5C,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAA;QACF,OAAO,IAAI,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IACvC,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,WAAoB,EAAE,IAAqB;QACtD,MAAM,OAAO,GAAG,IAAI,wCAAgB,CAAC;YACnC,WAAW;YACX,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YAC5C,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAA;QACF,OAAO,IAAI,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IACvC,CAAC;IAED,KAAK,CAAC,OAAO,CACX,GAAmB,EACnB,IAAyD;QAEzD,IACE,IAAI,CAAC,YAAY;YACjB,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,oBAAoB,CAAC,KAAK,IAAI,CAAC,YAAY,EAC1D,CAAC;YACD,OAAO,IAAI,CAAA;QACb,CAAC;QACD,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAC1D,OAAO,IAAI,CAAA;QACb,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACjE,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,OAAO,IAAI,CAAA;QACb,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,EAAE,UAAU;YAC7B,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YACtB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;QACxB,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YACf,OAAO,IAAI,CAAA;QACb,CAAC;QACD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;YACnD,OAAO,IAAA,2BAAmB,EAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;QAC/C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,mDAAmD;YACnD,IAAI,GAAG,YAAY,sCAAc,EAAE,CAAC;gBAClC,MAAM,MAAM,GAAG,IAAA,2BAAmB,EAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;gBACrD,OAAO,IAAI,8BAAsB,CAAC,MAAM,CAAC,CAAA;YAC3C,CAAC;iBAAM,CAAC;gBACN,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;oBACpB,MAAM,GAAG,CAAA;gBACX,CAAC;gBACD,eAAM,CAAC,KAAK,CACV;oBACE,GAAG;oBACH,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;oBACjC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;oBAC3B,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ;iBAChC,EACD,uCAAuC,CACxC,CAAA;gBACD,OAAO,IAAI,CAAA;YACb,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAnFD,kCAmFC;AAEM,MAAM,mBAAmB,GAAG,CACjC,OAA4B,EAC5B,GAAmB,EACA,EAAE;IACrB,OAAO;QACL,KAAK,EAAE,OAAO,CAAC,MAAM;QACrB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,eAAe,EAAE,GAAG,CAAC,eAAe;QACpC,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;KACzC,CAAA;AACH,CAAC,CAAA;AAZY,QAAA,mBAAmB,uBAY/B;AAEM,MAAM,WAAW,GAAG,KAAK,EAC9B,GAAmB,EACnB,GAAyB,EACmC,EAAE;IAC9D,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACjC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IAC3D,MAAM,aAAa,GAAG,IAAA,wBAAgB,EAAC,OAAO,CAAC,CAAA;IAC/C,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAA;IACb,CAAC;SAAM,IAAI,aAAa,YAAY,8BAAsB,EAAE,CAAC;QAC3D,IAAA,qBAAa,EAAC,GAAG,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;QACxC,OAAO,aAAa,CAAA;IACtB,CAAC;SAAM,CAAC;QACN,IAAA,qBAAa,EAAC,GAAG,EAAE,aAAa,CAAC,CAAA;QACjC,OAAO,aAAa,CAAA;IACtB,CAAC;AACH,CAAC,CAAA;AAhBY,QAAA,WAAW,eAgBvB;AAEM,MAAM,aAAa,GAAG,CAC3B,GAAmB,EACnB,MAAyB,EACzB,EAAE;IACF,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;IAClD,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,qBAAqB,EAAE,MAAM,CAAC,eAAe,CAAC,CAAA;IAChE,GAAG,CAAC,GAAG,CAAC,SAAS,CACf,iBAAiB,EACjB,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,CACtD,CAAA;IACD,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,kBAAkB,EAAE,GAAG,MAAM,CAAC,KAAK,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;AAC/E,CAAC,CAAA;AAXY,QAAA,aAAa,iBAWzB;AAEM,MAAM,gBAAgB,GAAG,CAC9B,KAA4D,EACT,EAAE;IACrD,IAAI,MAAM,GAA6B,IAAI,CAAA;IAC3C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,KAAK,IAAI;YAAE,SAAQ;QAC3B,IAAI,IAAI,YAAY,8BAAsB;YAAE,OAAO,IAAI,CAAA;QACvD,IAAI,MAAM,KAAK,IAAI,IAAI,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC;YACrE,MAAM,GAAG,IAAI,CAAA;QACf,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAZY,QAAA,gBAAgB,oBAY5B;AAED,qGAAqG;AACrG,qDAAqD;AACrD,MAAM,UAAU,GAAc,CAAC,GAAmB,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAA;AACjE,MAAM,aAAa,GAAiB,GAAG,EAAE,CAAC,CAAC,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAgB,EAEd,OAAO,EACP,MAAM,EACN,OAAO,EACP,QAAQ,EAER,YAAY,EACZ,cAAc,EACf,MAAM,SAAS,CAAA;AAChB,OAAO,EACL,UAAU,EACV,QAAQ,EAER,gBAAgB,EAChB,YAAY,EACZ,mBAAmB,EACpB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAmC,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAC5E,OAAO,EACL,WAAW,EAMX,iBAAiB,EAKjB,OAAO,EACP,uBAAuB,EACvB,iBAAiB,EAIjB,YAAY,EACZ,kBAAkB,EAInB,MAAM,SAAS,CAAA;AAUhB,wBAAgB,YAAY,CAAC,QAAQ,CAAC,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,EAAE,OAAO,UAEtE;AAED,qBAAa,MAAM;IACjB,MAAM,EAAE,OAAO,CAAY;IAC3B,MAAM,EAAE,MAAM,CAAmB;IACjC,aAAa,gCAAsC;IACnD,GAAG,WAAiB;IACpB,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,cAAc,CAAC,CAAA;IACnD,kBAAkB,EAAE,YAAY,EAAE,CAAA;IAClC,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IAChD,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAA;gBAE7C,QAAQ,CAAC,EAAE,UAAU,EAAE,EAAE,IAAI,CAAC,EAAE,OAAO;IAyCnD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB,GAAG,WAAW;IAIhE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB,GAAG,WAAW;IAWnE,YAAY,CACV,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,uBAAuB,GAAG,iBAAiB;IAKzD,eAAe,CACb,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,uBAAuB,GAAG,iBAAiB;IAezD,UAAU,CAAC,GAAG,EAAE,UAAU;IAI1B,WAAW,CAAC,IAAI,EAAE,UAAU,EAAE;cASd,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,YAAY,GAAG,gBAAgB,EACpC,MAAM,EAAE,iBAAiB;IAoBrB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY;IAsB/D,aAAa,CACX,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,YAAY,GAAG,gBAAgB,EACpC,QAAQ,EAAE,iBAAiB,GAC1B,cAAc;cAsHD,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,mBAAmB,EACxB,MAAM,EAAE,uBAAuB;IA4DjC,OAAO,CAAC,uBAAuB;IAmB/B,OAAO,CAAC,oBAAoB;CAiD7B"}
package/dist/server.js DELETED
@@ -1,472 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Server = exports.createServer = void 0;
7
- const stream_1 = require("stream");
8
- const express_1 = __importDefault(require("express"));
9
- const lexicon_1 = require("@atproto/lexicon");
10
- const common_1 = require("@atproto/common");
11
- const stream_2 = require("./stream");
12
- const types_1 = require("./types");
13
- const util_1 = require("./util");
14
- const logger_1 = __importDefault(require("./logger"));
15
- const rate_limiter_1 = require("./rate-limiter");
16
- function createServer(lexicons, options) {
17
- return new Server(lexicons, options);
18
- }
19
- exports.createServer = createServer;
20
- class Server {
21
- constructor(lexicons, opts) {
22
- Object.defineProperty(this, "router", {
23
- enumerable: true,
24
- configurable: true,
25
- writable: true,
26
- value: (0, express_1.default)()
27
- });
28
- Object.defineProperty(this, "routes", {
29
- enumerable: true,
30
- configurable: true,
31
- writable: true,
32
- value: express_1.default.Router()
33
- });
34
- Object.defineProperty(this, "subscriptions", {
35
- enumerable: true,
36
- configurable: true,
37
- writable: true,
38
- value: new Map()
39
- });
40
- Object.defineProperty(this, "lex", {
41
- enumerable: true,
42
- configurable: true,
43
- writable: true,
44
- value: new lexicon_1.Lexicons()
45
- });
46
- Object.defineProperty(this, "options", {
47
- enumerable: true,
48
- configurable: true,
49
- writable: true,
50
- value: void 0
51
- });
52
- Object.defineProperty(this, "middleware", {
53
- enumerable: true,
54
- configurable: true,
55
- writable: true,
56
- value: void 0
57
- });
58
- Object.defineProperty(this, "globalRateLimiters", {
59
- enumerable: true,
60
- configurable: true,
61
- writable: true,
62
- value: void 0
63
- });
64
- Object.defineProperty(this, "sharedRateLimiters", {
65
- enumerable: true,
66
- configurable: true,
67
- writable: true,
68
- value: void 0
69
- });
70
- Object.defineProperty(this, "routeRateLimiterFns", {
71
- enumerable: true,
72
- configurable: true,
73
- writable: true,
74
- value: void 0
75
- });
76
- if (lexicons) {
77
- this.addLexicons(lexicons);
78
- }
79
- this.router.use(this.routes);
80
- this.router.use('/xrpc/:methodId', this.catchall.bind(this));
81
- this.router.use(errorMiddleware);
82
- this.router.once('mount', (app) => {
83
- this.enableStreamingOnListen(app);
84
- });
85
- this.options = opts ?? {};
86
- this.middleware = {
87
- json: express_1.default.json({ limit: opts?.payload?.jsonLimit }),
88
- text: express_1.default.text({ limit: opts?.payload?.textLimit }),
89
- };
90
- this.globalRateLimiters = [];
91
- this.sharedRateLimiters = {};
92
- this.routeRateLimiterFns = {};
93
- if (opts?.rateLimits?.global) {
94
- for (const limit of opts.rateLimits.global) {
95
- const rateLimiter = opts.rateLimits.creator({
96
- ...limit,
97
- keyPrefix: `rl-${limit.name}`,
98
- });
99
- this.globalRateLimiters.push(rateLimiter);
100
- }
101
- }
102
- if (opts?.rateLimits?.shared) {
103
- for (const limit of opts.rateLimits.shared) {
104
- const rateLimiter = opts.rateLimits.creator({
105
- ...limit,
106
- keyPrefix: `rl-${limit.name}`,
107
- });
108
- this.sharedRateLimiters[limit.name] = rateLimiter;
109
- }
110
- }
111
- }
112
- // handlers
113
- // =
114
- method(nsid, configOrFn) {
115
- this.addMethod(nsid, configOrFn);
116
- }
117
- addMethod(nsid, configOrFn) {
118
- const config = typeof configOrFn === 'function' ? { handler: configOrFn } : configOrFn;
119
- const def = this.lex.getDef(nsid);
120
- if (def?.type === 'query' || def?.type === 'procedure') {
121
- this.addRoute(nsid, def, config);
122
- }
123
- else {
124
- throw new Error(`Lex def for ${nsid} is not a query or a procedure`);
125
- }
126
- }
127
- streamMethod(nsid, configOrFn) {
128
- this.addStreamMethod(nsid, configOrFn);
129
- }
130
- addStreamMethod(nsid, configOrFn) {
131
- const config = typeof configOrFn === 'function' ? { handler: configOrFn } : configOrFn;
132
- const def = this.lex.getDef(nsid);
133
- if (def?.type === 'subscription') {
134
- this.addSubscription(nsid, def, config);
135
- }
136
- else {
137
- throw new Error(`Lex def for ${nsid} is not a subscription`);
138
- }
139
- }
140
- // schemas
141
- // =
142
- addLexicon(doc) {
143
- this.lex.add(doc);
144
- }
145
- addLexicons(docs) {
146
- for (const doc of docs) {
147
- this.addLexicon(doc);
148
- }
149
- }
150
- // http
151
- // =
152
- async addRoute(nsid, def, config) {
153
- const verb = def.type === 'procedure' ? 'post' : 'get';
154
- const middleware = [];
155
- middleware.push(createLocalsMiddleware(nsid));
156
- if (config.auth) {
157
- middleware.push(createAuthMiddleware(config.auth));
158
- }
159
- if (verb === 'post') {
160
- middleware.push(this.middleware.json);
161
- middleware.push(this.middleware.text);
162
- }
163
- this.setupRouteRateLimits(nsid, config);
164
- this.routes[verb](`/xrpc/${nsid}`, ...middleware, this.createHandler(nsid, def, config));
165
- }
166
- async catchall(req, _res, next) {
167
- const def = this.lex.getDef(req.params.methodId);
168
- if (!def) {
169
- return next(new types_1.MethodNotImplementedError());
170
- }
171
- // validate method
172
- if (def.type === 'query' && req.method !== 'GET') {
173
- return next(new types_1.InvalidRequestError(`Incorrect HTTP method (${req.method}) expected GET`));
174
- }
175
- else if (def.type === 'procedure' && req.method !== 'POST') {
176
- return next(new types_1.InvalidRequestError(`Incorrect HTTP method (${req.method}) expected POST`));
177
- }
178
- return next();
179
- }
180
- createHandler(nsid, def, routeCfg) {
181
- const routeOpts = {
182
- blobLimit: routeCfg.opts?.blobLimit ?? this.options.payload?.blobLimit,
183
- };
184
- const validateReqInput = (req) => (0, util_1.validateInput)(nsid, def, req, routeOpts, this.lex);
185
- const validateResOutput = this.options.validateResponse === false
186
- ? (output) => output
187
- : (output) => (0, util_1.validateOutput)(nsid, def, output, this.lex);
188
- const assertValidXrpcParams = (params) => this.lex.assertValidXrpcParams(nsid, params);
189
- const rlFns = this.routeRateLimiterFns[nsid] ?? [];
190
- const consumeRateLimit = (reqCtx) => (0, rate_limiter_1.consumeMany)(reqCtx, rlFns);
191
- return async function (req, res, next) {
192
- try {
193
- // validate request
194
- let params = (0, util_1.decodeQueryParams)(def, req.query);
195
- try {
196
- params = assertValidXrpcParams(params);
197
- }
198
- catch (e) {
199
- throw new types_1.InvalidRequestError(String(e));
200
- }
201
- const input = validateReqInput(req);
202
- if (input?.body instanceof stream_1.Readable) {
203
- // If the body stream errors at any time, abort the request
204
- input.body.once('error', next);
205
- }
206
- const locals = req[kRequestLocals];
207
- const reqCtx = {
208
- params,
209
- input,
210
- auth: locals.auth,
211
- req,
212
- res,
213
- };
214
- // handle rate limits
215
- const result = await consumeRateLimit(reqCtx);
216
- if (result instanceof types_1.RateLimitExceededError) {
217
- return next(result);
218
- }
219
- // run the handler
220
- const outputUnvalidated = await routeCfg.handler(reqCtx);
221
- if ((0, types_1.isHandlerError)(outputUnvalidated)) {
222
- throw types_1.XRPCError.fromError(outputUnvalidated);
223
- }
224
- if (outputUnvalidated && isHandlerPipeThrough(outputUnvalidated)) {
225
- // set headers
226
- if (outputUnvalidated?.headers) {
227
- Object.entries(outputUnvalidated.headers).forEach(([name, val]) => {
228
- res.header(name, val);
229
- });
230
- }
231
- res
232
- .header('Content-Type', outputUnvalidated.encoding)
233
- .status(200)
234
- .send(Buffer.from(outputUnvalidated.buffer));
235
- return;
236
- }
237
- if (!outputUnvalidated || isHandlerSuccess(outputUnvalidated)) {
238
- // validate response
239
- const output = validateResOutput(outputUnvalidated);
240
- // set headers
241
- if (output?.headers) {
242
- Object.entries(output.headers).forEach(([name, val]) => {
243
- res.header(name, val);
244
- });
245
- }
246
- // send response
247
- if (output?.encoding === 'application/json' ||
248
- output?.encoding === 'json') {
249
- const json = (0, lexicon_1.lexToJson)(output.body);
250
- res.status(200).json(json);
251
- }
252
- else if (output?.body instanceof stream_1.Readable) {
253
- res.header('Content-Type', output.encoding);
254
- res.status(200);
255
- res.once('error', (err) => res.destroy(err));
256
- (0, common_1.forwardStreamErrors)(output.body, res);
257
- output.body.pipe(res);
258
- }
259
- else if (output) {
260
- res
261
- .header('Content-Type', output.encoding)
262
- .status(200)
263
- .send(output.body instanceof Uint8Array
264
- ? Buffer.from(output.body)
265
- : output.body);
266
- }
267
- else {
268
- res.status(200).end();
269
- }
270
- }
271
- }
272
- catch (err) {
273
- // Express will not call the next middleware (errorMiddleware in this case)
274
- // if the value passed to next is falsy (e.g. null, undefined, 0).
275
- // Hence we replace it with an InternalServerError.
276
- if (!err) {
277
- next(new types_1.InternalServerError());
278
- }
279
- else {
280
- next(err);
281
- }
282
- }
283
- };
284
- }
285
- async addSubscription(nsid, def, config) {
286
- const assertValidXrpcParams = (params) => this.lex.assertValidXrpcParams(nsid, params);
287
- this.subscriptions.set(nsid, new stream_2.XrpcStreamServer({
288
- noServer: true,
289
- handler: async function* (req, signal) {
290
- try {
291
- // authenticate request
292
- const auth = await config.auth?.({ req });
293
- if ((0, types_1.isHandlerError)(auth)) {
294
- throw types_1.XRPCError.fromError(auth);
295
- }
296
- // validate request
297
- let params = (0, util_1.decodeQueryParams)(def, (0, util_1.getQueryParams)(req.url));
298
- try {
299
- params = assertValidXrpcParams(params);
300
- }
301
- catch (e) {
302
- throw new types_1.InvalidRequestError(String(e));
303
- }
304
- // stream
305
- const items = config.handler({ req, params, auth, signal });
306
- for await (const item of items) {
307
- if (item instanceof stream_2.Frame) {
308
- yield item;
309
- continue;
310
- }
311
- const type = item?.['$type'];
312
- if (!common_1.check.is(item, common_1.schema.map) || typeof type !== 'string') {
313
- yield new stream_2.MessageFrame(item);
314
- continue;
315
- }
316
- const split = type.split('#');
317
- let t;
318
- if (split.length === 2 &&
319
- (split[0] === '' || split[0] === nsid)) {
320
- t = `#${split[1]}`;
321
- }
322
- else {
323
- t = type;
324
- }
325
- const clone = { ...item };
326
- delete clone['$type'];
327
- yield new stream_2.MessageFrame(clone, { type: t });
328
- }
329
- }
330
- catch (err) {
331
- const xrpcErrPayload = types_1.XRPCError.fromError(err).payload;
332
- yield new stream_2.ErrorFrame({
333
- error: xrpcErrPayload.error ?? 'Unknown',
334
- message: xrpcErrPayload.message,
335
- });
336
- }
337
- },
338
- }));
339
- }
340
- enableStreamingOnListen(app) {
341
- const _listen = app.listen;
342
- app.listen = (...args) => {
343
- // @ts-ignore the args spread
344
- const httpServer = _listen.call(app, ...args);
345
- httpServer.on('upgrade', (req, socket, head) => {
346
- const url = new URL(req.url || '', 'http://x');
347
- const sub = url.pathname.startsWith('/xrpc/')
348
- ? this.subscriptions.get(url.pathname.replace('/xrpc/', ''))
349
- : undefined;
350
- if (!sub)
351
- return socket.destroy();
352
- sub.wss.handleUpgrade(req, socket, head, (ws) => sub.wss.emit('connection', ws, req));
353
- });
354
- return httpServer;
355
- };
356
- }
357
- setupRouteRateLimits(nsid, config) {
358
- this.routeRateLimiterFns[nsid] = [];
359
- for (const limit of this.globalRateLimiters) {
360
- const consumeFn = async (ctx) => {
361
- return limit.consume(ctx);
362
- };
363
- this.routeRateLimiterFns[nsid].push(consumeFn);
364
- }
365
- if (config.rateLimit) {
366
- const limits = Array.isArray(config.rateLimit)
367
- ? config.rateLimit
368
- : [config.rateLimit];
369
- this.routeRateLimiterFns[nsid] = [];
370
- for (let i = 0; i < limits.length; i++) {
371
- const limit = limits[i];
372
- const { calcKey, calcPoints } = limit;
373
- if ((0, types_1.isShared)(limit)) {
374
- const rateLimiter = this.sharedRateLimiters[limit.name];
375
- if (rateLimiter) {
376
- const consumeFn = (ctx) => rateLimiter.consume(ctx, {
377
- calcKey,
378
- calcPoints,
379
- });
380
- this.routeRateLimiterFns[nsid].push(consumeFn);
381
- }
382
- }
383
- else {
384
- const { durationMs, points } = limit;
385
- const rateLimiter = this.options.rateLimits?.creator({
386
- keyPrefix: `nsid-${i}`,
387
- durationMs,
388
- points,
389
- calcKey,
390
- calcPoints,
391
- });
392
- if (rateLimiter) {
393
- this.sharedRateLimiters[nsid] = rateLimiter;
394
- const consumeFn = (ctx) => rateLimiter.consume(ctx, {
395
- calcKey,
396
- calcPoints,
397
- });
398
- this.routeRateLimiterFns[nsid].push(consumeFn);
399
- }
400
- }
401
- }
402
- }
403
- }
404
- }
405
- exports.Server = Server;
406
- function isHandlerSuccess(v) {
407
- return types_1.handlerSuccess.safeParse(v).success;
408
- }
409
- function isHandlerPipeThrough(v) {
410
- if (v === null || typeof v !== 'object') {
411
- return false;
412
- }
413
- if (!isString(v['encoding']) || !(v['buffer'] instanceof ArrayBuffer)) {
414
- return false;
415
- }
416
- if (v['headers'] !== undefined) {
417
- if (v['headers'] === null || typeof v['headers'] !== 'object') {
418
- return false;
419
- }
420
- if (!Object.values(v['headers']).every(isString)) {
421
- return false;
422
- }
423
- }
424
- return true;
425
- }
426
- const isString = (val) => typeof val === 'string';
427
- const kRequestLocals = Symbol('requestLocals');
428
- function createLocalsMiddleware(nsid) {
429
- return function (req, _res, next) {
430
- const locals = { auth: undefined, nsid };
431
- req[kRequestLocals] = locals;
432
- return next();
433
- };
434
- }
435
- function createAuthMiddleware(verifier) {
436
- return async function (req, res, next) {
437
- try {
438
- const result = await verifier({ req, res });
439
- if ((0, types_1.isHandlerError)(result)) {
440
- throw types_1.XRPCError.fromError(result);
441
- }
442
- const locals = req[kRequestLocals];
443
- locals.auth = result;
444
- next();
445
- }
446
- catch (err) {
447
- next(err);
448
- }
449
- };
450
- }
451
- const errorMiddleware = function (err, req, res, next) {
452
- const locals = req[kRequestLocals];
453
- const methodSuffix = locals ? ` method ${locals.nsid}` : '';
454
- const xrpcError = types_1.XRPCError.fromError(err);
455
- if (xrpcError instanceof types_1.InternalServerError) {
456
- // log trace for unhandled exceptions
457
- logger_1.default.error(err, `unhandled exception in xrpc${methodSuffix}`);
458
- }
459
- else {
460
- // do not log trace for known xrpc errors
461
- logger_1.default.error({
462
- status: xrpcError.type,
463
- message: xrpcError.message,
464
- name: xrpcError.customErrorName,
465
- }, `error in xrpc${methodSuffix}`);
466
- }
467
- if (res.headersSent) {
468
- return next(err);
469
- }
470
- return res.status(xrpcError.type).json(xrpcError.payload);
471
- };
472
- //# sourceMappingURL=server.js.map