@kaito-http/core 3.0.0-beta.10 → 3.0.0-beta.13
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/dist/index.cjs +62 -34
- package/dist/index.d.cts +43 -17
- package/dist/index.d.ts +43 -17
- package/dist/index.js +62 -33
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -24,7 +24,6 @@ __export(index_exports, {
|
|
|
24
24
|
KaitoRequest: () => KaitoRequest,
|
|
25
25
|
Router: () => Router,
|
|
26
26
|
WrappedError: () => WrappedError,
|
|
27
|
-
apiresponse: () => apiresponse,
|
|
28
27
|
createKaitoHandler: () => createKaitoHandler,
|
|
29
28
|
createUtilities: () => createUtilities,
|
|
30
29
|
parsable: () => parsable
|
|
@@ -56,53 +55,77 @@ var KaitoError = class extends Error {
|
|
|
56
55
|
|
|
57
56
|
// src/request.ts
|
|
58
57
|
var KaitoRequest = class {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
constructor(request) {
|
|
62
|
-
this.
|
|
58
|
+
url;
|
|
59
|
+
_request;
|
|
60
|
+
constructor(url, request) {
|
|
61
|
+
this._request = request;
|
|
62
|
+
this.url = url;
|
|
63
63
|
}
|
|
64
64
|
get headers() {
|
|
65
|
-
return this.
|
|
65
|
+
return this._request.headers;
|
|
66
66
|
}
|
|
67
67
|
get method() {
|
|
68
|
-
return this.
|
|
69
|
-
}
|
|
70
|
-
get url() {
|
|
71
|
-
return this.request.url;
|
|
72
|
-
}
|
|
73
|
-
parseURL() {
|
|
74
|
-
if (!this._url) {
|
|
75
|
-
this._url = new URL(this.url);
|
|
76
|
-
}
|
|
77
|
-
return this._url;
|
|
68
|
+
return this._request.method;
|
|
78
69
|
}
|
|
79
70
|
async arrayBuffer() {
|
|
80
|
-
return this.
|
|
71
|
+
return this._request.arrayBuffer();
|
|
81
72
|
}
|
|
82
73
|
async blob() {
|
|
83
|
-
return this.
|
|
74
|
+
return this._request.blob();
|
|
84
75
|
}
|
|
85
76
|
async formData() {
|
|
86
|
-
return this.
|
|
77
|
+
return this._request.formData();
|
|
87
78
|
}
|
|
88
79
|
async bytes() {
|
|
89
80
|
const buffer = await this.arrayBuffer();
|
|
90
81
|
return new Uint8Array(buffer);
|
|
91
82
|
}
|
|
92
83
|
async json() {
|
|
93
|
-
return this.
|
|
84
|
+
return this._request.json();
|
|
94
85
|
}
|
|
95
86
|
async text() {
|
|
96
|
-
return this.
|
|
87
|
+
return this._request.text();
|
|
88
|
+
}
|
|
89
|
+
get request() {
|
|
90
|
+
return this._request;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// src/response.ts
|
|
95
|
+
var KaitoResponse = class {
|
|
96
|
+
_headers;
|
|
97
|
+
_status;
|
|
98
|
+
constructor() {
|
|
99
|
+
this._headers = null;
|
|
100
|
+
this._status = 200;
|
|
101
|
+
}
|
|
102
|
+
get headers() {
|
|
103
|
+
if (this._headers === null) {
|
|
104
|
+
this._headers = new Headers();
|
|
105
|
+
}
|
|
106
|
+
return this._headers;
|
|
107
|
+
}
|
|
108
|
+
status(status) {
|
|
109
|
+
this._status = status;
|
|
110
|
+
return this;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Turn this KaitoResponse instance into a Response instance
|
|
114
|
+
* @param body The Kaito JSON format to be sent as the response body
|
|
115
|
+
* @returns A Response instance, ready to be sent
|
|
116
|
+
*/
|
|
117
|
+
toResponse(body) {
|
|
118
|
+
const init = {
|
|
119
|
+
status: this._status
|
|
120
|
+
};
|
|
121
|
+
if (this._headers) {
|
|
122
|
+
init.headers = this._headers;
|
|
123
|
+
}
|
|
124
|
+
return Response.json(body, init);
|
|
97
125
|
}
|
|
98
126
|
};
|
|
99
127
|
|
|
100
128
|
// src/util.ts
|
|
101
|
-
function apiresponse(status, response) {
|
|
102
|
-
return Response.json(response, {
|
|
103
|
-
status
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
129
|
function createUtilities(getContext) {
|
|
107
130
|
return {
|
|
108
131
|
getContext,
|
|
@@ -141,6 +164,7 @@ var Router = class _Router {
|
|
|
141
164
|
}
|
|
142
165
|
add = (method, path, route) => {
|
|
143
166
|
const merged = {
|
|
167
|
+
// TODO: Ideally fix the typing here, but this will be replaced in Kaito v4 where all routes must return a Response (which we can type)
|
|
144
168
|
...typeof route === "object" ? route : { run: route },
|
|
145
169
|
method,
|
|
146
170
|
path,
|
|
@@ -198,15 +222,17 @@ var Router = class _Router {
|
|
|
198
222
|
const method = req.method;
|
|
199
223
|
const { route, params } = findRoute(method, url.pathname);
|
|
200
224
|
if (!route) {
|
|
201
|
-
|
|
225
|
+
const body = {
|
|
202
226
|
success: false,
|
|
203
227
|
data: null,
|
|
204
228
|
message: `Cannot ${method} ${url.pathname}`
|
|
205
|
-
}
|
|
229
|
+
};
|
|
230
|
+
return Response.json(body, { status: 404 });
|
|
206
231
|
}
|
|
207
|
-
const request = new KaitoRequest(req);
|
|
232
|
+
const request = new KaitoRequest(url, req);
|
|
233
|
+
const response = new KaitoResponse();
|
|
208
234
|
try {
|
|
209
|
-
const rootCtx = await server.getContext(request);
|
|
235
|
+
const rootCtx = await server.getContext(request, response);
|
|
210
236
|
const ctx = await route.through(rootCtx);
|
|
211
237
|
const body = route.body ? await route.body.parse(await req.json()) : void 0;
|
|
212
238
|
const query = _Router.parseQuery(route.query, url);
|
|
@@ -216,7 +242,10 @@ var Router = class _Router {
|
|
|
216
242
|
query,
|
|
217
243
|
params
|
|
218
244
|
});
|
|
219
|
-
|
|
245
|
+
if (result instanceof Response) {
|
|
246
|
+
return result;
|
|
247
|
+
}
|
|
248
|
+
return response.toResponse({
|
|
220
249
|
success: true,
|
|
221
250
|
data: result,
|
|
222
251
|
message: "OK"
|
|
@@ -224,14 +253,14 @@ var Router = class _Router {
|
|
|
224
253
|
} catch (e) {
|
|
225
254
|
const error = WrappedError.maybe(e);
|
|
226
255
|
if (error instanceof KaitoError) {
|
|
227
|
-
return
|
|
256
|
+
return response.status(error.status).toResponse({
|
|
228
257
|
success: false,
|
|
229
258
|
data: null,
|
|
230
259
|
message: error.message
|
|
231
260
|
});
|
|
232
261
|
}
|
|
233
262
|
const { status, message } = await server.onError({ error, req: request }).catch(() => ({ status: 500, message: "Internal Server Error" }));
|
|
234
|
-
return
|
|
263
|
+
return response.status(status).toResponse({
|
|
235
264
|
success: false,
|
|
236
265
|
data: null,
|
|
237
266
|
message
|
|
@@ -283,7 +312,6 @@ function createKaitoHandler(config) {
|
|
|
283
312
|
KaitoRequest,
|
|
284
313
|
Router,
|
|
285
314
|
WrappedError,
|
|
286
|
-
apiresponse,
|
|
287
315
|
createKaitoHandler,
|
|
288
316
|
createUtilities,
|
|
289
317
|
parsable
|
package/dist/index.d.cts
CHANGED
|
@@ -10,23 +10,50 @@ declare class KaitoError extends Error {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
declare class KaitoRequest {
|
|
13
|
-
|
|
14
|
-
private
|
|
15
|
-
constructor(request: Request);
|
|
13
|
+
readonly url: URL;
|
|
14
|
+
private readonly _request;
|
|
15
|
+
constructor(url: URL, request: Request);
|
|
16
16
|
get headers(): Headers;
|
|
17
17
|
get method(): string;
|
|
18
|
-
get url(): string;
|
|
19
|
-
parseURL(): URL;
|
|
20
18
|
arrayBuffer(): Promise<ArrayBuffer>;
|
|
21
19
|
blob(): Promise<Blob>;
|
|
22
20
|
formData(): Promise<FormData>;
|
|
23
21
|
bytes(): Promise<Uint8Array>;
|
|
24
22
|
json(): Promise<unknown>;
|
|
25
23
|
text(): Promise<string>;
|
|
24
|
+
get request(): Request;
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
type KaitoMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS' | 'CONNECT' | 'TRACE';
|
|
29
28
|
|
|
29
|
+
/**
|
|
30
|
+
* This class is similar to a `Response` object from the Web Fetch API, but
|
|
31
|
+
* this with no body stream, and is only used for setting status codes/headers.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* const response = new KaitoResponse();
|
|
36
|
+
*
|
|
37
|
+
* response.status = 200;
|
|
38
|
+
* response.header('Content-Type', 'application/json');
|
|
39
|
+
*
|
|
40
|
+
* console.log(response.headers); // Headers { 'content-type': 'application/json' }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
declare class KaitoResponse {
|
|
44
|
+
private _headers;
|
|
45
|
+
private _status;
|
|
46
|
+
constructor();
|
|
47
|
+
get headers(): Headers;
|
|
48
|
+
status(status: number): this;
|
|
49
|
+
/**
|
|
50
|
+
* Turn this KaitoResponse instance into a Response instance
|
|
51
|
+
* @param body The Kaito JSON format to be sent as the response body
|
|
52
|
+
* @returns A Response instance, ready to be sent
|
|
53
|
+
*/
|
|
54
|
+
toResponse<T>(body: APIResponse<T>): Response;
|
|
55
|
+
}
|
|
56
|
+
|
|
30
57
|
type Before<BeforeAfterContext> = (req: Request) => Promise<BeforeAfterContext | Response>;
|
|
31
58
|
type After<BeforeAfterContext> = (ctx: BeforeAfterContext, response: Response) => Promise<void>;
|
|
32
59
|
type ServerConfigWithBefore<BeforeAfterContext> = {
|
|
@@ -61,17 +88,17 @@ declare class Router<ContextFrom, ContextTo, R extends AnyRoute> {
|
|
|
61
88
|
private static parseQuery;
|
|
62
89
|
constructor(options: RouterState<R, ContextFrom, ContextTo>);
|
|
63
90
|
get routes(): Set<R>;
|
|
64
|
-
add: <Result, Path extends string, Method extends KaitoMethod, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(method: Method, path: Path, route: (Method extends "GET" ? Omit<Route<ContextFrom, ContextTo, Result, Path, Method, Query, Body>, "body" | "path" | "method" | "through"> : Omit<Route<ContextFrom, ContextTo, Result, Path, Method, Query, Body>, "path" | "method" | "through">) | Route<ContextFrom, ContextTo, Result, Path, Method, Query, Body>["run"]) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, Method, Query, Body>>;
|
|
91
|
+
add: <Result, Path extends string, Method extends KaitoMethod, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(method: Method, path: Path, route: (Method extends "GET" ? Omit<Route<ContextFrom, ContextTo, Result, Path, Method, Query, Body>, "body" | "path" | "method" | "through"> : Omit<Route<ContextFrom, ContextTo, Result, Path, Method, Query, Body>, "path" | "method" | "through">) | Route<ContextFrom, ContextTo, Result, Path, Method, Query, Body>["run"]) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, Method, Query, Body>>;
|
|
65
92
|
readonly merge: <PathPrefix extends `/${string}`, OtherRoutes extends AnyRoute>(pathPrefix: PathPrefix, other: Router<ContextFrom, unknown, OtherRoutes>) => Router<ContextFrom, ContextTo, Extract<R | PrefixRoutesPath<PathPrefix, OtherRoutes>, AnyRoute>>;
|
|
66
|
-
freeze: (server: ServerConfig<ContextFrom, any>) => (req: Request) => Promise<Response>;
|
|
93
|
+
freeze: (server: Omit<ServerConfig<ContextFrom, any>, "router">) => (req: Request) => Promise<Response>;
|
|
67
94
|
private readonly method;
|
|
68
|
-
get: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "GET", Query, Body>, "body" | "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, "GET", Query, Body>>;
|
|
69
|
-
post: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "POST", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, "POST", Query, Body>>;
|
|
70
|
-
put: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "PUT", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, "PUT", Query, Body>>;
|
|
71
|
-
patch: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "PATCH", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, "PATCH", Query, Body>>;
|
|
72
|
-
delete: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "DELETE", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, "DELETE", Query, Body>>;
|
|
73
|
-
head: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "HEAD", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, "HEAD", Query, Body>>;
|
|
74
|
-
options: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "OPTIONS", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, "OPTIONS", Query, Body>>;
|
|
95
|
+
get: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "GET", Query, Body>, "body" | "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, "GET", Query, Body>>;
|
|
96
|
+
post: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "POST", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, "POST", Query, Body>>;
|
|
97
|
+
put: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "PUT", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, "PUT", Query, Body>>;
|
|
98
|
+
patch: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "PATCH", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, "PATCH", Query, Body>>;
|
|
99
|
+
delete: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "DELETE", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, "DELETE", Query, Body>>;
|
|
100
|
+
head: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "HEAD", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, "HEAD", Query, Body>>;
|
|
101
|
+
options: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "OPTIONS", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, "OPTIONS", Query, Body>>;
|
|
75
102
|
through: <NextContext>(transform: (context: ContextTo) => Promise<NextContext>) => Router<ContextFrom, NextContext, R>;
|
|
76
103
|
}
|
|
77
104
|
|
|
@@ -87,13 +114,12 @@ type SuccessfulAPIResponse<T> = {
|
|
|
87
114
|
};
|
|
88
115
|
type APIResponse<T> = ErroredAPIResponse | SuccessfulAPIResponse<T>;
|
|
89
116
|
type AnyResponse = APIResponse<unknown>;
|
|
90
|
-
declare function apiresponse<T>(status: number, response: APIResponse<T>): Response;
|
|
91
117
|
type ExtractRouteParams<T extends string> = string extends T ? Record<string, string> : T extends `${string}:${infer Param}/${infer Rest}` ? {
|
|
92
118
|
[k in Param | keyof ExtractRouteParams<Rest>]: string;
|
|
93
119
|
} : T extends `${string}:${infer Param}` ? {
|
|
94
120
|
[k in Param]: string;
|
|
95
121
|
} : {};
|
|
96
|
-
type GetContext<Result> = (req: KaitoRequest) => Promise<Result>;
|
|
122
|
+
type GetContext<Result> = (req: KaitoRequest, res: KaitoResponse) => Promise<Result>;
|
|
97
123
|
/**
|
|
98
124
|
* A helper function to create typed necessary functions
|
|
99
125
|
*
|
|
@@ -146,4 +172,4 @@ type Route<ContextFrom, ContextTo, Result, Path extends string, Method extends K
|
|
|
146
172
|
};
|
|
147
173
|
type AnyRoute<ContextFrom = any, ContextTo = any> = Route<ContextFrom, ContextTo, any, any, any, AnyQueryDefinition, any>;
|
|
148
174
|
|
|
149
|
-
export { type APIResponse, type After, type AnyQueryDefinition, type AnyResponse, type AnyRoute, type Before, type ErroredAPIResponse, type ExtractRouteParams, type GetContext, type InferParsable, type InferRoutes, KaitoError, type KaitoMethod, KaitoRequest, type Parsable, type Route, type RouteArgument, Router, type RouterState, type ServerConfig, type ServerConfigWithBefore, type SuccessfulAPIResponse, type Through, WrappedError,
|
|
175
|
+
export { type APIResponse, type After, type AnyQueryDefinition, type AnyResponse, type AnyRoute, type Before, type ErroredAPIResponse, type ExtractRouteParams, type GetContext, type InferParsable, type InferRoutes, KaitoError, type KaitoMethod, KaitoRequest, type Parsable, type Route, type RouteArgument, Router, type RouterState, type ServerConfig, type ServerConfigWithBefore, type SuccessfulAPIResponse, type Through, WrappedError, createKaitoHandler, createUtilities, parsable };
|
package/dist/index.d.ts
CHANGED
|
@@ -10,23 +10,50 @@ declare class KaitoError extends Error {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
declare class KaitoRequest {
|
|
13
|
-
|
|
14
|
-
private
|
|
15
|
-
constructor(request: Request);
|
|
13
|
+
readonly url: URL;
|
|
14
|
+
private readonly _request;
|
|
15
|
+
constructor(url: URL, request: Request);
|
|
16
16
|
get headers(): Headers;
|
|
17
17
|
get method(): string;
|
|
18
|
-
get url(): string;
|
|
19
|
-
parseURL(): URL;
|
|
20
18
|
arrayBuffer(): Promise<ArrayBuffer>;
|
|
21
19
|
blob(): Promise<Blob>;
|
|
22
20
|
formData(): Promise<FormData>;
|
|
23
21
|
bytes(): Promise<Uint8Array>;
|
|
24
22
|
json(): Promise<unknown>;
|
|
25
23
|
text(): Promise<string>;
|
|
24
|
+
get request(): Request;
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
type KaitoMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS' | 'CONNECT' | 'TRACE';
|
|
29
28
|
|
|
29
|
+
/**
|
|
30
|
+
* This class is similar to a `Response` object from the Web Fetch API, but
|
|
31
|
+
* this with no body stream, and is only used for setting status codes/headers.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* const response = new KaitoResponse();
|
|
36
|
+
*
|
|
37
|
+
* response.status = 200;
|
|
38
|
+
* response.header('Content-Type', 'application/json');
|
|
39
|
+
*
|
|
40
|
+
* console.log(response.headers); // Headers { 'content-type': 'application/json' }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
declare class KaitoResponse {
|
|
44
|
+
private _headers;
|
|
45
|
+
private _status;
|
|
46
|
+
constructor();
|
|
47
|
+
get headers(): Headers;
|
|
48
|
+
status(status: number): this;
|
|
49
|
+
/**
|
|
50
|
+
* Turn this KaitoResponse instance into a Response instance
|
|
51
|
+
* @param body The Kaito JSON format to be sent as the response body
|
|
52
|
+
* @returns A Response instance, ready to be sent
|
|
53
|
+
*/
|
|
54
|
+
toResponse<T>(body: APIResponse<T>): Response;
|
|
55
|
+
}
|
|
56
|
+
|
|
30
57
|
type Before<BeforeAfterContext> = (req: Request) => Promise<BeforeAfterContext | Response>;
|
|
31
58
|
type After<BeforeAfterContext> = (ctx: BeforeAfterContext, response: Response) => Promise<void>;
|
|
32
59
|
type ServerConfigWithBefore<BeforeAfterContext> = {
|
|
@@ -61,17 +88,17 @@ declare class Router<ContextFrom, ContextTo, R extends AnyRoute> {
|
|
|
61
88
|
private static parseQuery;
|
|
62
89
|
constructor(options: RouterState<R, ContextFrom, ContextTo>);
|
|
63
90
|
get routes(): Set<R>;
|
|
64
|
-
add: <Result, Path extends string, Method extends KaitoMethod, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(method: Method, path: Path, route: (Method extends "GET" ? Omit<Route<ContextFrom, ContextTo, Result, Path, Method, Query, Body>, "body" | "path" | "method" | "through"> : Omit<Route<ContextFrom, ContextTo, Result, Path, Method, Query, Body>, "path" | "method" | "through">) | Route<ContextFrom, ContextTo, Result, Path, Method, Query, Body>["run"]) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, Method, Query, Body>>;
|
|
91
|
+
add: <Result, Path extends string, Method extends KaitoMethod, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(method: Method, path: Path, route: (Method extends "GET" ? Omit<Route<ContextFrom, ContextTo, Result, Path, Method, Query, Body>, "body" | "path" | "method" | "through"> : Omit<Route<ContextFrom, ContextTo, Result, Path, Method, Query, Body>, "path" | "method" | "through">) | Route<ContextFrom, ContextTo, Result, Path, Method, Query, Body>["run"]) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, Method, Query, Body>>;
|
|
65
92
|
readonly merge: <PathPrefix extends `/${string}`, OtherRoutes extends AnyRoute>(pathPrefix: PathPrefix, other: Router<ContextFrom, unknown, OtherRoutes>) => Router<ContextFrom, ContextTo, Extract<R | PrefixRoutesPath<PathPrefix, OtherRoutes>, AnyRoute>>;
|
|
66
|
-
freeze: (server: ServerConfig<ContextFrom, any>) => (req: Request) => Promise<Response>;
|
|
93
|
+
freeze: (server: Omit<ServerConfig<ContextFrom, any>, "router">) => (req: Request) => Promise<Response>;
|
|
67
94
|
private readonly method;
|
|
68
|
-
get: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "GET", Query, Body>, "body" | "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, "GET", Query, Body>>;
|
|
69
|
-
post: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "POST", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, "POST", Query, Body>>;
|
|
70
|
-
put: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "PUT", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, "PUT", Query, Body>>;
|
|
71
|
-
patch: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "PATCH", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, "PATCH", Query, Body>>;
|
|
72
|
-
delete: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "DELETE", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, "DELETE", Query, Body>>;
|
|
73
|
-
head: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "HEAD", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, "HEAD", Query, Body>>;
|
|
74
|
-
options: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "OPTIONS", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result, Path, "OPTIONS", Query, Body>>;
|
|
95
|
+
get: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "GET", Query, Body>, "body" | "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, "GET", Query, Body>>;
|
|
96
|
+
post: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "POST", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, "POST", Query, Body>>;
|
|
97
|
+
put: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "PUT", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, "PUT", Query, Body>>;
|
|
98
|
+
patch: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "PATCH", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, "PATCH", Query, Body>>;
|
|
99
|
+
delete: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "DELETE", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, "DELETE", Query, Body>>;
|
|
100
|
+
head: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "HEAD", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, "HEAD", Query, Body>>;
|
|
101
|
+
options: <Result, Path extends string, Query extends AnyQueryDefinition = {}, Body extends Parsable = never>(path: Path, route: ((arg: RouteArgument<Path, ContextTo, { [Key in keyof Query]: InferParsable<Query[Key]>["output"]; }, InferParsable<Body>["output"]>) => Promise<Result>) | Omit<Route<ContextFrom, ContextTo, Result, Path, "OPTIONS", Query, Body>, "path" | "method" | "through">) => Router<ContextFrom, ContextTo, R | Route<ContextFrom, ContextTo, Result extends Response ? unknown : Result, Path, "OPTIONS", Query, Body>>;
|
|
75
102
|
through: <NextContext>(transform: (context: ContextTo) => Promise<NextContext>) => Router<ContextFrom, NextContext, R>;
|
|
76
103
|
}
|
|
77
104
|
|
|
@@ -87,13 +114,12 @@ type SuccessfulAPIResponse<T> = {
|
|
|
87
114
|
};
|
|
88
115
|
type APIResponse<T> = ErroredAPIResponse | SuccessfulAPIResponse<T>;
|
|
89
116
|
type AnyResponse = APIResponse<unknown>;
|
|
90
|
-
declare function apiresponse<T>(status: number, response: APIResponse<T>): Response;
|
|
91
117
|
type ExtractRouteParams<T extends string> = string extends T ? Record<string, string> : T extends `${string}:${infer Param}/${infer Rest}` ? {
|
|
92
118
|
[k in Param | keyof ExtractRouteParams<Rest>]: string;
|
|
93
119
|
} : T extends `${string}:${infer Param}` ? {
|
|
94
120
|
[k in Param]: string;
|
|
95
121
|
} : {};
|
|
96
|
-
type GetContext<Result> = (req: KaitoRequest) => Promise<Result>;
|
|
122
|
+
type GetContext<Result> = (req: KaitoRequest, res: KaitoResponse) => Promise<Result>;
|
|
97
123
|
/**
|
|
98
124
|
* A helper function to create typed necessary functions
|
|
99
125
|
*
|
|
@@ -146,4 +172,4 @@ type Route<ContextFrom, ContextTo, Result, Path extends string, Method extends K
|
|
|
146
172
|
};
|
|
147
173
|
type AnyRoute<ContextFrom = any, ContextTo = any> = Route<ContextFrom, ContextTo, any, any, any, AnyQueryDefinition, any>;
|
|
148
174
|
|
|
149
|
-
export { type APIResponse, type After, type AnyQueryDefinition, type AnyResponse, type AnyRoute, type Before, type ErroredAPIResponse, type ExtractRouteParams, type GetContext, type InferParsable, type InferRoutes, KaitoError, type KaitoMethod, KaitoRequest, type Parsable, type Route, type RouteArgument, Router, type RouterState, type ServerConfig, type ServerConfigWithBefore, type SuccessfulAPIResponse, type Through, WrappedError,
|
|
175
|
+
export { type APIResponse, type After, type AnyQueryDefinition, type AnyResponse, type AnyRoute, type Before, type ErroredAPIResponse, type ExtractRouteParams, type GetContext, type InferParsable, type InferRoutes, KaitoError, type KaitoMethod, KaitoRequest, type Parsable, type Route, type RouteArgument, Router, type RouterState, type ServerConfig, type ServerConfigWithBefore, type SuccessfulAPIResponse, type Through, WrappedError, createKaitoHandler, createUtilities, parsable };
|
package/dist/index.js
CHANGED
|
@@ -23,53 +23,77 @@ var KaitoError = class extends Error {
|
|
|
23
23
|
|
|
24
24
|
// src/request.ts
|
|
25
25
|
var KaitoRequest = class {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
constructor(request) {
|
|
29
|
-
this.
|
|
26
|
+
url;
|
|
27
|
+
_request;
|
|
28
|
+
constructor(url, request) {
|
|
29
|
+
this._request = request;
|
|
30
|
+
this.url = url;
|
|
30
31
|
}
|
|
31
32
|
get headers() {
|
|
32
|
-
return this.
|
|
33
|
+
return this._request.headers;
|
|
33
34
|
}
|
|
34
35
|
get method() {
|
|
35
|
-
return this.
|
|
36
|
-
}
|
|
37
|
-
get url() {
|
|
38
|
-
return this.request.url;
|
|
39
|
-
}
|
|
40
|
-
parseURL() {
|
|
41
|
-
if (!this._url) {
|
|
42
|
-
this._url = new URL(this.url);
|
|
43
|
-
}
|
|
44
|
-
return this._url;
|
|
36
|
+
return this._request.method;
|
|
45
37
|
}
|
|
46
38
|
async arrayBuffer() {
|
|
47
|
-
return this.
|
|
39
|
+
return this._request.arrayBuffer();
|
|
48
40
|
}
|
|
49
41
|
async blob() {
|
|
50
|
-
return this.
|
|
42
|
+
return this._request.blob();
|
|
51
43
|
}
|
|
52
44
|
async formData() {
|
|
53
|
-
return this.
|
|
45
|
+
return this._request.formData();
|
|
54
46
|
}
|
|
55
47
|
async bytes() {
|
|
56
48
|
const buffer = await this.arrayBuffer();
|
|
57
49
|
return new Uint8Array(buffer);
|
|
58
50
|
}
|
|
59
51
|
async json() {
|
|
60
|
-
return this.
|
|
52
|
+
return this._request.json();
|
|
61
53
|
}
|
|
62
54
|
async text() {
|
|
63
|
-
return this.
|
|
55
|
+
return this._request.text();
|
|
56
|
+
}
|
|
57
|
+
get request() {
|
|
58
|
+
return this._request;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// src/response.ts
|
|
63
|
+
var KaitoResponse = class {
|
|
64
|
+
_headers;
|
|
65
|
+
_status;
|
|
66
|
+
constructor() {
|
|
67
|
+
this._headers = null;
|
|
68
|
+
this._status = 200;
|
|
69
|
+
}
|
|
70
|
+
get headers() {
|
|
71
|
+
if (this._headers === null) {
|
|
72
|
+
this._headers = new Headers();
|
|
73
|
+
}
|
|
74
|
+
return this._headers;
|
|
75
|
+
}
|
|
76
|
+
status(status) {
|
|
77
|
+
this._status = status;
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Turn this KaitoResponse instance into a Response instance
|
|
82
|
+
* @param body The Kaito JSON format to be sent as the response body
|
|
83
|
+
* @returns A Response instance, ready to be sent
|
|
84
|
+
*/
|
|
85
|
+
toResponse(body) {
|
|
86
|
+
const init = {
|
|
87
|
+
status: this._status
|
|
88
|
+
};
|
|
89
|
+
if (this._headers) {
|
|
90
|
+
init.headers = this._headers;
|
|
91
|
+
}
|
|
92
|
+
return Response.json(body, init);
|
|
64
93
|
}
|
|
65
94
|
};
|
|
66
95
|
|
|
67
96
|
// src/util.ts
|
|
68
|
-
function apiresponse(status, response) {
|
|
69
|
-
return Response.json(response, {
|
|
70
|
-
status
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
97
|
function createUtilities(getContext) {
|
|
74
98
|
return {
|
|
75
99
|
getContext,
|
|
@@ -108,6 +132,7 @@ var Router = class _Router {
|
|
|
108
132
|
}
|
|
109
133
|
add = (method, path, route) => {
|
|
110
134
|
const merged = {
|
|
135
|
+
// TODO: Ideally fix the typing here, but this will be replaced in Kaito v4 where all routes must return a Response (which we can type)
|
|
111
136
|
...typeof route === "object" ? route : { run: route },
|
|
112
137
|
method,
|
|
113
138
|
path,
|
|
@@ -165,15 +190,17 @@ var Router = class _Router {
|
|
|
165
190
|
const method = req.method;
|
|
166
191
|
const { route, params } = findRoute(method, url.pathname);
|
|
167
192
|
if (!route) {
|
|
168
|
-
|
|
193
|
+
const body = {
|
|
169
194
|
success: false,
|
|
170
195
|
data: null,
|
|
171
196
|
message: `Cannot ${method} ${url.pathname}`
|
|
172
|
-
}
|
|
197
|
+
};
|
|
198
|
+
return Response.json(body, { status: 404 });
|
|
173
199
|
}
|
|
174
|
-
const request = new KaitoRequest(req);
|
|
200
|
+
const request = new KaitoRequest(url, req);
|
|
201
|
+
const response = new KaitoResponse();
|
|
175
202
|
try {
|
|
176
|
-
const rootCtx = await server.getContext(request);
|
|
203
|
+
const rootCtx = await server.getContext(request, response);
|
|
177
204
|
const ctx = await route.through(rootCtx);
|
|
178
205
|
const body = route.body ? await route.body.parse(await req.json()) : void 0;
|
|
179
206
|
const query = _Router.parseQuery(route.query, url);
|
|
@@ -183,7 +210,10 @@ var Router = class _Router {
|
|
|
183
210
|
query,
|
|
184
211
|
params
|
|
185
212
|
});
|
|
186
|
-
|
|
213
|
+
if (result instanceof Response) {
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
return response.toResponse({
|
|
187
217
|
success: true,
|
|
188
218
|
data: result,
|
|
189
219
|
message: "OK"
|
|
@@ -191,14 +221,14 @@ var Router = class _Router {
|
|
|
191
221
|
} catch (e) {
|
|
192
222
|
const error = WrappedError.maybe(e);
|
|
193
223
|
if (error instanceof KaitoError) {
|
|
194
|
-
return
|
|
224
|
+
return response.status(error.status).toResponse({
|
|
195
225
|
success: false,
|
|
196
226
|
data: null,
|
|
197
227
|
message: error.message
|
|
198
228
|
});
|
|
199
229
|
}
|
|
200
230
|
const { status, message } = await server.onError({ error, req: request }).catch(() => ({ status: 500, message: "Internal Server Error" }));
|
|
201
|
-
return
|
|
231
|
+
return response.status(status).toResponse({
|
|
202
232
|
success: false,
|
|
203
233
|
data: null,
|
|
204
234
|
message
|
|
@@ -249,7 +279,6 @@ export {
|
|
|
249
279
|
KaitoRequest,
|
|
250
280
|
Router,
|
|
251
281
|
WrappedError,
|
|
252
|
-
apiresponse,
|
|
253
282
|
createKaitoHandler,
|
|
254
283
|
createUtilities,
|
|
255
284
|
parsable
|