@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.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 raw: IncomingMessage;
22
- private _url;
23
- constructor(raw: IncomingMessage);
24
- /**
25
- * The full URL of the request, including the protocol, hostname, and path.
26
- * Note: does not include the query string or hash
27
- */
28
- get fullURL(): string;
29
- /**
30
- * A new URL instance for the full URL of the request.
31
- */
32
- get url(): URL;
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
- * The HTTP method of the request.
53
+ * Gets the status code of this KaitoHead instance
54
+ * @returns The status code
35
55
  */
36
- get method(): HTTPMethod;
56
+ status(): number;
37
57
  /**
38
- * The protocol of the request, either `http` or `https`.
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
- get protocol(): 'http' | 'https';
62
+ status(status: number): this;
41
63
  /**
42
- * The request headers
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
- get headers(): http.IncomingHttpHeaders;
68
+ toResponse<T>(body: APIResponse<T>): Response;
45
69
  /**
46
- * The hostname of the request.
70
+ * Whether this KaitoHead instance has been touched/modified
47
71
  */
48
- get hostname(): string;
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
- declare class KaitoResponse<T = unknown> {
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
- * @deprecated use `createUtilities` instead
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
- declare function createGetContext<Context>(callback: GetContext<Context>): GetContext<Context>;
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 = createServer({
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 RouteRunner<Result, Path extends string, Context, QueryOutput, BodyOutput> = (args: RouteArgument<Path, Context, QueryOutput, BodyOutput>) => Promise<Result>;
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: (context: ContextFrom) => Promise<ContextTo>;
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<FromContext = any, ToContext = any> = Route<FromContext, ToContext, any, any, any, AnyQueryDefinition, any>;
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 AddStartSlashes, type After, type AnyQueryDefinition, type AnyResponse, type AnyRoute, type Before, type ErroredAPIResponse, type ExtractRouteParams, type GetContext, type HandlerResult, type InferContext, type InferParsable, type InferRoutes, KaitoError, type KaitoMethod, KaitoRequest, KaitoResponse, type NoEmpty, type NormalizePath, type Parsable, type RemoveEndSlashes, type Route, type RouteArgument, type RouteRunner, Router, type RouterOptions, type ServerConfig, type ServerConfigWithBefore, type SuccessfulAPIResponse, type Values, WrappedError, createFMWServer, createGetContext, createServer, createUtilities, getBody, getLastEntryInMultiHeaderValue, parsable };
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 };