@atcute/xrpc-server 0.1.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/LICENSE +17 -0
- package/README.md +177 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.js +3 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/jwt-creator.d.ts +11 -0
- package/dist/auth/jwt-creator.js +30 -0
- package/dist/auth/jwt-creator.js.map +1 -0
- package/dist/auth/jwt-verifier.d.ts +23 -0
- package/dist/auth/jwt-verifier.js +173 -0
- package/dist/auth/jwt-verifier.js.map +1 -0
- package/dist/auth/jwt.d.ts +27 -0
- package/dist/auth/jwt.js +96 -0
- package/dist/auth/jwt.js.map +1 -0
- package/dist/auth/types.d.ts +4 -0
- package/dist/auth/types.js +2 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/main/index.d.ts +3 -0
- package/dist/main/index.js +4 -0
- package/dist/main/index.js.map +1 -0
- package/dist/main/response.d.ts +8 -0
- package/dist/main/response.js +4 -0
- package/dist/main/response.js.map +1 -0
- package/dist/main/router.d.ts +21 -0
- package/dist/main/router.js +158 -0
- package/dist/main/router.js.map +1 -0
- package/dist/main/types/operation.d.ts +36 -0
- package/dist/main/types/operation.js +2 -0
- package/dist/main/types/operation.js.map +1 -0
- package/dist/main/utils/middlewares.d.ts +2 -0
- package/dist/main/utils/middlewares.js +5 -0
- package/dist/main/utils/middlewares.js.map +1 -0
- package/dist/main/utils/request-input.d.ts +3 -0
- package/dist/main/utils/request-input.js +50 -0
- package/dist/main/utils/request-input.js.map +1 -0
- package/dist/main/utils/request-params.d.ts +5 -0
- package/dist/main/utils/request-params.js +80 -0
- package/dist/main/utils/request-params.js.map +1 -0
- package/dist/main/utils/response.d.ts +3 -0
- package/dist/main/utils/response.js +8 -0
- package/dist/main/utils/response.js.map +1 -0
- package/dist/main/xrpc-error.d.ts +39 -0
- package/dist/main/xrpc-error.js +58 -0
- package/dist/main/xrpc-error.js.map +1 -0
- package/dist/middlewares/cors.d.ts +8 -0
- package/dist/middlewares/cors.js +42 -0
- package/dist/middlewares/cors.js.map +1 -0
- package/dist/types/misc.d.ts +9 -0
- package/dist/types/misc.js +2 -0
- package/dist/types/misc.js.map +1 -0
- package/lib/auth/index.ts +2 -0
- package/lib/auth/jwt-creator.ts +51 -0
- package/lib/auth/jwt-verifier.ts +215 -0
- package/lib/auth/jwt.ts +124 -0
- package/lib/auth/types.ts +4 -0
- package/lib/main/index.ts +3 -0
- package/lib/main/response.ts +9 -0
- package/lib/main/router.ts +237 -0
- package/lib/main/types/operation.ts +87 -0
- package/lib/main/utils/middlewares.ts +13 -0
- package/lib/main/utils/request-input.ts +64 -0
- package/lib/main/utils/request-params.ts +108 -0
- package/lib/main/utils/response.ts +14 -0
- package/lib/main/xrpc-error.ts +80 -0
- package/lib/middlewares/cors.ts +68 -0
- package/lib/types/misc.ts +4 -0
- package/package.json +44 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { safeParse } from '@atcute/lexicons/validations';
|
|
2
|
+
import { createAsyncMiddlewareRunner } from './utils/middlewares.js';
|
|
3
|
+
import { constructMimeValidator } from './utils/request-input.js';
|
|
4
|
+
import { constructParamsHandler } from './utils/request-params.js';
|
|
5
|
+
import { invalidRequest, validationError } from './utils/response.js';
|
|
6
|
+
import { XRPCError } from './xrpc-error.js';
|
|
7
|
+
export const defaultExceptionHandler = (error) => {
|
|
8
|
+
if (error instanceof XRPCError) {
|
|
9
|
+
return error.toResponse();
|
|
10
|
+
}
|
|
11
|
+
if (error instanceof Response) {
|
|
12
|
+
return error;
|
|
13
|
+
}
|
|
14
|
+
return Response.json({ error: 'InternalServerError', message: `an exception happened whilst processing this request` }, { status: 500 });
|
|
15
|
+
};
|
|
16
|
+
export const defaultNotFoundHandler = () => {
|
|
17
|
+
return new Response('Not Found', { status: 404 });
|
|
18
|
+
};
|
|
19
|
+
export class XRPCRouter {
|
|
20
|
+
#handlers = {};
|
|
21
|
+
#handleNotFound;
|
|
22
|
+
#handleException;
|
|
23
|
+
fetch;
|
|
24
|
+
constructor({ middlewares = [], handleException = defaultExceptionHandler, handleNotFound = defaultNotFoundHandler, } = {}) {
|
|
25
|
+
this.fetch = createAsyncMiddlewareRunner([...middlewares, (request) => this.#dispatch(request)]);
|
|
26
|
+
this.#handleException = handleException;
|
|
27
|
+
this.#handleNotFound = handleNotFound;
|
|
28
|
+
}
|
|
29
|
+
async #dispatch(request) {
|
|
30
|
+
const url = new URL(request.url);
|
|
31
|
+
const pathname = url.pathname;
|
|
32
|
+
if (!pathname.startsWith('/xrpc/')) {
|
|
33
|
+
return this.#handleNotFound(request);
|
|
34
|
+
}
|
|
35
|
+
const nsid = pathname.slice('/xrpc/'.length);
|
|
36
|
+
const route = this.#handlers[nsid];
|
|
37
|
+
if (route === undefined) {
|
|
38
|
+
return this.#handleNotFound(request);
|
|
39
|
+
}
|
|
40
|
+
if (request.method !== route.method) {
|
|
41
|
+
return Response.json({ error: 'InvalidHttpMethod', message: `invalid http method (expected ${route.method})` }, { status: 405, headers: { allow: `${route.method}` } });
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const response = await route.handler({
|
|
45
|
+
request: request,
|
|
46
|
+
url: url,
|
|
47
|
+
});
|
|
48
|
+
return response;
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
return this.#handleException(err, request);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
add(operation, config) {
|
|
55
|
+
switch (operation.type) {
|
|
56
|
+
case 'xrpc_query': {
|
|
57
|
+
return this.#addQuery(operation, config);
|
|
58
|
+
}
|
|
59
|
+
case 'xrpc_procedure': {
|
|
60
|
+
return this.#addProcedure(operation, config);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
#addQuery(query, config) {
|
|
65
|
+
const handleParams = query.params ? constructParamsHandler(query.params) : null;
|
|
66
|
+
const handler = config.handler;
|
|
67
|
+
this.#handlers[query.nsid] = {
|
|
68
|
+
method: 'GET',
|
|
69
|
+
handler: async ({ request, url }) => {
|
|
70
|
+
let params;
|
|
71
|
+
if (handleParams !== null) {
|
|
72
|
+
const result = handleParams(url.searchParams);
|
|
73
|
+
if (!result.ok) {
|
|
74
|
+
return validationError('params', result);
|
|
75
|
+
}
|
|
76
|
+
params = result.value;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
params = {};
|
|
80
|
+
}
|
|
81
|
+
const context = {
|
|
82
|
+
request: request,
|
|
83
|
+
params: params,
|
|
84
|
+
};
|
|
85
|
+
const output = await handler(context);
|
|
86
|
+
if (output instanceof Response) {
|
|
87
|
+
return output;
|
|
88
|
+
}
|
|
89
|
+
return new Response(null);
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
#addProcedure(procedure, config) {
|
|
94
|
+
const handleParams = procedure.params ? constructParamsHandler(procedure.params) : null;
|
|
95
|
+
const validateInputType = procedure.input ? constructMimeValidator(procedure.input) : null;
|
|
96
|
+
const requiresInput = procedure.input !== null;
|
|
97
|
+
const inputSchema = procedure.input?.type === 'lex' ? procedure.input.schema : null;
|
|
98
|
+
const handler = config.handler;
|
|
99
|
+
this.#handlers[procedure.nsid] = {
|
|
100
|
+
method: 'POST',
|
|
101
|
+
handler: async ({ request, url }) => {
|
|
102
|
+
let params;
|
|
103
|
+
let input;
|
|
104
|
+
if (handleParams !== null) {
|
|
105
|
+
const result = handleParams(url.searchParams);
|
|
106
|
+
if (!result.ok) {
|
|
107
|
+
return validationError('params', result);
|
|
108
|
+
}
|
|
109
|
+
params = result.value;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
params = {};
|
|
113
|
+
}
|
|
114
|
+
if (requiresInput) {
|
|
115
|
+
if (request.body === null) {
|
|
116
|
+
return invalidRequest(`request body is expected but none was provided`);
|
|
117
|
+
}
|
|
118
|
+
if (validateInputType !== null) {
|
|
119
|
+
const result = validateInputType(request);
|
|
120
|
+
if (!result.ok) {
|
|
121
|
+
return invalidRequest(result.error);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (inputSchema !== null) {
|
|
125
|
+
let raw;
|
|
126
|
+
try {
|
|
127
|
+
raw = await request.json();
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
return invalidRequest(`invalid request body (failed to parse json)`);
|
|
131
|
+
}
|
|
132
|
+
const result = safeParse(inputSchema, raw);
|
|
133
|
+
if (!result.ok) {
|
|
134
|
+
return validationError('input', result);
|
|
135
|
+
}
|
|
136
|
+
input = result.value;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
if (request.body !== null) {
|
|
141
|
+
return invalidRequest(`request body is provided when none was expected`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const context = {
|
|
145
|
+
request: request,
|
|
146
|
+
params: params,
|
|
147
|
+
input: input,
|
|
148
|
+
};
|
|
149
|
+
const output = await handler(context);
|
|
150
|
+
if (output instanceof Response) {
|
|
151
|
+
return output;
|
|
152
|
+
}
|
|
153
|
+
return new Response(null);
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../lib/main/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAsD,MAAM,8BAA8B,CAAC;AAK7G,OAAO,EAAE,2BAA2B,EAAmB,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAmB5C,MAAM,CAAC,MAAM,uBAAuB,GAAqB,CAAC,KAAc,EAAE,EAAE;IAC3E,IAAI,KAAK,YAAY,SAAS,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC,UAAU,EAAE,CAAC;IAC3B,CAAC;IAED,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC;IACd,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,CACnB,EAAE,KAAK,EAAE,qBAAqB,EAAE,OAAO,EAAE,sDAAsD,EAAE,EACjG,EAAE,MAAM,EAAE,GAAG,EAAE,CACf,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAoB,GAAG,EAAE;IAC3D,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;AACnD,CAAC,CAAC;AAQF,MAAM,OAAO,UAAU;IACtB,SAAS,GAAsC,EAAE,CAAC;IAClD,eAAe,CAAkB;IACjC,gBAAgB,CAAmB;IAEnC,KAAK,CAA0C;IAE/C,YAAY,EACX,WAAW,GAAG,EAAE,EAChB,eAAe,GAAG,uBAAuB,EACzC,cAAc,GAAG,sBAAsB,MACjB,EAAE;QACxB,IAAI,CAAC,KAAK,GAAG,2BAA2B,CAAC,CAAC,GAAG,WAAW,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACjG,IAAI,CAAC,gBAAgB,GAAG,eAAe,CAAC;QACxC,IAAI,CAAC,eAAe,GAAG,cAAc,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,OAAgB;QAC/B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;QAE9B,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,OAAO,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;QAED,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAEnC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;YACrC,OAAO,QAAQ,CAAC,IAAI,CACnB,EAAE,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,iCAAiC,KAAK,CAAC,MAAM,GAAG,EAAE,EACzF,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE,CACtD,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC;gBACpC,OAAO,EAAE,OAAO;gBAChB,GAAG,EAAE,GAAG;aACR,CAAC,CAAC;YAEH,OAAO,QAAQ,CAAC;QACjB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,OAAO,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;IACF,CAAC;IAOD,GAAG,CAAC,SAAoD,EAAE,MAAW;QACpE,QAAQ,SAAS,CAAC,IAAI,EAAE,CAAC;YACxB,KAAK,YAAY,CAAC,CAAC,CAAC;gBACnB,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAC1C,CAAC;YACD,KAAK,gBAAgB,CAAC,CAAC,CAAC;gBACvB,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAC9C,CAAC;QACF,CAAC;IACF,CAAC;IAED,SAAS,CAAmC,KAAa,EAAE,MAA2B;QACrF,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAEhF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAE/B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG;YAC5B,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE;gBACnC,IAAI,MAA2C,CAAC;gBAEhD,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;oBAC3B,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;oBAC9C,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;wBAChB,OAAO,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;oBAC1C,CAAC;oBAED,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC;gBACvB,CAAC;qBAAM,CAAC;oBACP,MAAM,GAAG,EAAE,CAAC;gBACb,CAAC;gBAED,MAAM,OAAO,GAA4B;oBACxC,OAAO,EAAE,OAAO;oBAChB,MAAM,EAAE,MAAM;iBACd,CAAC;gBAEF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAc,CAAC,CAAC;gBAE7C,IAAI,MAAM,YAAY,QAAQ,EAAE,CAAC;oBAChC,OAAO,MAAM,CAAC;gBACf,CAAC;gBAED,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC3B,CAAC;SACD,CAAC;IACH,CAAC;IAED,aAAa,CACZ,SAAqB,EACrB,MAAmC;QAEnC,MAAM,YAAY,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACxF,MAAM,iBAAiB,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,sBAAsB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAE3F,MAAM,aAAa,GAAG,SAAS,CAAC,KAAK,KAAK,IAAI,CAAC;QAC/C,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QAEpF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAE/B,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG;YAChC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE;gBACnC,IAAI,MAA2C,CAAC;gBAChD,IAAI,KAA0C,CAAC;gBAE/C,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;oBAC3B,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;oBAC9C,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;wBAChB,OAAO,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;oBAC1C,CAAC;oBAED,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC;gBACvB,CAAC;qBAAM,CAAC;oBACP,MAAM,GAAG,EAAE,CAAC;gBACb,CAAC;gBAED,IAAI,aAAa,EAAE,CAAC;oBACnB,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;wBAC3B,OAAO,cAAc,CAAC,gDAAgD,CAAC,CAAC;oBACzE,CAAC;oBAED,IAAI,iBAAiB,KAAK,IAAI,EAAE,CAAC;wBAChC,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;wBAC1C,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;4BAChB,OAAO,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;wBACrC,CAAC;oBACF,CAAC;oBAED,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;wBAC1B,IAAI,GAAQ,CAAC;wBACb,IAAI,CAAC;4BACJ,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;wBAC5B,CAAC;wBAAC,OAAO,GAAG,EAAE,CAAC;4BACd,OAAO,cAAc,CAAC,6CAA6C,CAAC,CAAC;wBACtE,CAAC;wBAED,MAAM,MAAM,GAAG,SAAS,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;wBAC3C,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;4BAChB,OAAO,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;wBACzC,CAAC;wBAED,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;oBACtB,CAAC;gBACF,CAAC;qBAAM,CAAC;oBACP,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;wBAC3B,OAAO,cAAc,CAAC,iDAAiD,CAAC,CAAC;oBAC1E,CAAC;gBACF,CAAC;gBAED,MAAM,OAAO,GAA4B;oBACxC,OAAO,EAAE,OAAO;oBAChB,MAAM,EAAE,MAAM;oBACd,KAAK,EAAE,KAAK;iBACZ,CAAC;gBAEF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAc,CAAC,CAAC;gBAE7C,IAAI,MAAM,YAAY,QAAQ,EAAE,CAAC;oBAChC,OAAO,MAAM,CAAC;gBACf,CAAC;gBAED,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC3B,CAAC;SACD,CAAC;IACH,CAAC;CACD"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { InferOutput, ObjectSchema, XRPCBlobBodyParam, XRPCLexBodyParam, XRPCProcedureMetadata, XRPCQueryMetadata } from '@atcute/lexicons/validations';
|
|
2
|
+
import type { Literal, Promisable } from '../../types/misc.js';
|
|
3
|
+
import type { JSONResponse } from '../response.js';
|
|
4
|
+
export type UnknownOperationContext = {
|
|
5
|
+
request: Request;
|
|
6
|
+
params: Record<string, Literal | Literal[]>;
|
|
7
|
+
input?: Record<string, unknown>;
|
|
8
|
+
};
|
|
9
|
+
export type QueryContext<TQuery extends XRPCQueryMetadata> = {
|
|
10
|
+
request: Request;
|
|
11
|
+
} & (TQuery['params'] extends ObjectSchema ? {
|
|
12
|
+
params: InferOutput<TQuery['params']>;
|
|
13
|
+
} : {});
|
|
14
|
+
export type QueryHandler<TQuery extends XRPCQueryMetadata> = (context: QueryContext<TQuery>) => Promisable<TQuery['output'] extends null ? Response | void : TQuery['output'] extends XRPCLexBodyParam ? Response | JSONResponse<InferOutput<TQuery['output']['schema']>> : Response>;
|
|
15
|
+
export type QueryConfig<TQuery extends XRPCQueryMetadata = XRPCQueryMetadata> = {
|
|
16
|
+
handler: QueryHandler<TQuery>;
|
|
17
|
+
};
|
|
18
|
+
export type ProcedureContext<TProcedure extends XRPCProcedureMetadata> = (TProcedure['input'] extends XRPCBlobBodyParam ? {
|
|
19
|
+
request: Request & {
|
|
20
|
+
readonly body: ReadableStream<Uint8Array>;
|
|
21
|
+
};
|
|
22
|
+
} : TProcedure['input'] extends XRPCLexBodyParam ? {
|
|
23
|
+
request: Request & {
|
|
24
|
+
readonly body: null;
|
|
25
|
+
};
|
|
26
|
+
} : {
|
|
27
|
+
request: Request;
|
|
28
|
+
}) & (TProcedure['params'] extends ObjectSchema ? {
|
|
29
|
+
params: InferOutput<TProcedure['params']>;
|
|
30
|
+
} : {}) & (TProcedure['input'] extends XRPCLexBodyParam ? {
|
|
31
|
+
input: InferOutput<TProcedure['input']['schema']>;
|
|
32
|
+
} : {});
|
|
33
|
+
export type ProcedureHandler<TProcedure extends XRPCProcedureMetadata> = (context: ProcedureContext<TProcedure>) => Promisable<TProcedure['output'] extends null ? Response | void : TProcedure['output'] extends XRPCLexBodyParam ? Response | JSONResponse<InferOutput<TProcedure['output']['schema']>> : Response>;
|
|
34
|
+
export type ProcedureConfig<TProcedure extends XRPCProcedureMetadata = XRPCProcedureMetadata> = {
|
|
35
|
+
handler: ProcedureHandler<TProcedure>;
|
|
36
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operation.js","sourceRoot":"","sources":["../../../lib/main/types/operation.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export type Middleware<TParams extends any[], TReturn> = (...params: [...TParams, next: (...params: TParams) => TReturn]) => TReturn;
|
|
2
|
+
export declare const createAsyncMiddlewareRunner: <TParams extends any[], TReturn>(middlewares: [...Middleware<TParams, Promise<TReturn>>[], Middleware<TParams, Promise<TReturn>>]) => (...params: TParams) => Promise<TReturn>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export const createAsyncMiddlewareRunner = (middlewares) => {
|
|
2
|
+
// prettier-ignore
|
|
3
|
+
return middlewares.reduceRight((next, run) => (...args) => run(...args, next), () => Promise.reject(new Error(`middleware chain exhausted`)));
|
|
4
|
+
};
|
|
5
|
+
//# sourceMappingURL=middlewares.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middlewares.js","sourceRoot":"","sources":["../../../lib/main/utils/middlewares.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAC1C,WAAgG,EAC/F,EAAE;IACH,kBAAkB;IAClB,OAAO,WAAW,CAAC,WAAW,CAC7B,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC,EAC9C,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC,CAC7D,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { XRPCBlobBodyParam, XRPCLexBodyParam } from '@atcute/lexicons/validations';
|
|
2
|
+
import type { Result } from '../../types/misc.js';
|
|
3
|
+
export declare const constructMimeValidator: (param: XRPCLexBodyParam | XRPCBlobBodyParam) => ((request: Request) => Result<void, string>) | null;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const jsonMimeValidator = (() => {
|
|
2
|
+
const JSON_RE = /^\s*application\/json\s*(?:$|;)/;
|
|
3
|
+
return (request) => {
|
|
4
|
+
const type = request.headers.get('content-type');
|
|
5
|
+
if (type === null) {
|
|
6
|
+
return { ok: false, error: `missing input content type (expected application/json)` };
|
|
7
|
+
}
|
|
8
|
+
if (!JSON_RE.test(type)) {
|
|
9
|
+
return { ok: false, error: `invalid input content type (expected application/json)` };
|
|
10
|
+
}
|
|
11
|
+
return { ok: true, value: undefined };
|
|
12
|
+
};
|
|
13
|
+
})();
|
|
14
|
+
export const constructMimeValidator = (param) => {
|
|
15
|
+
if (param.type === 'lex') {
|
|
16
|
+
return jsonMimeValidator;
|
|
17
|
+
}
|
|
18
|
+
const mimes = param.encoding;
|
|
19
|
+
if (mimes === undefined || mimes.length === 0) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const pattern = new RegExp(`^\\s*(?:${mimes.map(escapeRegexp).join('|')})\\s*(?:$|;)`);
|
|
23
|
+
return (request) => {
|
|
24
|
+
const type = request.headers.get('content-type');
|
|
25
|
+
if (type === null) {
|
|
26
|
+
return { ok: false, error: `missing input content type (expected ${separatedList(mimes, 'or')})` };
|
|
27
|
+
}
|
|
28
|
+
if (!pattern.test(type)) {
|
|
29
|
+
return { ok: false, error: `invalid input content type (expected ${separatedList(mimes, 'or')})` };
|
|
30
|
+
}
|
|
31
|
+
return { ok: true, value: undefined };
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
const separatedList = (list, sep) => {
|
|
35
|
+
switch (list.length) {
|
|
36
|
+
case 0: {
|
|
37
|
+
return `nothing`;
|
|
38
|
+
}
|
|
39
|
+
case 1: {
|
|
40
|
+
return list[0];
|
|
41
|
+
}
|
|
42
|
+
default: {
|
|
43
|
+
return `${list.slice(0, -1).join(', ')} ${sep} ${list[list.length - 1]}`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const escapeRegexp = (input) => {
|
|
48
|
+
return input.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=request-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-input.js","sourceRoot":"","sources":["../../../lib/main/utils/request-input.ts"],"names":[],"mappings":"AAIA,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE;IAC/B,MAAM,OAAO,GAAG,iCAAiC,CAAC;IAElD,OAAO,CAAC,OAAgB,EAAwB,EAAE;QACjD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACjD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YACnB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,wDAAwD,EAAE,CAAC;QACvF,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,wDAAwD,EAAE,CAAC;QACvF,CAAC;QAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IACvC,CAAC,CAAC;AACH,CAAC,CAAC,EAAE,CAAC;AAEL,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,KAA2C,EAAE,EAAE;IACrF,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QAC1B,OAAO,iBAAiB,CAAC;IAC1B,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC;IAC7B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/C,OAAO,IAAI,CAAC;IACb,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,WAAW,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAEvF,OAAO,CAAC,OAAgB,EAAwB,EAAE;QACjD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACjD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YACnB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,wCAAwC,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;QACpG,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,wCAAwC,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;QACpG,CAAC;QAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IACvC,CAAC,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,IAAc,EAAE,GAAiB,EAAU,EAAE;IACnE,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACrB,KAAK,CAAC,CAAC,CAAC,CAAC;YACR,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,KAAK,CAAC,CAAC,CAAC,CAAC;YACR,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,CAAC;QACD,OAAO,CAAC,CAAC,CAAC;YACT,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;QAC1E,CAAC;IACF,CAAC;AACF,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,KAAa,EAAU,EAAE;IAC9C,OAAO,KAAK,CAAC,OAAO,CAAC,0BAA0B,EAAE,MAAM,CAAC,CAAC;AAC1D,CAAC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type ObjectSchema, type ValidationResult } from '@atcute/lexicons/validations';
|
|
2
|
+
import type { Literal } from '../../types/misc.js';
|
|
3
|
+
type MaybeArray<T> = T | T[];
|
|
4
|
+
export declare const constructParamsHandler: <TSchema extends ObjectSchema>(schema: TSchema) => (searchParams: URLSearchParams) => ValidationResult<Record<string, MaybeArray<Literal>>>;
|
|
5
|
+
export {};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { safeParse, } from '@atcute/lexicons/validations';
|
|
2
|
+
const isArraySchema = (schema) => {
|
|
3
|
+
return schema.type === 'array';
|
|
4
|
+
};
|
|
5
|
+
const isOptionalSchema = (schema) => {
|
|
6
|
+
return schema.type === 'optional';
|
|
7
|
+
};
|
|
8
|
+
const unwrapOptional = (schema) => {
|
|
9
|
+
return isOptionalSchema(schema) ? schema.wrapped : schema;
|
|
10
|
+
};
|
|
11
|
+
const unwrapArray = (schema) => {
|
|
12
|
+
return isArraySchema(schema) ? schema.item : schema;
|
|
13
|
+
};
|
|
14
|
+
const coerceBoolean = (str) => {
|
|
15
|
+
switch (str) {
|
|
16
|
+
case 'true':
|
|
17
|
+
return true;
|
|
18
|
+
case 'false':
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
};
|
|
23
|
+
const coerceInteger = (str) => {
|
|
24
|
+
return Number(str);
|
|
25
|
+
};
|
|
26
|
+
export const constructParamsHandler = (schema) => {
|
|
27
|
+
const entries = Object.entries(schema.shape).map(([key, schema]) => {
|
|
28
|
+
const nonnullable = unwrapOptional(schema);
|
|
29
|
+
const singular = unwrapArray(nonnullable);
|
|
30
|
+
let coerce;
|
|
31
|
+
switch (singular.type) {
|
|
32
|
+
case 'boolean': {
|
|
33
|
+
coerce = coerceBoolean;
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
case 'integer': {
|
|
37
|
+
coerce = coerceInteger;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
key: key,
|
|
43
|
+
coerce: coerce,
|
|
44
|
+
multiple: isArraySchema(nonnullable),
|
|
45
|
+
optional: isOptionalSchema(schema) && schema.default === undefined,
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
const len = entries.length;
|
|
49
|
+
return (searchParams) => {
|
|
50
|
+
const input = {};
|
|
51
|
+
for (let idx = 0; idx < len; idx++) {
|
|
52
|
+
const entry = entries[idx];
|
|
53
|
+
const key = entry.key;
|
|
54
|
+
const coerce = entry.coerce;
|
|
55
|
+
const raw = searchParams.getAll(key);
|
|
56
|
+
const count = raw.length;
|
|
57
|
+
let value;
|
|
58
|
+
if (entry.multiple || count > 1) {
|
|
59
|
+
value = coerce !== undefined ? raw.map(coerce) : raw;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
if (count === 0) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
value = coerce !== undefined ? coerce(raw[0]) : raw[0];
|
|
66
|
+
}
|
|
67
|
+
/*#__INLINE__*/ set(input, key, value);
|
|
68
|
+
}
|
|
69
|
+
return safeParse(schema, input);
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
const set = (obj, key, value) => {
|
|
73
|
+
if (key === '__proto__') {
|
|
74
|
+
Object.defineProperty(obj, key, { value });
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
obj[key] = value;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=request-params.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-params.js","sourceRoot":"","sources":["../../../lib/main/utils/request-params.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const invalidRequest = (message) => {
|
|
2
|
+
return Response.json({ error: 'InvalidRequest', message }, { status: 400 });
|
|
3
|
+
};
|
|
4
|
+
export const validationError = (kind, err) => {
|
|
5
|
+
const message = `invalid ${kind}: ${err.message}`;
|
|
6
|
+
return Response.json({ error: 'InvalidRequest', message: message, 'net.kelinci.atcute.issues': err.issues }, { status: 400 });
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response.js","sourceRoot":"","sources":["../../../lib/main/utils/response.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAe,EAAE,EAAE;IACjD,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;AAC7E,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAAwB,EAAE,GAAQ,EAAY,EAAE;IAC/E,MAAM,OAAO,GAAG,WAAW,IAAI,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC;IAElD,OAAO,QAAQ,CAAC,IAAI,CACnB,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,EAAE,2BAA2B,EAAE,GAAG,CAAC,MAAM,EAAE,EACtF,EAAE,MAAM,EAAE,GAAG,EAAE,CACf,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface XRPCErrorOptions {
|
|
2
|
+
status: number;
|
|
3
|
+
error: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class XRPCError extends Error {
|
|
7
|
+
/** response status */
|
|
8
|
+
readonly status: number;
|
|
9
|
+
/** error name */
|
|
10
|
+
readonly error: string;
|
|
11
|
+
/** error message */
|
|
12
|
+
readonly description?: string;
|
|
13
|
+
constructor({ status, error, description }: XRPCErrorOptions);
|
|
14
|
+
toResponse(): Response;
|
|
15
|
+
}
|
|
16
|
+
export declare class InvalidRequestError extends XRPCError {
|
|
17
|
+
constructor({ status, error, description }?: Partial<XRPCErrorOptions>);
|
|
18
|
+
}
|
|
19
|
+
export declare class AuthRequiredError extends XRPCError {
|
|
20
|
+
constructor({ status, error, description, }?: Partial<XRPCErrorOptions>);
|
|
21
|
+
}
|
|
22
|
+
export declare class ForbiddenError extends XRPCError {
|
|
23
|
+
constructor({ status, error, description }?: Partial<XRPCErrorOptions>);
|
|
24
|
+
}
|
|
25
|
+
export declare class RateLimitExceededError extends XRPCError {
|
|
26
|
+
constructor({ status, error, description }?: Partial<XRPCErrorOptions>);
|
|
27
|
+
}
|
|
28
|
+
export declare class InternalServerError extends XRPCError {
|
|
29
|
+
constructor({ status, error, description }?: Partial<XRPCErrorOptions>);
|
|
30
|
+
}
|
|
31
|
+
export declare class UpstreamFailureError extends XRPCError {
|
|
32
|
+
constructor({ status, error, description }?: Partial<XRPCErrorOptions>);
|
|
33
|
+
}
|
|
34
|
+
export declare class NotEnoughResourcesError extends XRPCError {
|
|
35
|
+
constructor({ status, error, description }?: Partial<XRPCErrorOptions>);
|
|
36
|
+
}
|
|
37
|
+
export declare class UpstreamTimeoutError extends XRPCError {
|
|
38
|
+
constructor({ status, error, description }?: Partial<XRPCErrorOptions>);
|
|
39
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export class XRPCError extends Error {
|
|
2
|
+
/** response status */
|
|
3
|
+
status;
|
|
4
|
+
/** error name */
|
|
5
|
+
error;
|
|
6
|
+
/** error message */
|
|
7
|
+
description;
|
|
8
|
+
constructor({ status, error, description }) {
|
|
9
|
+
super(`${error} > ${description ?? '(unspecified description)'}`);
|
|
10
|
+
this.status = status;
|
|
11
|
+
this.error = error;
|
|
12
|
+
this.description = description;
|
|
13
|
+
}
|
|
14
|
+
toResponse() {
|
|
15
|
+
return Response.json({ error: this.error, message: this.description }, { status: this.status });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export class InvalidRequestError extends XRPCError {
|
|
19
|
+
constructor({ status = 400, error = 'InvalidRequest', description } = {}) {
|
|
20
|
+
super({ status, error, description });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export class AuthRequiredError extends XRPCError {
|
|
24
|
+
constructor({ status = 401, error = 'AuthenticationRequired', description, } = {}) {
|
|
25
|
+
super({ status, error, description });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export class ForbiddenError extends XRPCError {
|
|
29
|
+
constructor({ status = 403, error = 'Forbidden', description } = {}) {
|
|
30
|
+
super({ status, error, description });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export class RateLimitExceededError extends XRPCError {
|
|
34
|
+
constructor({ status = 429, error = 'RateLimitExceeded', description } = {}) {
|
|
35
|
+
super({ status, error, description });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export class InternalServerError extends XRPCError {
|
|
39
|
+
constructor({ status = 500, error = 'InternalServerError', description } = {}) {
|
|
40
|
+
super({ status, error, description });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export class UpstreamFailureError extends XRPCError {
|
|
44
|
+
constructor({ status = 502, error = 'UpstreamFailure', description } = {}) {
|
|
45
|
+
super({ status, error, description });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export class NotEnoughResourcesError extends XRPCError {
|
|
49
|
+
constructor({ status = 503, error = 'NotEnoughResources', description } = {}) {
|
|
50
|
+
super({ status, error, description });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export class UpstreamTimeoutError extends XRPCError {
|
|
54
|
+
constructor({ status = 504, error = 'UpstreamTimeout', description } = {}) {
|
|
55
|
+
super({ status, error, description });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=xrpc-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xrpc-error.js","sourceRoot":"","sources":["../../lib/main/xrpc-error.ts"],"names":[],"mappings":"AAMA,MAAM,OAAO,SAAU,SAAQ,KAAK;IACnC,sBAAsB;IACb,MAAM,CAAS;IAExB,iBAAiB;IACR,KAAK,CAAS;IACvB,oBAAoB;IACX,WAAW,CAAU;IAE9B,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAoB;QAC3D,KAAK,CAAC,GAAG,KAAK,MAAM,WAAW,IAAI,2BAA2B,EAAE,CAAC,CAAC;QAElE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IAChC,CAAC;IAED,UAAU;QACT,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACjG,CAAC;CACD;AAED,MAAM,OAAO,mBAAoB,SAAQ,SAAS;IACjD,YAAY,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,GAAG,gBAAgB,EAAE,WAAW,KAAgC,EAAE;QAClG,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD;AAED,MAAM,OAAO,iBAAkB,SAAQ,SAAS;IAC/C,YAAY,EACX,MAAM,GAAG,GAAG,EACZ,KAAK,GAAG,wBAAwB,EAChC,WAAW,MACmB,EAAE;QAChC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD;AAED,MAAM,OAAO,cAAe,SAAQ,SAAS;IAC5C,YAAY,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,GAAG,WAAW,EAAE,WAAW,KAAgC,EAAE;QAC7F,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD;AAED,MAAM,OAAO,sBAAuB,SAAQ,SAAS;IACpD,YAAY,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,GAAG,mBAAmB,EAAE,WAAW,KAAgC,EAAE;QACrG,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD;AAED,MAAM,OAAO,mBAAoB,SAAQ,SAAS;IACjD,YAAY,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,GAAG,qBAAqB,EAAE,WAAW,KAAgC,EAAE;QACvG,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD;AAED,MAAM,OAAO,oBAAqB,SAAQ,SAAS;IAClD,YAAY,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,GAAG,iBAAiB,EAAE,WAAW,KAAgC,EAAE;QACnG,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD;AAED,MAAM,OAAO,uBAAwB,SAAQ,SAAS;IACrD,YAAY,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,GAAG,oBAAoB,EAAE,WAAW,KAAgC,EAAE;QACtG,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD;AAED,MAAM,OAAO,oBAAqB,SAAQ,SAAS;IAClD,YAAY,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,GAAG,iBAAiB,EAAE,WAAW,KAAgC,EAAE;QACnG,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FetchMiddleware } from '../main/router.js';
|
|
2
|
+
export interface CORSOptions {
|
|
3
|
+
/** Additional headers to expose to the client */
|
|
4
|
+
exposedHeaders?: string[];
|
|
5
|
+
/** Additional headers to allow */
|
|
6
|
+
allowedHeaders?: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare const cors: (options?: CORSOptions) => FetchMiddleware;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const DEFAULT_EXPOSED_HEADERS = [
|
|
2
|
+
'dpop-nonce',
|
|
3
|
+
'www-authenticate',
|
|
4
|
+
'ratelimit-limit',
|
|
5
|
+
'ratelimit-policy',
|
|
6
|
+
'ratelimit-remaining',
|
|
7
|
+
'ratelimit-reset',
|
|
8
|
+
];
|
|
9
|
+
const DEFAULT_ALLOWED_HEADERS = [
|
|
10
|
+
'content-type',
|
|
11
|
+
'authorization',
|
|
12
|
+
'dpop',
|
|
13
|
+
'atproto-accept-labelers',
|
|
14
|
+
'atproto-proxy',
|
|
15
|
+
];
|
|
16
|
+
export const cors = (options = {}) => {
|
|
17
|
+
const exposedHeaders = Array.from(new Set([...DEFAULT_EXPOSED_HEADERS, ...(options.exposedHeaders?.map((h) => h.toLowerCase()) || [])])).sort();
|
|
18
|
+
const allowedHeaders = Array.from(new Set([...DEFAULT_ALLOWED_HEADERS, ...(options.allowedHeaders?.map((h) => h.toLowerCase()) || [])]))
|
|
19
|
+
.sort()
|
|
20
|
+
.join(',');
|
|
21
|
+
return async (request, next) => {
|
|
22
|
+
const origin = request.headers.get('origin') || '*';
|
|
23
|
+
// Handle preflight requests
|
|
24
|
+
if (request.method === 'OPTIONS') {
|
|
25
|
+
const headers = new Headers();
|
|
26
|
+
headers.set('access-control-max-age', '86400');
|
|
27
|
+
headers.set('access-control-allow-origin', origin);
|
|
28
|
+
if (allowedHeaders) {
|
|
29
|
+
headers.set('access-control-allow-headers', allowedHeaders);
|
|
30
|
+
}
|
|
31
|
+
return new Response(null, { status: 204, headers: headers });
|
|
32
|
+
}
|
|
33
|
+
const response = await next(request);
|
|
34
|
+
const expose = exposedHeaders.filter((h) => response.headers.has(h)).join(',');
|
|
35
|
+
response.headers.set('access-control-allow-origin', origin);
|
|
36
|
+
if (expose.length > 0) {
|
|
37
|
+
response.headers.append('access-control-expose-headers', expose);
|
|
38
|
+
}
|
|
39
|
+
return response;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=cors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.js","sourceRoot":"","sources":["../../lib/middlewares/cors.ts"],"names":[],"mappings":"AASA,MAAM,uBAAuB,GAAG;IAC/B,YAAY;IACZ,kBAAkB;IAElB,iBAAiB;IACjB,kBAAkB;IAClB,qBAAqB;IACrB,iBAAiB;CACjB,CAAC;AAEF,MAAM,uBAAuB,GAAG;IAC/B,cAAc;IAEd,eAAe;IACf,MAAM;IAEN,yBAAyB;IACzB,eAAe;CACf,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,UAAuB,EAAE,EAAmB,EAAE;IAClE,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAChC,IAAI,GAAG,CAAC,CAAC,GAAG,uBAAuB,EAAE,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CACrG,CAAC,IAAI,EAAE,CAAC;IAET,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAChC,IAAI,GAAG,CAAC,CAAC,GAAG,uBAAuB,EAAE,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CACrG;SACC,IAAI,EAAE;SACN,IAAI,CAAC,GAAG,CAAC,CAAC;IAEZ,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC;QAEpD,4BAA4B;QAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;YAEnD,IAAI,cAAc,EAAE,CAAC;gBACpB,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;YAC7D,CAAC;YAED,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC9D,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;QAErC,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAE/E,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;QAC5D,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,+BAA+B,EAAE,MAAM,CAAC,CAAC;QAClE,CAAC;QAED,OAAO,QAAQ,CAAC;IACjB,CAAC,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"misc.js","sourceRoot":"","sources":["../../lib/types/misc.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { PrivateKey } from '@atcute/crypto';
|
|
2
|
+
import type { Did, Nsid } from '@atcute/lexicons';
|
|
3
|
+
import { toBase64Url } from '@atcute/multibase';
|
|
4
|
+
import { encodeUtf8 } from '@atcute/uint8array';
|
|
5
|
+
|
|
6
|
+
import { nanoid } from 'nanoid';
|
|
7
|
+
|
|
8
|
+
import type { JwtHeader, JwtPayload } from './jwt.js';
|
|
9
|
+
|
|
10
|
+
export interface CreateServiceJwtOptions {
|
|
11
|
+
keypair: PrivateKey;
|
|
12
|
+
issuer: Did;
|
|
13
|
+
audience: Did;
|
|
14
|
+
lxm: Nsid | null;
|
|
15
|
+
issuedAt?: number;
|
|
16
|
+
expiresIn?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const createServiceJwt = async (options: CreateServiceJwtOptions): Promise<string> => {
|
|
20
|
+
const keypair = options.keypair;
|
|
21
|
+
|
|
22
|
+
const issuedAt = Math.floor(options.issuedAt ?? Date.now() / 1_000);
|
|
23
|
+
const expiresIn = Math.floor(options.expiresIn ?? 60);
|
|
24
|
+
|
|
25
|
+
const header: JwtHeader = {
|
|
26
|
+
typ: 'JWT',
|
|
27
|
+
alg: keypair.jwtAlg,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const payload: JwtPayload = {
|
|
31
|
+
aud: options.audience,
|
|
32
|
+
exp: issuedAt + expiresIn,
|
|
33
|
+
iat: issuedAt,
|
|
34
|
+
iss: options.issuer,
|
|
35
|
+
jti: nanoid(24),
|
|
36
|
+
lxm: options.lxm ?? undefined,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const headerB64 = encodeJwtPortion(header);
|
|
40
|
+
const payloadB64 = encodeJwtPortion(payload);
|
|
41
|
+
const message = `${headerB64}.${payloadB64}`;
|
|
42
|
+
|
|
43
|
+
const signature = await keypair.sign(encodeUtf8(message));
|
|
44
|
+
const signatureB64 = toBase64Url(signature);
|
|
45
|
+
|
|
46
|
+
return `${message}.${signatureB64}`;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const encodeJwtPortion = (data: unknown): string => {
|
|
50
|
+
return toBase64Url(encodeUtf8(JSON.stringify(data)));
|
|
51
|
+
};
|