@atproto/xrpc-server 0.4.3 → 0.4.4-next.0
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 +11 -0
- package/dist/auth.d.ts +1 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +124 -0
- package/dist/auth.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -53682
- package/dist/index.js.map +1 -7
- package/dist/logger.d.ts +1 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +7 -0
- package/dist/logger.js.map +1 -0
- package/dist/rate-limiter.d.ts +1 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +166 -0
- package/dist/rate-limiter.js.map +1 -0
- package/dist/server.d.ts +5 -4
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +472 -0
- package/dist/server.js.map +1 -0
- package/dist/stream/frames.d.ts +2 -1
- package/dist/stream/frames.d.ts.map +1 -0
- package/dist/stream/frames.js +141 -0
- package/dist/stream/frames.js.map +1 -0
- package/dist/stream/index.d.ts +1 -0
- package/dist/stream/index.d.ts.map +1 -0
- package/dist/stream/index.js +22 -0
- package/dist/stream/index.js.map +1 -0
- package/dist/stream/logger.d.ts +1 -0
- package/dist/stream/logger.d.ts.map +1 -0
- package/dist/stream/logger.js +7 -0
- package/dist/stream/logger.js.map +1 -0
- package/dist/stream/server.d.ts +2 -0
- package/dist/stream/server.d.ts.map +1 -0
- package/dist/stream/server.js +70 -0
- package/dist/stream/server.js.map +1 -0
- package/dist/stream/stream.d.ts +1 -0
- package/dist/stream/stream.d.ts.map +1 -0
- package/dist/stream/stream.js +44 -0
- package/dist/stream/stream.js.map +1 -0
- package/dist/stream/subscription.d.ts +2 -0
- package/dist/stream/subscription.d.ts.map +1 -0
- package/dist/stream/subscription.js +80 -0
- package/dist/stream/subscription.js.map +1 -0
- package/dist/stream/types.d.ts +1 -0
- package/dist/stream/types.d.ts.map +1 -0
- package/dist/stream/types.js +47 -0
- package/dist/stream/types.js.map +1 -0
- package/dist/stream/websocket-keepalive.d.ts +2 -0
- package/dist/stream/websocket-keepalive.d.ts.map +1 -0
- package/dist/stream/websocket-keepalive.js +160 -0
- package/dist/stream/websocket-keepalive.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +163 -0
- package/dist/types.js.map +1 -0
- package/dist/util.d.ts +1 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +263 -0
- package/dist/util.js.map +1 -0
- package/jest.config.js +4 -3
- package/package.json +10 -11
- package/src/server.ts +11 -11
- package/src/stream/frames.ts +1 -1
- package/src/stream/websocket-keepalive.ts +2 -1
- package/tests/bodies.test.ts +4 -4
- package/tests/errors.test.ts +1 -1
- package/tsconfig.build.json +6 -2
- package/tsconfig.json +3 -11
- package/tsconfig.tests.json +7 -0
- package/babel.config.js +0 -1
- package/build.js +0 -14
package/dist/types.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
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.MethodNotImplementedError = exports.UpstreamTimeoutError = exports.NotEnoughResourcesError = exports.UpstreamFailureError = exports.InternalServerError = exports.RateLimitExceededError = exports.ForbiddenError = exports.AuthRequiredError = exports.InvalidRequestError = exports.isHandlerError = exports.XRPCError = exports.isShared = exports.handlerError = exports.handlerPipeThrough = exports.handlerSuccess = exports.handlerAuth = exports.handlerInput = void 0;
|
|
7
|
+
const http_errors_1 = require("http-errors");
|
|
8
|
+
const zod_1 = __importDefault(require("zod"));
|
|
9
|
+
const xrpc_1 = require("@atproto/xrpc");
|
|
10
|
+
exports.handlerInput = zod_1.default.object({
|
|
11
|
+
encoding: zod_1.default.string(),
|
|
12
|
+
body: zod_1.default.any(),
|
|
13
|
+
});
|
|
14
|
+
exports.handlerAuth = zod_1.default.object({
|
|
15
|
+
credentials: zod_1.default.any(),
|
|
16
|
+
artifacts: zod_1.default.any(),
|
|
17
|
+
});
|
|
18
|
+
exports.handlerSuccess = zod_1.default.object({
|
|
19
|
+
encoding: zod_1.default.string(),
|
|
20
|
+
body: zod_1.default.any(),
|
|
21
|
+
headers: zod_1.default.record(zod_1.default.string()).optional(),
|
|
22
|
+
});
|
|
23
|
+
exports.handlerPipeThrough = zod_1.default.object({
|
|
24
|
+
encoding: zod_1.default.string(),
|
|
25
|
+
buffer: zod_1.default.instanceof(ArrayBuffer),
|
|
26
|
+
headers: zod_1.default.record(zod_1.default.string()).optional(),
|
|
27
|
+
});
|
|
28
|
+
exports.handlerError = zod_1.default.object({
|
|
29
|
+
status: zod_1.default.number(),
|
|
30
|
+
error: zod_1.default.string().optional(),
|
|
31
|
+
message: zod_1.default.string().optional(),
|
|
32
|
+
});
|
|
33
|
+
const isShared = (opts) => {
|
|
34
|
+
return typeof opts['name'] === 'string';
|
|
35
|
+
};
|
|
36
|
+
exports.isShared = isShared;
|
|
37
|
+
class XRPCError extends Error {
|
|
38
|
+
constructor(type, errorMessage, customErrorName) {
|
|
39
|
+
super(errorMessage);
|
|
40
|
+
Object.defineProperty(this, "type", {
|
|
41
|
+
enumerable: true,
|
|
42
|
+
configurable: true,
|
|
43
|
+
writable: true,
|
|
44
|
+
value: type
|
|
45
|
+
});
|
|
46
|
+
Object.defineProperty(this, "errorMessage", {
|
|
47
|
+
enumerable: true,
|
|
48
|
+
configurable: true,
|
|
49
|
+
writable: true,
|
|
50
|
+
value: errorMessage
|
|
51
|
+
});
|
|
52
|
+
Object.defineProperty(this, "customErrorName", {
|
|
53
|
+
enumerable: true,
|
|
54
|
+
configurable: true,
|
|
55
|
+
writable: true,
|
|
56
|
+
value: customErrorName
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
get payload() {
|
|
60
|
+
return {
|
|
61
|
+
error: this.customErrorName ?? this.typeName,
|
|
62
|
+
message: this.type === xrpc_1.ResponseType.InternalServerError
|
|
63
|
+
? this.typeStr // Do not respond with error details for 500s
|
|
64
|
+
: this.errorMessage || this.typeStr,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
get typeName() {
|
|
68
|
+
return xrpc_1.ResponseTypeNames[this.type];
|
|
69
|
+
}
|
|
70
|
+
get typeStr() {
|
|
71
|
+
return xrpc_1.ResponseTypeStrings[this.type];
|
|
72
|
+
}
|
|
73
|
+
static fromError(error) {
|
|
74
|
+
if (error instanceof XRPCError) {
|
|
75
|
+
return error;
|
|
76
|
+
}
|
|
77
|
+
let resultErr;
|
|
78
|
+
if ((0, http_errors_1.isHttpError)(error)) {
|
|
79
|
+
resultErr = new XRPCError(error.status, error.message, error.name);
|
|
80
|
+
}
|
|
81
|
+
else if (isHandlerError(error)) {
|
|
82
|
+
resultErr = new XRPCError(error.status, error.message, error.error);
|
|
83
|
+
}
|
|
84
|
+
else if (error instanceof Error) {
|
|
85
|
+
resultErr = new InternalServerError(error.message);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
resultErr = new InternalServerError('Unexpected internal server error');
|
|
89
|
+
}
|
|
90
|
+
resultErr.cause = error;
|
|
91
|
+
return resultErr;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.XRPCError = XRPCError;
|
|
95
|
+
function isHandlerError(v) {
|
|
96
|
+
return (!!v &&
|
|
97
|
+
typeof v === 'object' &&
|
|
98
|
+
typeof v['status'] === 'number' &&
|
|
99
|
+
(v['error'] === undefined || typeof v['error'] === 'string') &&
|
|
100
|
+
(v['message'] === undefined || typeof v['message'] === 'string'));
|
|
101
|
+
}
|
|
102
|
+
exports.isHandlerError = isHandlerError;
|
|
103
|
+
class InvalidRequestError extends XRPCError {
|
|
104
|
+
constructor(errorMessage, customErrorName) {
|
|
105
|
+
super(xrpc_1.ResponseType.InvalidRequest, errorMessage, customErrorName);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
exports.InvalidRequestError = InvalidRequestError;
|
|
109
|
+
class AuthRequiredError extends XRPCError {
|
|
110
|
+
constructor(errorMessage, customErrorName) {
|
|
111
|
+
super(xrpc_1.ResponseType.AuthRequired, errorMessage, customErrorName);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
exports.AuthRequiredError = AuthRequiredError;
|
|
115
|
+
class ForbiddenError extends XRPCError {
|
|
116
|
+
constructor(errorMessage, customErrorName) {
|
|
117
|
+
super(xrpc_1.ResponseType.Forbidden, errorMessage, customErrorName);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
exports.ForbiddenError = ForbiddenError;
|
|
121
|
+
class RateLimitExceededError extends XRPCError {
|
|
122
|
+
constructor(status, errorMessage, customErrorName) {
|
|
123
|
+
super(xrpc_1.ResponseType.RateLimitExceeded, errorMessage, customErrorName);
|
|
124
|
+
Object.defineProperty(this, "status", {
|
|
125
|
+
enumerable: true,
|
|
126
|
+
configurable: true,
|
|
127
|
+
writable: true,
|
|
128
|
+
value: status
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
exports.RateLimitExceededError = RateLimitExceededError;
|
|
133
|
+
class InternalServerError extends XRPCError {
|
|
134
|
+
constructor(errorMessage, customErrorName) {
|
|
135
|
+
super(xrpc_1.ResponseType.InternalServerError, errorMessage, customErrorName);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
exports.InternalServerError = InternalServerError;
|
|
139
|
+
class UpstreamFailureError extends XRPCError {
|
|
140
|
+
constructor(errorMessage, customErrorName) {
|
|
141
|
+
super(xrpc_1.ResponseType.UpstreamFailure, errorMessage, customErrorName);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
exports.UpstreamFailureError = UpstreamFailureError;
|
|
145
|
+
class NotEnoughResourcesError extends XRPCError {
|
|
146
|
+
constructor(errorMessage, customErrorName) {
|
|
147
|
+
super(xrpc_1.ResponseType.NotEnoughResources, errorMessage, customErrorName);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
exports.NotEnoughResourcesError = NotEnoughResourcesError;
|
|
151
|
+
class UpstreamTimeoutError extends XRPCError {
|
|
152
|
+
constructor(errorMessage, customErrorName) {
|
|
153
|
+
super(xrpc_1.ResponseType.UpstreamTimeout, errorMessage, customErrorName);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
exports.UpstreamTimeoutError = UpstreamTimeoutError;
|
|
157
|
+
class MethodNotImplementedError extends XRPCError {
|
|
158
|
+
constructor(errorMessage, customErrorName) {
|
|
159
|
+
super(xrpc_1.ResponseType.MethodNotImplemented, errorMessage, customErrorName);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
exports.MethodNotImplementedError = MethodNotImplementedError;
|
|
163
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/util.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAGA,OAAO,OAAO,MAAM,SAAS,CAAA;AAE7B,OAAO,EAEL,QAAQ,EACR,gBAAgB,EAChB,YAAY,EACZ,mBAAmB,EACpB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EACL,eAAe,EACf,MAAM,EACN,YAAY,EACZ,cAAc,EAKd,SAAS,EACV,MAAM,SAAS,CAAA;AAEhB,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,gBAAgB,GAAG,YAAY,GAAG,mBAAmB,EAC1D,MAAM,EAAE,eAAe,GACtB,MAAM,CAmBR;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,GACb,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAcvC;AAED,wBAAgB,cAAc,CAAC,GAAG,SAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAU1E;AAED,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,gBAAgB,GAAG,YAAY,EACpC,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,QAAQ,GACjB,YAAY,GAAG,SAAS,CA8D1B;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,gBAAgB,GAAG,YAAY,EACpC,MAAM,EAAE,cAAc,GAAG,SAAS,EAClC,QAAQ,EAAE,QAAQ,GACjB,cAAc,GAAG,SAAS,CA0C5B;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,OAOtC;AAUD,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,6BAI3C;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAM5E;AA0CD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,EAAE,UASzD;AAED,qBAAa,WAAY,YAAW,YAAY;IAG3B,IAAI,EAAE,MAAM;IAAS,WAAW,CAAC;IAF7C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACxB,OAAO,CAAC,OAAO,CAAC,CAAQ;gBACL,IAAI,EAAE,MAAM,EAAS,WAAW,CAAC,oBAAQ;IAC5D,KAAK;IAIL,IAAI;CAKL;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB"}
|
package/dist/util.js
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
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.ServerTimer = exports.serverTimingHeader = exports.processBodyAsBytes = exports.hasBody = exports.normalizeMime = exports.validateOutput = exports.validateInput = exports.getQueryParams = exports.decodeQueryParam = exports.decodeQueryParams = void 0;
|
|
7
|
+
const assert_1 = __importDefault(require("assert"));
|
|
8
|
+
const zlib_1 = require("zlib");
|
|
9
|
+
const mime_types_1 = __importDefault(require("mime-types"));
|
|
10
|
+
const lexicon_1 = require("@atproto/lexicon");
|
|
11
|
+
const common_1 = require("@atproto/common");
|
|
12
|
+
const types_1 = require("./types");
|
|
13
|
+
function decodeQueryParams(def, params) {
|
|
14
|
+
const decoded = {};
|
|
15
|
+
for (const k in params) {
|
|
16
|
+
const val = params[k];
|
|
17
|
+
const property = def.parameters?.properties?.[k];
|
|
18
|
+
if (property) {
|
|
19
|
+
if (property.type === 'array') {
|
|
20
|
+
const vals = [];
|
|
21
|
+
decoded[k] = val
|
|
22
|
+
? vals
|
|
23
|
+
.concat(val) // Cast to array
|
|
24
|
+
.flatMap((v) => decodeQueryParam(property.items.type, v) ?? [])
|
|
25
|
+
: undefined;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
decoded[k] = decodeQueryParam(property.type, val);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return decoded;
|
|
33
|
+
}
|
|
34
|
+
exports.decodeQueryParams = decodeQueryParams;
|
|
35
|
+
function decodeQueryParam(type, value) {
|
|
36
|
+
if (!value) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
if (type === 'string' || type === 'datetime') {
|
|
40
|
+
return String(value);
|
|
41
|
+
}
|
|
42
|
+
if (type === 'float') {
|
|
43
|
+
return Number(String(value));
|
|
44
|
+
}
|
|
45
|
+
else if (type === 'integer') {
|
|
46
|
+
return parseInt(String(value), 10) || 0;
|
|
47
|
+
}
|
|
48
|
+
else if (type === 'boolean') {
|
|
49
|
+
return value === 'true';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.decodeQueryParam = decodeQueryParam;
|
|
53
|
+
function getQueryParams(url = '') {
|
|
54
|
+
const { searchParams } = new URL(url ?? '', 'http://x');
|
|
55
|
+
const result = {};
|
|
56
|
+
for (const key of searchParams.keys()) {
|
|
57
|
+
result[key] = searchParams.getAll(key);
|
|
58
|
+
if (result[key].length === 1) {
|
|
59
|
+
result[key] = result[key][0];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
exports.getQueryParams = getQueryParams;
|
|
65
|
+
function validateInput(nsid, def, req, opts, lexicons) {
|
|
66
|
+
// request expectation
|
|
67
|
+
const reqHasBody = hasBody(req);
|
|
68
|
+
if (reqHasBody && (def.type !== 'procedure' || !def.input)) {
|
|
69
|
+
throw new types_1.InvalidRequestError(`A request body was provided when none was expected`);
|
|
70
|
+
}
|
|
71
|
+
if (def.type === 'query') {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (!reqHasBody && def.input) {
|
|
75
|
+
throw new types_1.InvalidRequestError(`A request body is expected but none was provided`);
|
|
76
|
+
}
|
|
77
|
+
// mimetype
|
|
78
|
+
const inputEncoding = normalizeMime(req.headers['content-type'] || '');
|
|
79
|
+
if (def.input?.encoding &&
|
|
80
|
+
(!inputEncoding || !isValidEncoding(def.input?.encoding, inputEncoding))) {
|
|
81
|
+
if (!inputEncoding) {
|
|
82
|
+
throw new types_1.InvalidRequestError(`Request encoding (Content-Type) required but not provided`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
throw new types_1.InvalidRequestError(`Wrong request encoding (Content-Type): ${inputEncoding}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (!inputEncoding) {
|
|
89
|
+
// no input body
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
// if input schema, validate
|
|
93
|
+
if (def.input?.schema) {
|
|
94
|
+
try {
|
|
95
|
+
const lexBody = req.body ? (0, lexicon_1.jsonToLex)(req.body) : req.body;
|
|
96
|
+
req.body = lexicons.assertValidXrpcInput(nsid, lexBody);
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
throw new types_1.InvalidRequestError(e instanceof Error ? e.message : String(e));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// if middleware already got the body, we pass that along as input
|
|
103
|
+
// otherwise, we pass along a decoded readable stream
|
|
104
|
+
let body;
|
|
105
|
+
if (req.readableEnded) {
|
|
106
|
+
body = req.body;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
body = decodeBodyStream(req, opts.blobLimit);
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
encoding: inputEncoding,
|
|
113
|
+
body,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
exports.validateInput = validateInput;
|
|
117
|
+
function validateOutput(nsid, def, output, lexicons) {
|
|
118
|
+
// initial validation
|
|
119
|
+
if (output) {
|
|
120
|
+
types_1.handlerSuccess.parse(output);
|
|
121
|
+
}
|
|
122
|
+
// response expectation
|
|
123
|
+
if (output?.body && !def.output) {
|
|
124
|
+
throw new types_1.InternalServerError(`A response body was provided when none was expected`);
|
|
125
|
+
}
|
|
126
|
+
if (!output?.body && def.output) {
|
|
127
|
+
throw new types_1.InternalServerError(`A response body is expected but none was provided`);
|
|
128
|
+
}
|
|
129
|
+
// mimetype
|
|
130
|
+
if (def.output?.encoding &&
|
|
131
|
+
(!output?.encoding ||
|
|
132
|
+
!isValidEncoding(def.output?.encoding, output?.encoding))) {
|
|
133
|
+
throw new types_1.InternalServerError(`Invalid response encoding: ${output?.encoding}`);
|
|
134
|
+
}
|
|
135
|
+
// output schema
|
|
136
|
+
if (def.output?.schema) {
|
|
137
|
+
try {
|
|
138
|
+
const result = lexicons.assertValidXrpcOutput(nsid, output?.body);
|
|
139
|
+
if (output) {
|
|
140
|
+
output.body = result;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
throw new types_1.InternalServerError(e instanceof Error ? e.message : String(e));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return output;
|
|
148
|
+
}
|
|
149
|
+
exports.validateOutput = validateOutput;
|
|
150
|
+
function normalizeMime(v) {
|
|
151
|
+
if (!v)
|
|
152
|
+
return false;
|
|
153
|
+
const fullType = mime_types_1.default.contentType(v);
|
|
154
|
+
if (!fullType)
|
|
155
|
+
return false;
|
|
156
|
+
const shortType = fullType.split(';')[0];
|
|
157
|
+
if (!shortType)
|
|
158
|
+
return false;
|
|
159
|
+
return shortType;
|
|
160
|
+
}
|
|
161
|
+
exports.normalizeMime = normalizeMime;
|
|
162
|
+
function isValidEncoding(possibleStr, value) {
|
|
163
|
+
const possible = possibleStr.split(',').map((v) => v.trim());
|
|
164
|
+
const normalized = normalizeMime(value);
|
|
165
|
+
if (!normalized)
|
|
166
|
+
return false;
|
|
167
|
+
if (possible.includes('*/*'))
|
|
168
|
+
return true;
|
|
169
|
+
return possible.includes(normalized);
|
|
170
|
+
}
|
|
171
|
+
function hasBody(req) {
|
|
172
|
+
const contentLength = req.headers['content-length'];
|
|
173
|
+
const transferEncoding = req.headers['transfer-encoding'];
|
|
174
|
+
return (contentLength && parseInt(contentLength, 10) > 0) || transferEncoding;
|
|
175
|
+
}
|
|
176
|
+
exports.hasBody = hasBody;
|
|
177
|
+
function processBodyAsBytes(req) {
|
|
178
|
+
return new Promise((resolve) => {
|
|
179
|
+
const chunks = [];
|
|
180
|
+
req.on('data', (chunk) => chunks.push(chunk));
|
|
181
|
+
req.on('end', () => resolve(new Uint8Array(Buffer.concat(chunks))));
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
exports.processBodyAsBytes = processBodyAsBytes;
|
|
185
|
+
function decodeBodyStream(req, maxSize) {
|
|
186
|
+
let stream = req;
|
|
187
|
+
const contentEncoding = req.headers['content-encoding'];
|
|
188
|
+
const contentLength = req.headers['content-length'];
|
|
189
|
+
if (maxSize !== undefined &&
|
|
190
|
+
contentLength &&
|
|
191
|
+
parseInt(contentLength, 10) > maxSize) {
|
|
192
|
+
throw new types_1.XRPCError(413, 'request entity too large');
|
|
193
|
+
}
|
|
194
|
+
let decoder;
|
|
195
|
+
if (contentEncoding === 'gzip') {
|
|
196
|
+
decoder = (0, zlib_1.createGunzip)();
|
|
197
|
+
}
|
|
198
|
+
else if (contentEncoding === 'deflate') {
|
|
199
|
+
decoder = (0, zlib_1.createDeflate)();
|
|
200
|
+
}
|
|
201
|
+
if (decoder) {
|
|
202
|
+
(0, common_1.forwardStreamErrors)(stream, decoder);
|
|
203
|
+
stream = stream.pipe(decoder);
|
|
204
|
+
}
|
|
205
|
+
if (maxSize !== undefined) {
|
|
206
|
+
const maxSizeChecker = new common_1.MaxSizeChecker(maxSize, () => new types_1.XRPCError(413, 'request entity too large'));
|
|
207
|
+
(0, common_1.forwardStreamErrors)(stream, maxSizeChecker);
|
|
208
|
+
stream = stream.pipe(maxSizeChecker);
|
|
209
|
+
}
|
|
210
|
+
return stream;
|
|
211
|
+
}
|
|
212
|
+
function serverTimingHeader(timings) {
|
|
213
|
+
return timings
|
|
214
|
+
.map((timing) => {
|
|
215
|
+
let header = timing.name;
|
|
216
|
+
if (timing.duration)
|
|
217
|
+
header += `;dur=${timing.duration}`;
|
|
218
|
+
if (timing.description)
|
|
219
|
+
header += `;desc="${timing.description}"`;
|
|
220
|
+
return header;
|
|
221
|
+
})
|
|
222
|
+
.join(', ');
|
|
223
|
+
}
|
|
224
|
+
exports.serverTimingHeader = serverTimingHeader;
|
|
225
|
+
class ServerTimer {
|
|
226
|
+
constructor(name, description) {
|
|
227
|
+
Object.defineProperty(this, "name", {
|
|
228
|
+
enumerable: true,
|
|
229
|
+
configurable: true,
|
|
230
|
+
writable: true,
|
|
231
|
+
value: name
|
|
232
|
+
});
|
|
233
|
+
Object.defineProperty(this, "description", {
|
|
234
|
+
enumerable: true,
|
|
235
|
+
configurable: true,
|
|
236
|
+
writable: true,
|
|
237
|
+
value: description
|
|
238
|
+
});
|
|
239
|
+
Object.defineProperty(this, "duration", {
|
|
240
|
+
enumerable: true,
|
|
241
|
+
configurable: true,
|
|
242
|
+
writable: true,
|
|
243
|
+
value: void 0
|
|
244
|
+
});
|
|
245
|
+
Object.defineProperty(this, "startMs", {
|
|
246
|
+
enumerable: true,
|
|
247
|
+
configurable: true,
|
|
248
|
+
writable: true,
|
|
249
|
+
value: void 0
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
start() {
|
|
253
|
+
this.startMs = Date.now();
|
|
254
|
+
return this;
|
|
255
|
+
}
|
|
256
|
+
stop() {
|
|
257
|
+
(0, assert_1.default)(this.startMs, "timer hasn't been started");
|
|
258
|
+
this.duration = Date.now() - this.startMs;
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
exports.ServerTimer = ServerTimer;
|
|
263
|
+
//# sourceMappingURL=util.js.map
|
package/dist/util.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
|
package/jest.config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/** @type {import('jest').Config} */
|
|
3
2
|
module.exports = {
|
|
4
|
-
...base,
|
|
5
3
|
displayName: 'XRPC Server',
|
|
4
|
+
transform: { '^.+\\.(t|j)s$': '@swc/jest' },
|
|
5
|
+
transformIgnorePatterns: [`<rootDir>/node_modules/(?!get-port)`],
|
|
6
|
+
setupFiles: ['<rootDir>/../../jest.setup.ts'],
|
|
6
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/xrpc-server",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4-next.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "atproto HTTP API (XRPC) server library",
|
|
6
6
|
"keywords": [
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"directory": "packages/xrpc-server"
|
|
15
15
|
},
|
|
16
16
|
"main": "dist/index.js",
|
|
17
|
+
"types": "dist/index.d.ts",
|
|
17
18
|
"dependencies": {
|
|
18
19
|
"cbor-x": "^1.5.1",
|
|
19
20
|
"express": "^4.17.2",
|
|
@@ -23,9 +24,9 @@
|
|
|
23
24
|
"uint8arrays": "3.0.0",
|
|
24
25
|
"ws": "^8.12.0",
|
|
25
26
|
"zod": "^3.21.4",
|
|
26
|
-
"@atproto/common": "^0.3.
|
|
27
|
-
"@atproto/
|
|
28
|
-
"@atproto/
|
|
27
|
+
"@atproto/common": "^0.3.4-next.0",
|
|
28
|
+
"@atproto/lexicon": "^0.3.3-next.0",
|
|
29
|
+
"@atproto/crypto": "^0.3.1-next.0"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
32
|
"@types/express": "^4.17.13",
|
|
@@ -34,16 +35,14 @@
|
|
|
34
35
|
"@types/ws": "^8.5.4",
|
|
35
36
|
"get-port": "^6.1.2",
|
|
36
37
|
"jose": "^4.15.4",
|
|
38
|
+
"jest": "^28.1.2",
|
|
37
39
|
"key-encoder": "^2.0.3",
|
|
38
40
|
"multiformats": "^9.9.0",
|
|
39
|
-
"@atproto/
|
|
40
|
-
"@atproto/
|
|
41
|
+
"@atproto/crypto": "^0.3.1-next.0",
|
|
42
|
+
"@atproto/xrpc": "^0.4.3-next.0"
|
|
41
43
|
},
|
|
42
44
|
"scripts": {
|
|
43
45
|
"test": "jest",
|
|
44
|
-
"build": "
|
|
45
|
-
|
|
46
|
-
"update-main-to-dist": "node ../../update-main-to-dist.js packages/xrpc-server"
|
|
47
|
-
},
|
|
48
|
-
"types": "dist/index.d.ts"
|
|
46
|
+
"build": "tsc --build tsconfig.build.json"
|
|
47
|
+
}
|
|
49
48
|
}
|
package/src/server.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Readable } from 'stream'
|
|
2
2
|
import express, {
|
|
3
|
+
Application,
|
|
4
|
+
Express,
|
|
5
|
+
Router,
|
|
6
|
+
Request,
|
|
7
|
+
Response,
|
|
3
8
|
ErrorRequestHandler,
|
|
4
9
|
NextFunction,
|
|
5
10
|
RequestHandler,
|
|
@@ -37,7 +42,6 @@ import {
|
|
|
37
42
|
isShared,
|
|
38
43
|
RateLimitExceededError,
|
|
39
44
|
HandlerPipeThrough,
|
|
40
|
-
handlerPipeThrough,
|
|
41
45
|
} from './types'
|
|
42
46
|
import {
|
|
43
47
|
decodeQueryParams,
|
|
@@ -53,8 +57,8 @@ export function createServer(lexicons?: LexiconDoc[], options?: Options) {
|
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
export class Server {
|
|
56
|
-
router = express()
|
|
57
|
-
routes = express.Router()
|
|
60
|
+
router: Express = express()
|
|
61
|
+
routes: Router = express.Router()
|
|
58
62
|
subscriptions = new Map<string, XrpcStreamServer>()
|
|
59
63
|
lex = new Lexicons()
|
|
60
64
|
options: Options
|
|
@@ -70,7 +74,7 @@ export class Server {
|
|
|
70
74
|
this.router.use(this.routes)
|
|
71
75
|
this.router.use('/xrpc/:methodId', this.catchall.bind(this))
|
|
72
76
|
this.router.use(errorMiddleware)
|
|
73
|
-
this.router.once('mount', (app:
|
|
77
|
+
this.router.once('mount', (app: Application) => {
|
|
74
78
|
this.enableStreamingOnListen(app)
|
|
75
79
|
})
|
|
76
80
|
this.options = opts ?? {}
|
|
@@ -179,11 +183,7 @@ export class Server {
|
|
|
179
183
|
)
|
|
180
184
|
}
|
|
181
185
|
|
|
182
|
-
async catchall(
|
|
183
|
-
req: express.Request,
|
|
184
|
-
_res: express.Response,
|
|
185
|
-
next: NextFunction,
|
|
186
|
-
) {
|
|
186
|
+
async catchall(req: Request, _res: Response, next: NextFunction) {
|
|
187
187
|
const def = this.lex.getDef(req.params.methodId)
|
|
188
188
|
if (!def) {
|
|
189
189
|
return next(new MethodNotImplementedError())
|
|
@@ -213,7 +213,7 @@ export class Server {
|
|
|
213
213
|
const routeOpts = {
|
|
214
214
|
blobLimit: routeCfg.opts?.blobLimit ?? this.options.payload?.blobLimit,
|
|
215
215
|
}
|
|
216
|
-
const validateReqInput = (req:
|
|
216
|
+
const validateReqInput = (req: Request) =>
|
|
217
217
|
validateInput(nsid, def, req, routeOpts, this.lex)
|
|
218
218
|
const validateResOutput =
|
|
219
219
|
this.options.validateResponse === false
|
|
@@ -390,7 +390,7 @@ export class Server {
|
|
|
390
390
|
)
|
|
391
391
|
}
|
|
392
392
|
|
|
393
|
-
private enableStreamingOnListen(app:
|
|
393
|
+
private enableStreamingOnListen(app: Application) {
|
|
394
394
|
const _listen = app.listen
|
|
395
395
|
app.listen = (...args) => {
|
|
396
396
|
// @ts-ignore the args spread
|
package/src/stream/frames.ts
CHANGED
|
@@ -80,7 +80,7 @@ export class WebSocketKeepAlive {
|
|
|
80
80
|
|
|
81
81
|
startHeartbeat(ws: WebSocket) {
|
|
82
82
|
let isAlive = true
|
|
83
|
-
let heartbeatInterval: NodeJS.
|
|
83
|
+
let heartbeatInterval: NodeJS.Timeout | null = null
|
|
84
84
|
|
|
85
85
|
const checkAlive = () => {
|
|
86
86
|
if (!isAlive) {
|
|
@@ -145,6 +145,7 @@ function forwardSignal(signal: AbortSignal, ac: AbortController) {
|
|
|
145
145
|
return ac.abort(signal.reason)
|
|
146
146
|
} else {
|
|
147
147
|
signal.addEventListener('abort', () => ac.abort(signal.reason), {
|
|
148
|
+
// @ts-ignore https://github.com/DefinitelyTyped/DefinitelyTyped/pull/68625
|
|
148
149
|
signal: ac.signal,
|
|
149
150
|
})
|
|
150
151
|
}
|
package/tests/bodies.test.ts
CHANGED
|
@@ -274,9 +274,9 @@ describe('Bodies', () => {
|
|
|
274
274
|
const resBody = await res.json()
|
|
275
275
|
const status = res.status
|
|
276
276
|
expect(status).toBe(400)
|
|
277
|
-
expect(resBody
|
|
278
|
-
|
|
279
|
-
'Request encoding (Content-Type) required but not provided',
|
|
280
|
-
)
|
|
277
|
+
expect(resBody).toMatchObject({
|
|
278
|
+
error: 'InvalidRequest',
|
|
279
|
+
message: 'Request encoding (Content-Type) required but not provided',
|
|
280
|
+
})
|
|
281
281
|
})
|
|
282
282
|
})
|
package/tests/errors.test.ts
CHANGED