@kaito-http/core 3.0.0-beta.7 → 3.0.1
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 +344 -0
- package/dist/index.d.cts +255 -0
- package/dist/index.d.ts +166 -148
- package/dist/index.js +220 -301
- package/dist/stream/stream.cjs +134 -0
- package/dist/stream/stream.d.cts +36 -0
- package/dist/stream/stream.d.ts +36 -0
- package/dist/stream/stream.js +105 -0
- package/package.json +24 -15
- package/src/error.ts +26 -0
- package/src/handler.ts +96 -0
- package/src/head.ts +83 -0
- package/src/index.ts +7 -0
- package/src/request.ts +47 -0
- package/src/route.ts +52 -0
- package/src/router/router.test.ts +269 -0
- package/src/router/router.ts +264 -0
- package/src/router/types.ts +1 -0
- package/src/stream/stream.ts +156 -0
- package/src/util.ts +83 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
import * as find_my_way from 'find-my-way';
|
|
2
|
-
import find_my_way__default, { HTTPMethod } from 'find-my-way';
|
|
3
|
-
export { HTTPMethod } from 'find-my-way';
|
|
4
|
-
import * as http from 'http';
|
|
5
|
-
import * as http$1 from 'node:http';
|
|
6
|
-
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
7
|
-
import { CookieSerializeOptions } from 'cookie';
|
|
8
|
-
|
|
9
1
|
declare class WrappedError<T> extends Error {
|
|
10
2
|
readonly data: T;
|
|
11
3
|
static maybe<T>(maybeError: T): (T & Error) | WrappedError<T>;
|
|
@@ -18,36 +10,72 @@ declare class KaitoError extends Error {
|
|
|
18
10
|
}
|
|
19
11
|
|
|
20
12
|
declare class KaitoRequest {
|
|
21
|
-
readonly
|
|
22
|
-
private
|
|
23
|
-
constructor(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
get
|
|
13
|
+
readonly url: URL;
|
|
14
|
+
private readonly _request;
|
|
15
|
+
constructor(url: URL, request: Request);
|
|
16
|
+
get headers(): Headers;
|
|
17
|
+
get method(): string;
|
|
18
|
+
arrayBuffer(): Promise<ArrayBuffer>;
|
|
19
|
+
blob(): Promise<Blob>;
|
|
20
|
+
formData(): Promise<FormData>;
|
|
21
|
+
bytes(): Promise<Uint8Array>;
|
|
22
|
+
json(): Promise<unknown>;
|
|
23
|
+
text(): Promise<string>;
|
|
24
|
+
get request(): Request;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
type KaitoMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS' | 'CONNECT' | 'TRACE';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* This class is merely a wrapper around a `Headers` object and a status code.
|
|
31
|
+
* It's used while the router is executing a route to store any mutations to the status
|
|
32
|
+
* code or headers that the developer may want to make.
|
|
33
|
+
*
|
|
34
|
+
* This exists because there's otherwise no way to indicate back to Kaito that
|
|
35
|
+
* the developer wants to change the status code or headers.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* const response = new KaitoHead();
|
|
40
|
+
*
|
|
41
|
+
* response.status(200);
|
|
42
|
+
* response.headers.set('Content-Type', 'application/json');
|
|
43
|
+
*
|
|
44
|
+
* console.log(response.headers); // Headers {'content-type': 'application/json'}
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
declare class KaitoHead {
|
|
48
|
+
private _headers;
|
|
49
|
+
private _status;
|
|
50
|
+
constructor();
|
|
51
|
+
get headers(): Headers;
|
|
33
52
|
/**
|
|
34
|
-
*
|
|
53
|
+
* Gets the status code of this KaitoHead instance
|
|
54
|
+
* @returns The status code
|
|
35
55
|
*/
|
|
36
|
-
|
|
56
|
+
status(): number;
|
|
37
57
|
/**
|
|
38
|
-
*
|
|
58
|
+
* Sets the status code of this KaitoHead instance
|
|
59
|
+
* @param status The status code to set
|
|
60
|
+
* @returns This KaitoHead instance
|
|
39
61
|
*/
|
|
40
|
-
|
|
62
|
+
status(status: number): this;
|
|
41
63
|
/**
|
|
42
|
-
*
|
|
64
|
+
* Turn this KaitoHead instance into a Response instance
|
|
65
|
+
* @param body The Kaito JSON format to be sent as the response body
|
|
66
|
+
* @returns A Response instance, ready to be sent
|
|
43
67
|
*/
|
|
44
|
-
|
|
68
|
+
toResponse<T>(body: APIResponse<T>): Response;
|
|
45
69
|
/**
|
|
46
|
-
*
|
|
70
|
+
* Whether this KaitoHead instance has been touched/modified
|
|
47
71
|
*/
|
|
48
|
-
get
|
|
72
|
+
get touched(): boolean;
|
|
49
73
|
}
|
|
50
74
|
|
|
75
|
+
/**
|
|
76
|
+
* A helper to check if the environment is Node.js-like and the NODE_ENV is development
|
|
77
|
+
*/
|
|
78
|
+
declare const isNodeLikeDev: boolean;
|
|
51
79
|
type ErroredAPIResponse = {
|
|
52
80
|
success: false;
|
|
53
81
|
data: null;
|
|
@@ -60,120 +88,24 @@ type SuccessfulAPIResponse<T> = {
|
|
|
60
88
|
};
|
|
61
89
|
type APIResponse<T> = ErroredAPIResponse | SuccessfulAPIResponse<T>;
|
|
62
90
|
type AnyResponse = APIResponse<unknown>;
|
|
63
|
-
|
|
64
|
-
readonly raw: ServerResponse;
|
|
65
|
-
constructor(raw: ServerResponse);
|
|
66
|
-
/**
|
|
67
|
-
* Send a response
|
|
68
|
-
* @param key The key of the header
|
|
69
|
-
* @param value The value of the header
|
|
70
|
-
* @returns The response object
|
|
71
|
-
*/
|
|
72
|
-
header(key: string, value: string | readonly string[]): this;
|
|
73
|
-
/**
|
|
74
|
-
* Set the status code of the response
|
|
75
|
-
* @param code The status code
|
|
76
|
-
* @returns The response object
|
|
77
|
-
*/
|
|
78
|
-
status(code: number): this;
|
|
79
|
-
/**
|
|
80
|
-
* Set a cookie
|
|
81
|
-
* @param name The name of the cookie
|
|
82
|
-
* @param value The value of the cookie
|
|
83
|
-
* @param options The options for the cookie
|
|
84
|
-
* @returns The response object
|
|
85
|
-
*/
|
|
86
|
-
cookie(name: string, value: string, options: CookieSerializeOptions): this;
|
|
87
|
-
/**
|
|
88
|
-
* Send a JSON APIResponse body
|
|
89
|
-
* @param data The data to send
|
|
90
|
-
* @returns The response object
|
|
91
|
-
*/
|
|
92
|
-
json(data: APIResponse<T>): this;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
type Before<BeforeAfterContext> = (req: http$1.IncomingMessage, res: http$1.ServerResponse) => Promise<BeforeAfterContext>;
|
|
96
|
-
type HandlerResult = {
|
|
97
|
-
success: true;
|
|
98
|
-
data: unknown;
|
|
99
|
-
} | {
|
|
100
|
-
success: false;
|
|
101
|
-
data: {
|
|
102
|
-
status: number;
|
|
103
|
-
message: string;
|
|
104
|
-
};
|
|
105
|
-
};
|
|
106
|
-
type After<BeforeAfterContext> = (ctx: BeforeAfterContext, result: HandlerResult) => Promise<void>;
|
|
107
|
-
type ServerConfigWithBefore<BeforeAfterContext> = {
|
|
108
|
-
before: Before<BeforeAfterContext>;
|
|
109
|
-
after?: After<BeforeAfterContext>;
|
|
110
|
-
} | {
|
|
111
|
-
before?: undefined;
|
|
112
|
-
};
|
|
113
|
-
type ServerConfig<ContextFrom, BeforeAfterContext> = ServerConfigWithBefore<BeforeAfterContext> & {
|
|
114
|
-
router: Router<ContextFrom, unknown, any>;
|
|
115
|
-
getContext: GetContext<ContextFrom>;
|
|
116
|
-
rawRoutes?: Partial<Record<KaitoMethod, Array<{
|
|
117
|
-
path: string;
|
|
118
|
-
handler: (request: http$1.IncomingMessage, response: http$1.ServerResponse) => unknown;
|
|
119
|
-
}>>>;
|
|
120
|
-
onError(arg: {
|
|
121
|
-
error: Error;
|
|
122
|
-
req: KaitoRequest;
|
|
123
|
-
res: KaitoResponse;
|
|
124
|
-
}): Promise<KaitoError | {
|
|
125
|
-
status: number;
|
|
126
|
-
message: string;
|
|
127
|
-
}>;
|
|
128
|
-
};
|
|
129
|
-
declare function createFMWServer<Context, BeforeAfterContext = null>(config: ServerConfig<Context, BeforeAfterContext>): {
|
|
130
|
-
readonly server: http$1.Server<typeof http$1.IncomingMessage, typeof http$1.ServerResponse>;
|
|
131
|
-
readonly fmw: find_my_way.Instance<find_my_way.HTTPVersion.V1>;
|
|
132
|
-
};
|
|
133
|
-
declare function createServer<Context, BeforeAfterContext = null>(config: ServerConfig<Context, BeforeAfterContext>): http$1.Server<typeof http$1.IncomingMessage, typeof http$1.ServerResponse>;
|
|
134
|
-
|
|
135
|
-
type PrefixRoutesPathInner<R extends AnyRoute, Prefix extends `/${string}`> = R extends Route<infer ContextFrom, infer ContextTo, infer Result, infer Path, infer Method, infer Query, infer BodyOutput> ? Route<ContextFrom, ContextTo, Result, `${Prefix}${Path}`, Method, Query, BodyOutput> : never;
|
|
136
|
-
type PrefixRoutesPath<Prefix extends `/${string}`, R extends AnyRoute> = R extends R ? PrefixRoutesPathInner<R, Prefix> : never;
|
|
137
|
-
type RouterOptions<ContextFrom, ContextTo> = {
|
|
138
|
-
through: (context: ContextFrom) => Promise<ContextTo>;
|
|
139
|
-
};
|
|
140
|
-
type InferRoutes<R extends Router<any, any, any>> = R extends Router<any, any, infer R> ? R : never;
|
|
141
|
-
declare class Router<ContextFrom, ContextTo, R extends AnyRoute> {
|
|
142
|
-
private readonly routerOptions;
|
|
143
|
-
readonly routes: Set<R>;
|
|
144
|
-
static create: <Context>() => Router<Context, Context, never>;
|
|
145
|
-
private static parseQuery;
|
|
146
|
-
private static handle;
|
|
147
|
-
constructor(routes: Iterable<R>, options: RouterOptions<ContextFrom, ContextTo>);
|
|
148
|
-
/**
|
|
149
|
-
* Adds a new route to the router
|
|
150
|
-
* @deprecated Use the method-specific methods instead
|
|
151
|
-
*/
|
|
152
|
-
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>>;
|
|
153
|
-
readonly merge: <PathPrefix extends `/${string}`, OtherRoutes extends AnyRoute>(pathPrefix: PathPrefix, other: Router<ContextFrom, unknown, OtherRoutes>) => Router<ContextFrom, ContextTo, Extract<R | PrefixRoutesPath<PathPrefix, OtherRoutes>, AnyRoute>>;
|
|
154
|
-
freeze: (server: ServerConfig<ContextFrom, any>) => find_my_way__default.Instance<find_my_way__default.HTTPVersion.V1>;
|
|
155
|
-
private readonly method;
|
|
156
|
-
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>>;
|
|
157
|
-
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>>;
|
|
158
|
-
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>>;
|
|
159
|
-
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>>;
|
|
160
|
-
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>>;
|
|
161
|
-
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>>;
|
|
162
|
-
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>>;
|
|
163
|
-
through: <NextContext>(transform: (context: ContextTo) => Promise<NextContext>) => Router<ContextFrom, NextContext, R>;
|
|
164
|
-
}
|
|
165
|
-
|
|
91
|
+
type MakeOptional<T, K extends keyof T> = T extends T ? Omit<T, K> & Partial<Pick<T, K>> : never;
|
|
166
92
|
type ExtractRouteParams<T extends string> = string extends T ? Record<string, string> : T extends `${string}:${infer Param}/${infer Rest}` ? {
|
|
167
93
|
[k in Param | keyof ExtractRouteParams<Rest>]: string;
|
|
168
94
|
} : T extends `${string}:${infer Param}` ? {
|
|
169
95
|
[k in Param]: string;
|
|
170
96
|
} : {};
|
|
171
|
-
type KaitoMethod = HTTPMethod | '*';
|
|
172
|
-
type GetContext<Result> = (req: KaitoRequest, res: KaitoResponse) => Promise<Result>;
|
|
173
97
|
/**
|
|
174
|
-
*
|
|
98
|
+
* A function that is called to get the context for a request.
|
|
99
|
+
*
|
|
100
|
+
* This is useful for things like authentication, to pass in a database connection, etc.
|
|
101
|
+
*
|
|
102
|
+
* It's fine for this function to throw; if it does, the error is passed to the `onError` function.
|
|
103
|
+
*
|
|
104
|
+
* @param req - The kaito request object, which contains the request method, url, headers, etc
|
|
105
|
+
* @param head - The kaito head object, which contains getters and setters for headers and status
|
|
106
|
+
* @returns The context for your routes
|
|
175
107
|
*/
|
|
176
|
-
|
|
108
|
+
type GetContext<Result> = (req: KaitoRequest, head: KaitoHead) => Promise<Result>;
|
|
177
109
|
/**
|
|
178
110
|
* A helper function to create typed necessary functions
|
|
179
111
|
*
|
|
@@ -185,7 +117,7 @@ declare function createGetContext<Context>(callback: GetContext<Context>): GetCo
|
|
|
185
117
|
*
|
|
186
118
|
* const app = router().get('/', async () => "hello");
|
|
187
119
|
*
|
|
188
|
-
* const server =
|
|
120
|
+
* const server = createKaitoHandler({
|
|
189
121
|
* router: app,
|
|
190
122
|
* getContext,
|
|
191
123
|
* // ...
|
|
@@ -196,8 +128,6 @@ declare function createUtilities<Context>(getContext: GetContext<Context>): {
|
|
|
196
128
|
getContext: GetContext<Context>;
|
|
197
129
|
router: () => Router<Context, Context, never>;
|
|
198
130
|
};
|
|
199
|
-
type InferContext<T> = T extends (req: KaitoRequest, res: KaitoResponse) => Promise<infer U> ? U : never;
|
|
200
|
-
declare function getLastEntryInMultiHeaderValue(headerValue: string | string[]): string;
|
|
201
131
|
interface Parsable<Output = any, Input = Output> {
|
|
202
132
|
_input: Input;
|
|
203
133
|
parse: (value: unknown) => Output;
|
|
@@ -207,12 +137,6 @@ type InferParsable<T> = T extends Parsable<infer Output, infer Input> ? {
|
|
|
207
137
|
output: Output;
|
|
208
138
|
} : never;
|
|
209
139
|
declare function parsable<T>(parse: (value: unknown) => T): Parsable<T, T>;
|
|
210
|
-
type RemoveEndSlashes<T extends string> = T extends `${infer U}/` ? U : T;
|
|
211
|
-
type AddStartSlashes<T extends string> = T extends `/${infer U}` ? `/${U}` : `/${T}`;
|
|
212
|
-
type NormalizePath<T extends string> = AddStartSlashes<RemoveEndSlashes<T>>;
|
|
213
|
-
type Values<T> = T[keyof T];
|
|
214
|
-
type NoEmpty<T> = [keyof T] extends [never] ? never : T;
|
|
215
|
-
declare function getBody(req: KaitoRequest): Promise<unknown>;
|
|
216
140
|
|
|
217
141
|
type RouteArgument<Path extends string, Context, QueryOutput, BodyOutput> = {
|
|
218
142
|
ctx: Context;
|
|
@@ -221,9 +145,9 @@ type RouteArgument<Path extends string, Context, QueryOutput, BodyOutput> = {
|
|
|
221
145
|
params: ExtractRouteParams<Path>;
|
|
222
146
|
};
|
|
223
147
|
type AnyQueryDefinition = Record<string, Parsable<any, string | undefined>>;
|
|
224
|
-
type
|
|
148
|
+
type Through<From, To> = (context: From) => Promise<To>;
|
|
225
149
|
type Route<ContextFrom, ContextTo, Result, Path extends string, Method extends KaitoMethod, Query extends AnyQueryDefinition, Body extends Parsable> = {
|
|
226
|
-
through:
|
|
150
|
+
through: Through<ContextFrom, ContextTo>;
|
|
227
151
|
body?: Body;
|
|
228
152
|
query?: Query;
|
|
229
153
|
path: Path;
|
|
@@ -232,6 +156,100 @@ type Route<ContextFrom, ContextTo, Result, Path extends string, Method extends K
|
|
|
232
156
|
[Key in keyof Query]: InferParsable<Query[Key]>['output'];
|
|
233
157
|
}, InferParsable<Body>['output']>): Promise<Result>;
|
|
234
158
|
};
|
|
235
|
-
type AnyRoute<
|
|
159
|
+
type AnyRoute<ContextFrom = any, ContextTo = any> = Route<ContextFrom, ContextTo, any, any, any, AnyQueryDefinition, any>;
|
|
160
|
+
|
|
161
|
+
type PrefixRoutesPathInner<R extends AnyRoute, Prefix extends `/${string}`> = R extends Route<infer ContextFrom, infer ContextTo, infer Result, infer Path, infer Method, infer Query, infer BodyOutput> ? Route<ContextFrom, ContextTo, Result, `${Prefix}${Path}`, Method, Query, BodyOutput> : never;
|
|
162
|
+
type PrefixRoutesPath<Prefix extends `/${string}`, R extends AnyRoute> = R extends R ? PrefixRoutesPathInner<R, Prefix> : never;
|
|
163
|
+
type RouterState<Routes extends AnyRoute, ContextFrom, ContextTo> = {
|
|
164
|
+
routes: Set<Routes>;
|
|
165
|
+
through: (context: ContextFrom) => Promise<ContextTo>;
|
|
166
|
+
};
|
|
167
|
+
type InferRoutes<R extends Router<any, any, any>> = R extends Router<any, any, infer R> ? R : never;
|
|
168
|
+
declare class Router<ContextFrom, ContextTo, R extends AnyRoute> {
|
|
169
|
+
private readonly state;
|
|
170
|
+
static create: <Context>() => Router<Context, Context, never>;
|
|
171
|
+
private static parseQuery;
|
|
172
|
+
constructor(options: RouterState<R, ContextFrom, ContextTo>);
|
|
173
|
+
get routes(): Set<R>;
|
|
174
|
+
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>>;
|
|
175
|
+
readonly merge: <PathPrefix extends `/${string}`, OtherRoutes extends AnyRoute>(pathPrefix: PathPrefix, other: Router<ContextFrom, unknown, OtherRoutes>) => Router<ContextFrom, ContextTo, Extract<R | PrefixRoutesPath<PathPrefix, OtherRoutes>, AnyRoute>>;
|
|
176
|
+
freeze: (server: Omit<HandlerConfig<ContextFrom>, "router">) => (req: Request) => Promise<Response>;
|
|
177
|
+
private readonly method;
|
|
178
|
+
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>>;
|
|
179
|
+
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>>;
|
|
180
|
+
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>>;
|
|
181
|
+
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>>;
|
|
182
|
+
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>>;
|
|
183
|
+
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>>;
|
|
184
|
+
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>>;
|
|
185
|
+
through: <NextContext>(through: (context: ContextTo) => Promise<NextContext>) => Router<ContextFrom, NextContext, R>;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
type HandlerConfig<ContextFrom> = {
|
|
189
|
+
/**
|
|
190
|
+
* The root router to mount on this handler.
|
|
191
|
+
*/
|
|
192
|
+
router: Router<ContextFrom, unknown, any>;
|
|
193
|
+
/**
|
|
194
|
+
* A function that is called to get the context for a request.
|
|
195
|
+
*
|
|
196
|
+
* This is useful for things like authentication, to pass in a database connection, etc.
|
|
197
|
+
*
|
|
198
|
+
* It's fine for this function to throw; if it does, the error is passed to the `onError` function.
|
|
199
|
+
*/
|
|
200
|
+
getContext: GetContext<ContextFrom>;
|
|
201
|
+
/**
|
|
202
|
+
* A function that is called when an error occurs inside a route handler.
|
|
203
|
+
*
|
|
204
|
+
* The result of this function is used to determine the response status and message, and is
|
|
205
|
+
* always sent to the client. You could include logic to check for production vs development
|
|
206
|
+
* environments here, and this would also be a good place to include error tracking
|
|
207
|
+
* like Sentry or Rollbar.
|
|
208
|
+
*
|
|
209
|
+
* @param arg - The error thrown, and the KaitoRequest instance
|
|
210
|
+
* @returns A KaitoError or an object with a status and message
|
|
211
|
+
*/
|
|
212
|
+
onError: (arg: {
|
|
213
|
+
error: Error;
|
|
214
|
+
req: KaitoRequest;
|
|
215
|
+
}) => Promise<KaitoError | {
|
|
216
|
+
status: number;
|
|
217
|
+
message: string;
|
|
218
|
+
}>;
|
|
219
|
+
/**
|
|
220
|
+
* A function that is called before every request. Most useful for bailing out early in the case of an OPTIONS request.
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```ts
|
|
224
|
+
* before: async req => {
|
|
225
|
+
* if (req.method === 'OPTIONS') {
|
|
226
|
+
* return new Response(null, {status: 204});
|
|
227
|
+
* }
|
|
228
|
+
* }
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
before?: (req: Request) => Promise<Response | void | undefined>;
|
|
232
|
+
/**
|
|
233
|
+
* Transforms the response before it is sent to the client. Very useful for settings headers like CORS.
|
|
234
|
+
*
|
|
235
|
+
* You can also return a new response in this function, or just mutate the current one.
|
|
236
|
+
*
|
|
237
|
+
* This function WILL receive the result of `.before()` if you return a response from it. This means
|
|
238
|
+
* you only need to define headers in a single place.
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* ```ts
|
|
242
|
+
* transform: async (req, res) => {
|
|
243
|
+
* res.headers.set('Access-Control-Allow-Origin', 'http://localhost:3000');
|
|
244
|
+
* res.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
|
245
|
+
* res.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
246
|
+
* res.headers.set('Access-Control-Max-Age', '86400');
|
|
247
|
+
* res.headers.set('Access-Control-Allow-Credentials', 'true');
|
|
248
|
+
* }
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
transform?: (req: Request, res: Response) => Promise<Response | void | undefined>;
|
|
252
|
+
};
|
|
253
|
+
declare function createKaitoHandler<Context>(config: HandlerConfig<Context>): (request: Request) => Promise<Response>;
|
|
236
254
|
|
|
237
|
-
export { type APIResponse, type
|
|
255
|
+
export { type APIResponse, type AnyQueryDefinition, type AnyResponse, type AnyRoute, type ErroredAPIResponse, type ExtractRouteParams, type GetContext, type HandlerConfig, type InferParsable, type InferRoutes, KaitoError, type KaitoMethod, KaitoRequest, type MakeOptional, type Parsable, type Route, type RouteArgument, Router, type RouterState, type SuccessfulAPIResponse, type Through, WrappedError, createKaitoHandler, createUtilities, isNodeLikeDev, parsable };
|