@kaito-http/core 4.0.0-beta.24 → 4.0.0-beta.25

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 CHANGED
@@ -101,14 +101,14 @@ var KaitoHead = class {
101
101
  * @param body The Kaito JSON format to be sent as the response body
102
102
  * @returns A Response instance, ready to be sent
103
103
  */
104
- toResponse(body) {
104
+ toResponse(data) {
105
105
  const init = {
106
106
  status: this.#status
107
107
  };
108
108
  if (this.#headers) {
109
109
  init.headers = this.#headers;
110
110
  }
111
- return Response.json(body, init);
111
+ return Response.json(data, init);
112
112
  }
113
113
  /**
114
114
  * Whether this KaitoHead instance has been touched/modified
@@ -1093,12 +1093,7 @@ var Router = class _Router {
1093
1093
  const method = req.method;
1094
1094
  const { route, params: rawParams } = findRoute(method, url.pathname);
1095
1095
  if (!route) {
1096
- const body = {
1097
- success: false,
1098
- data: null,
1099
- message: `Cannot ${method} ${url.pathname}`
1100
- };
1101
- return Response.json(body, { status: 404 });
1096
+ return Response.json({ message: `Cannot ${method} ${url.pathname}` }, { status: 404 });
1102
1097
  }
1103
1098
  const request = new KaitoRequest(url, req);
1104
1099
  const head = new KaitoHead();
@@ -1136,44 +1131,30 @@ var Router = class _Router {
1136
1131
  );
1137
1132
  }
1138
1133
  const parsed = route.openapi.schema.serialize(result);
1139
- return head.toResponse({
1140
- success: true,
1141
- data: parsed
1142
- });
1134
+ return head.toResponse(parsed);
1143
1135
  }
1144
- return head.toResponse({
1145
- success: true,
1146
- data: result
1147
- });
1136
+ return head.toResponse(result);
1148
1137
  } catch (e) {
1149
1138
  const error = WrappedError.maybe(e);
1150
1139
  if (error instanceof KaitoError) {
1151
1140
  return head.status(error.status).toResponse({
1152
- success: false,
1153
- data: null,
1154
1141
  message: error.message
1155
1142
  });
1156
1143
  }
1157
1144
  if (!this.#state.config.onError) {
1158
1145
  return head.status(500).toResponse({
1159
- success: false,
1160
- data: null,
1161
1146
  message: "Internal Server Error"
1162
1147
  });
1163
1148
  }
1164
1149
  try {
1165
1150
  const { status, message } = await this.#state.config.onError(error, request);
1166
1151
  return head.status(status).toResponse({
1167
- success: false,
1168
- data: null,
1169
1152
  message
1170
1153
  });
1171
1154
  } catch (e2) {
1172
1155
  console.error("[Kaito] Failed to handle error inside `.onError()`, returning 500 and Internal Server Error");
1173
1156
  console.error(e2);
1174
1157
  return head.status(500).toResponse({
1175
- success: false,
1176
- data: null,
1177
1158
  message: "Internal Server Error"
1178
1159
  });
1179
1160
  }
@@ -1202,6 +1183,27 @@ var Router = class _Router {
1202
1183
  return response;
1203
1184
  };
1204
1185
  };
1186
+ /**
1187
+ * Create a `/openapi.json` route on this router.
1188
+ *
1189
+ * Any routes defined AFTER this method call will NOT be included in the
1190
+ * file. This is because all methods in Kaito are immutable, so there's no
1191
+ * way for the router to know about routes that were created in the future
1192
+ * on another router.
1193
+ *
1194
+ * @example
1195
+ * ```ts
1196
+ * router.get("/", () => "hey").openapi({
1197
+ * info: {
1198
+ * title: "My API",
1199
+ * version: "1.0.0",
1200
+ * },
1201
+ * });
1202
+ * ```
1203
+ *
1204
+ * @param options Options object
1205
+ * @returns
1206
+ */
1205
1207
  openapi = ({
1206
1208
  info,
1207
1209
  servers
@@ -1264,10 +1266,7 @@ var Router = class _Router {
1264
1266
  description: route.openapi?.description ?? "Successful response",
1265
1267
  content: {
1266
1268
  [contentType]: {
1267
- schema: k.object({
1268
- success: k.literal(true),
1269
- data: route.openapi.schema
1270
- }).toOpenAPI()
1269
+ schema: route.openapi.schema.toOpenAPI()
1271
1270
  }
1272
1271
  }
1273
1272
  }
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as OpenAPI from 'openapi3-ts/oas31';
2
- import { JSONValue, AnySchemaFor, BaseSchema, BaseSchemaDef } from './schema/schema.cjs';
2
+ import { JSONValue as JSONValue$1, AnySchemaFor, BaseSchema, BaseSchemaDef } from './schema/schema.cjs';
3
3
  export { ArrayChecks, ArrayDef, BooleanDef, Issue, JSONPrimitive, KArray, KBoolean, KLiteral, KNull, KNumber, KObject, KObjectFromURLSearchParams, KRef, KScalar, KString, KUnion, LiteralDef, NullDef, NumberChecks, NumberDef, NumberFormat, ObjectDef, ParseContext, ParseResult, RefDef, STRING_FORMAT_REGEXES, ScalarDef, ScalarOptions, SchemaError, StringChecks, StringDef, StringFormat, UnionDef, isPrimitiveJSONValue, k } from './schema/schema.cjs';
4
4
  import { KaitoSSEResponse } from './stream/stream.cjs';
5
5
 
@@ -29,6 +29,11 @@ declare class KaitoRequest {
29
29
  get request(): Request;
30
30
  }
31
31
 
32
+ type JSONPrimitive = string | number | boolean | null;
33
+ type JSONValue = JSONPrimitive | JSONValue[] | {
34
+ [key: string]: JSONValue;
35
+ };
36
+
32
37
  /**
33
38
  * This class is merely a wrapper around a `Headers` object and a status code.
34
39
  * It's used while the router is executing a route to store any mutations to the status
@@ -67,7 +72,7 @@ declare class KaitoHead {
67
72
  * @param body The Kaito JSON format to be sent as the response body
68
73
  * @returns A Response instance, ready to be sent
69
74
  */
70
- toResponse<T>(body: APIResponse<T>): Response;
75
+ toResponse<T extends JSONValue>(data: T): Response;
71
76
  /**
72
77
  * Whether this KaitoHead instance has been touched/modified
73
78
  */
@@ -97,18 +102,39 @@ declare class Router<ContextFrom, ContextTo, RequiredParams extends string, Rout
97
102
  params: Record<string, string>;
98
103
  };
99
104
  serve: () => (request: Request, ...args: Input) => Promise<Response>;
105
+ /**
106
+ * Create a `/openapi.json` route on this router.
107
+ *
108
+ * Any routes defined AFTER this method call will NOT be included in the
109
+ * file. This is because all methods in Kaito are immutable, so there's no
110
+ * way for the router to know about routes that were created in the future
111
+ * on another router.
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * router.get("/", () => "hey").openapi({
116
+ * info: {
117
+ * title: "My API",
118
+ * version: "1.0.0",
119
+ * },
120
+ * });
121
+ * ```
122
+ *
123
+ * @param options Options object
124
+ * @returns
125
+ */
100
126
  openapi: ({ info, servers, }: {
101
127
  info: OpenAPI.InfoObject;
102
128
  servers?: Partial<Record<(`https://` | `http://`) | ({} & string), string>>;
103
129
  }) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, never, Response, "/openapi.json", RequiredParams, "GET", {}, never>, Input>;
104
130
  private readonly method;
105
- readonly get: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "GET", Query, Body>, "body" | "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "GET", Query, Body>, Input>;
106
- readonly post: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "POST", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "POST", Query, Body>, Input>;
107
- readonly put: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PUT", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PUT", Query, Body>, Input>;
108
- readonly patch: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PATCH", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PATCH", Query, Body>, Input>;
109
- readonly delete: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "DELETE", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "DELETE", Query, Body>, Input>;
110
- readonly head: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "HEAD", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "HEAD", Query, Body>, Input>;
111
- readonly options: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "OPTIONS", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "OPTIONS", Query, Body>, Input>;
131
+ readonly get: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue$1 = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "GET", Query, Body>, "body" | "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "GET", Query, Body>, Input>;
132
+ readonly post: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue$1 = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "POST", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "POST", Query, Body>, Input>;
133
+ readonly put: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue$1 = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PUT", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PUT", Query, Body>, Input>;
134
+ readonly patch: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue$1 = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PATCH", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PATCH", Query, Body>, Input>;
135
+ readonly delete: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue$1 = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "DELETE", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "DELETE", Query, Body>, Input>;
136
+ readonly head: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue$1 = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "HEAD", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "HEAD", Query, Body>, Input>;
137
+ readonly options: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue$1 = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "OPTIONS", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "OPTIONS", Query, Body>, Input>;
112
138
  through: <NextContext>(through: (context: ContextTo, params: Record<RequiredParams, string>) => MaybePromise<NextContext>) => Router<ContextFrom, NextContext, RequiredParams, Routes, Input>;
113
139
  }
114
140
 
@@ -122,22 +148,22 @@ type AnyQuery = {
122
148
  [key in string]: any;
123
149
  };
124
150
  type Through<From, To, RequiredParams extends string> = (context: From, params: Record<RequiredParams, string>) => Promise<To>;
125
- type SSEOutputSpec<Result extends JSONValue> = {
151
+ type SSEOutputSpec<Result extends JSONValue$1> = {
126
152
  type: 'sse';
127
153
  schema: AnySchemaFor<Result>;
128
154
  description?: string | undefined;
129
155
  };
130
- type JSONOutputSpec<ResultInput, ResultOutput extends JSONValue> = {
156
+ type JSONOutputSpec<ResultInput, ResultOutput extends JSONValue$1> = {
131
157
  type: 'json';
132
158
  schema: BaseSchema<ResultOutput, ResultInput, BaseSchemaDef<ResultOutput>>;
133
159
  description?: string | undefined;
134
160
  };
135
- type OutputSpec<ResultInput, ResultOutput> = ResultInput extends KaitoSSEResponse<infer R> ? SSEOutputSpec<Extract<R, JSONValue>> & {
161
+ type OutputSpec<ResultInput, ResultOutput> = ResultInput extends KaitoSSEResponse<infer R> ? SSEOutputSpec<Extract<R, JSONValue$1>> & {
136
162
  description?: string;
137
- } : JSONOutputSpec<ResultOutput, Extract<ResultInput, JSONValue>> & {
163
+ } : JSONOutputSpec<ResultOutput, Extract<ResultInput, JSONValue$1>> & {
138
164
  description?: string;
139
165
  };
140
- type Route<ContextFrom, ContextTo, RouterInput extends readonly unknown[], ResultInput, ResultOutput, Path extends string, AdditionalParams extends string, Method extends KaitoMethod, Query extends Record<string, JSONValue>, Body extends JSONValue> = {
166
+ type Route<ContextFrom, ContextTo, RouterInput extends readonly unknown[], ResultInput, ResultOutput, Path extends string, AdditionalParams extends string, Method extends KaitoMethod, Query extends Record<string, JSONValue$1>, Body extends JSONValue$1> = {
141
167
  body?: AnySchemaFor<Body>;
142
168
  query?: {
143
169
  [Key in keyof Query]: AnySchemaFor<Query[Key]>;
@@ -154,16 +180,6 @@ type AnyRoute = Route<any, any, any, any, any, any, any, any, any, any>;
154
180
  * A helper to check if the environment is Node.js-like and the `NODE_ENV` environment variable is set to `'development'`
155
181
  */
156
182
  declare const isNodeLikeDev: boolean;
157
- type ErroredAPIResponse = {
158
- success: false;
159
- data: null;
160
- message: string;
161
- };
162
- type SuccessfulAPIResponse<T> = {
163
- success: true;
164
- data: T;
165
- };
166
- type APIResponse<T> = ErroredAPIResponse | SuccessfulAPIResponse<T>;
167
183
  type MaybePromise<T> = T | Promise<T>;
168
184
  type KaitoMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
169
185
  type ExtractRouteParams<T extends string> = string extends T ? string : T extends `${string}:${infer Param}/${infer Rest}` ? Param | ExtractRouteParams<Rest> : T extends `${string}:${infer Param}` ? Param : never;
@@ -260,4 +276,4 @@ interface KaitoConfig<ContextFrom, Input extends readonly unknown[]> {
260
276
  */
261
277
  declare const create: <Context = null, Input extends readonly unknown[] = []>(config?: KaitoConfig<Context, Input>) => Router<Context, Context, never, never, Input>;
262
278
 
263
- export { type APIResponse, type AnyQuery, type AnyRoute, AnySchemaFor, BaseSchema, BaseSchemaDef, type ErroredAPIResponse, type ExtractRouteParams, type GetContext, type InferRoutes, type JSONOutputSpec, JSONValue, type KaitoConfig, KaitoError, KaitoHead, type KaitoMethod, KaitoRequest, type MaybePromise, type OutputSpec, type Route, type RouteRunData, Router, type RouterState, type SSEOutputSpec, type SuccessfulAPIResponse, type Through, WrappedError, create, isNodeLikeDev };
279
+ export { type AnyQuery, type AnyRoute, AnySchemaFor, BaseSchema, BaseSchemaDef, type ExtractRouteParams, type GetContext, type InferRoutes, type JSONOutputSpec, JSONValue$1 as JSONValue, type KaitoConfig, KaitoError, KaitoHead, type KaitoMethod, KaitoRequest, type MaybePromise, type OutputSpec, type Route, type RouteRunData, Router, type RouterState, type SSEOutputSpec, type Through, WrappedError, create, isNodeLikeDev };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as OpenAPI from 'openapi3-ts/oas31';
2
- import { JSONValue, AnySchemaFor, BaseSchema, BaseSchemaDef } from './schema/schema.js';
2
+ import { JSONValue as JSONValue$1, AnySchemaFor, BaseSchema, BaseSchemaDef } from './schema/schema.js';
3
3
  export { ArrayChecks, ArrayDef, BooleanDef, Issue, JSONPrimitive, KArray, KBoolean, KLiteral, KNull, KNumber, KObject, KObjectFromURLSearchParams, KRef, KScalar, KString, KUnion, LiteralDef, NullDef, NumberChecks, NumberDef, NumberFormat, ObjectDef, ParseContext, ParseResult, RefDef, STRING_FORMAT_REGEXES, ScalarDef, ScalarOptions, SchemaError, StringChecks, StringDef, StringFormat, UnionDef, isPrimitiveJSONValue, k } from './schema/schema.js';
4
4
  import { KaitoSSEResponse } from './stream/stream.js';
5
5
 
@@ -29,6 +29,11 @@ declare class KaitoRequest {
29
29
  get request(): Request;
30
30
  }
31
31
 
32
+ type JSONPrimitive = string | number | boolean | null;
33
+ type JSONValue = JSONPrimitive | JSONValue[] | {
34
+ [key: string]: JSONValue;
35
+ };
36
+
32
37
  /**
33
38
  * This class is merely a wrapper around a `Headers` object and a status code.
34
39
  * It's used while the router is executing a route to store any mutations to the status
@@ -67,7 +72,7 @@ declare class KaitoHead {
67
72
  * @param body The Kaito JSON format to be sent as the response body
68
73
  * @returns A Response instance, ready to be sent
69
74
  */
70
- toResponse<T>(body: APIResponse<T>): Response;
75
+ toResponse<T extends JSONValue>(data: T): Response;
71
76
  /**
72
77
  * Whether this KaitoHead instance has been touched/modified
73
78
  */
@@ -97,18 +102,39 @@ declare class Router<ContextFrom, ContextTo, RequiredParams extends string, Rout
97
102
  params: Record<string, string>;
98
103
  };
99
104
  serve: () => (request: Request, ...args: Input) => Promise<Response>;
105
+ /**
106
+ * Create a `/openapi.json` route on this router.
107
+ *
108
+ * Any routes defined AFTER this method call will NOT be included in the
109
+ * file. This is because all methods in Kaito are immutable, so there's no
110
+ * way for the router to know about routes that were created in the future
111
+ * on another router.
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * router.get("/", () => "hey").openapi({
116
+ * info: {
117
+ * title: "My API",
118
+ * version: "1.0.0",
119
+ * },
120
+ * });
121
+ * ```
122
+ *
123
+ * @param options Options object
124
+ * @returns
125
+ */
100
126
  openapi: ({ info, servers, }: {
101
127
  info: OpenAPI.InfoObject;
102
128
  servers?: Partial<Record<(`https://` | `http://`) | ({} & string), string>>;
103
129
  }) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, never, Response, "/openapi.json", RequiredParams, "GET", {}, never>, Input>;
104
130
  private readonly method;
105
- readonly get: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "GET", Query, Body>, "body" | "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "GET", Query, Body>, Input>;
106
- readonly post: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "POST", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "POST", Query, Body>, Input>;
107
- readonly put: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PUT", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PUT", Query, Body>, Input>;
108
- readonly patch: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PATCH", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PATCH", Query, Body>, Input>;
109
- readonly delete: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "DELETE", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "DELETE", Query, Body>, Input>;
110
- readonly head: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "HEAD", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "HEAD", Query, Body>, Input>;
111
- readonly options: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "OPTIONS", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "OPTIONS", Query, Body>, Input>;
131
+ readonly get: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue$1 = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "GET", Query, Body>, "body" | "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "GET", Query, Body>, Input>;
132
+ readonly post: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue$1 = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "POST", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "POST", Query, Body>, Input>;
133
+ readonly put: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue$1 = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PUT", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PUT", Query, Body>, Input>;
134
+ readonly patch: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue$1 = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PATCH", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "PATCH", Query, Body>, Input>;
135
+ readonly delete: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue$1 = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "DELETE", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "DELETE", Query, Body>, Input>;
136
+ readonly head: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue$1 = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "HEAD", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "HEAD", Query, Body>, Input>;
137
+ readonly options: <Path extends string, ResultInput = never, ResultOutput = ResultInput, Query extends AnyQuery = {}, Body extends JSONValue$1 = never>(path: Path, route: ((data: RouteRunData<RequiredParams | ExtractRouteParams<Path>, ContextTo, Query, Body>) => ResultOutput | Promise<ResultOutput>) | Omit<Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "OPTIONS", Query, Body>, "path" | "method" | "router">) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultInput, ResultOutput, Path, RequiredParams, "OPTIONS", Query, Body>, Input>;
112
138
  through: <NextContext>(through: (context: ContextTo, params: Record<RequiredParams, string>) => MaybePromise<NextContext>) => Router<ContextFrom, NextContext, RequiredParams, Routes, Input>;
113
139
  }
114
140
 
@@ -122,22 +148,22 @@ type AnyQuery = {
122
148
  [key in string]: any;
123
149
  };
124
150
  type Through<From, To, RequiredParams extends string> = (context: From, params: Record<RequiredParams, string>) => Promise<To>;
125
- type SSEOutputSpec<Result extends JSONValue> = {
151
+ type SSEOutputSpec<Result extends JSONValue$1> = {
126
152
  type: 'sse';
127
153
  schema: AnySchemaFor<Result>;
128
154
  description?: string | undefined;
129
155
  };
130
- type JSONOutputSpec<ResultInput, ResultOutput extends JSONValue> = {
156
+ type JSONOutputSpec<ResultInput, ResultOutput extends JSONValue$1> = {
131
157
  type: 'json';
132
158
  schema: BaseSchema<ResultOutput, ResultInput, BaseSchemaDef<ResultOutput>>;
133
159
  description?: string | undefined;
134
160
  };
135
- type OutputSpec<ResultInput, ResultOutput> = ResultInput extends KaitoSSEResponse<infer R> ? SSEOutputSpec<Extract<R, JSONValue>> & {
161
+ type OutputSpec<ResultInput, ResultOutput> = ResultInput extends KaitoSSEResponse<infer R> ? SSEOutputSpec<Extract<R, JSONValue$1>> & {
136
162
  description?: string;
137
- } : JSONOutputSpec<ResultOutput, Extract<ResultInput, JSONValue>> & {
163
+ } : JSONOutputSpec<ResultOutput, Extract<ResultInput, JSONValue$1>> & {
138
164
  description?: string;
139
165
  };
140
- type Route<ContextFrom, ContextTo, RouterInput extends readonly unknown[], ResultInput, ResultOutput, Path extends string, AdditionalParams extends string, Method extends KaitoMethod, Query extends Record<string, JSONValue>, Body extends JSONValue> = {
166
+ type Route<ContextFrom, ContextTo, RouterInput extends readonly unknown[], ResultInput, ResultOutput, Path extends string, AdditionalParams extends string, Method extends KaitoMethod, Query extends Record<string, JSONValue$1>, Body extends JSONValue$1> = {
141
167
  body?: AnySchemaFor<Body>;
142
168
  query?: {
143
169
  [Key in keyof Query]: AnySchemaFor<Query[Key]>;
@@ -154,16 +180,6 @@ type AnyRoute = Route<any, any, any, any, any, any, any, any, any, any>;
154
180
  * A helper to check if the environment is Node.js-like and the `NODE_ENV` environment variable is set to `'development'`
155
181
  */
156
182
  declare const isNodeLikeDev: boolean;
157
- type ErroredAPIResponse = {
158
- success: false;
159
- data: null;
160
- message: string;
161
- };
162
- type SuccessfulAPIResponse<T> = {
163
- success: true;
164
- data: T;
165
- };
166
- type APIResponse<T> = ErroredAPIResponse | SuccessfulAPIResponse<T>;
167
183
  type MaybePromise<T> = T | Promise<T>;
168
184
  type KaitoMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
169
185
  type ExtractRouteParams<T extends string> = string extends T ? string : T extends `${string}:${infer Param}/${infer Rest}` ? Param | ExtractRouteParams<Rest> : T extends `${string}:${infer Param}` ? Param : never;
@@ -260,4 +276,4 @@ interface KaitoConfig<ContextFrom, Input extends readonly unknown[]> {
260
276
  */
261
277
  declare const create: <Context = null, Input extends readonly unknown[] = []>(config?: KaitoConfig<Context, Input>) => Router<Context, Context, never, never, Input>;
262
278
 
263
- export { type APIResponse, type AnyQuery, type AnyRoute, AnySchemaFor, BaseSchema, BaseSchemaDef, type ErroredAPIResponse, type ExtractRouteParams, type GetContext, type InferRoutes, type JSONOutputSpec, JSONValue, type KaitoConfig, KaitoError, KaitoHead, type KaitoMethod, KaitoRequest, type MaybePromise, type OutputSpec, type Route, type RouteRunData, Router, type RouterState, type SSEOutputSpec, type SuccessfulAPIResponse, type Through, WrappedError, create, isNodeLikeDev };
279
+ export { type AnyQuery, type AnyRoute, AnySchemaFor, BaseSchema, BaseSchemaDef, type ExtractRouteParams, type GetContext, type InferRoutes, type JSONOutputSpec, JSONValue$1 as JSONValue, type KaitoConfig, KaitoError, KaitoHead, type KaitoMethod, KaitoRequest, type MaybePromise, type OutputSpec, type Route, type RouteRunData, Router, type RouterState, type SSEOutputSpec, type Through, WrappedError, create, isNodeLikeDev };
package/dist/index.js CHANGED
@@ -72,14 +72,14 @@ var KaitoHead = class {
72
72
  * @param body The Kaito JSON format to be sent as the response body
73
73
  * @returns A Response instance, ready to be sent
74
74
  */
75
- toResponse(body) {
75
+ toResponse(data) {
76
76
  const init = {
77
77
  status: this.#status
78
78
  };
79
79
  if (this.#headers) {
80
80
  init.headers = this.#headers;
81
81
  }
82
- return Response.json(body, init);
82
+ return Response.json(data, init);
83
83
  }
84
84
  /**
85
85
  * Whether this KaitoHead instance has been touched/modified
@@ -214,12 +214,7 @@ var Router = class _Router {
214
214
  const method = req.method;
215
215
  const { route, params: rawParams } = findRoute(method, url.pathname);
216
216
  if (!route) {
217
- const body = {
218
- success: false,
219
- data: null,
220
- message: `Cannot ${method} ${url.pathname}`
221
- };
222
- return Response.json(body, { status: 404 });
217
+ return Response.json({ message: `Cannot ${method} ${url.pathname}` }, { status: 404 });
223
218
  }
224
219
  const request = new KaitoRequest(url, req);
225
220
  const head = new KaitoHead();
@@ -257,44 +252,30 @@ var Router = class _Router {
257
252
  );
258
253
  }
259
254
  const parsed = route.openapi.schema.serialize(result);
260
- return head.toResponse({
261
- success: true,
262
- data: parsed
263
- });
255
+ return head.toResponse(parsed);
264
256
  }
265
- return head.toResponse({
266
- success: true,
267
- data: result
268
- });
257
+ return head.toResponse(result);
269
258
  } catch (e) {
270
259
  const error = WrappedError.maybe(e);
271
260
  if (error instanceof KaitoError) {
272
261
  return head.status(error.status).toResponse({
273
- success: false,
274
- data: null,
275
262
  message: error.message
276
263
  });
277
264
  }
278
265
  if (!this.#state.config.onError) {
279
266
  return head.status(500).toResponse({
280
- success: false,
281
- data: null,
282
267
  message: "Internal Server Error"
283
268
  });
284
269
  }
285
270
  try {
286
271
  const { status, message } = await this.#state.config.onError(error, request);
287
272
  return head.status(status).toResponse({
288
- success: false,
289
- data: null,
290
273
  message
291
274
  });
292
275
  } catch (e2) {
293
276
  console.error("[Kaito] Failed to handle error inside `.onError()`, returning 500 and Internal Server Error");
294
277
  console.error(e2);
295
278
  return head.status(500).toResponse({
296
- success: false,
297
- data: null,
298
279
  message: "Internal Server Error"
299
280
  });
300
281
  }
@@ -323,6 +304,27 @@ var Router = class _Router {
323
304
  return response;
324
305
  };
325
306
  };
307
+ /**
308
+ * Create a `/openapi.json` route on this router.
309
+ *
310
+ * Any routes defined AFTER this method call will NOT be included in the
311
+ * file. This is because all methods in Kaito are immutable, so there's no
312
+ * way for the router to know about routes that were created in the future
313
+ * on another router.
314
+ *
315
+ * @example
316
+ * ```ts
317
+ * router.get("/", () => "hey").openapi({
318
+ * info: {
319
+ * title: "My API",
320
+ * version: "1.0.0",
321
+ * },
322
+ * });
323
+ * ```
324
+ *
325
+ * @param options Options object
326
+ * @returns
327
+ */
326
328
  openapi = ({
327
329
  info,
328
330
  servers
@@ -385,10 +387,7 @@ var Router = class _Router {
385
387
  description: route.openapi?.description ?? "Successful response",
386
388
  content: {
387
389
  [contentType]: {
388
- schema: k.object({
389
- success: k.literal(true),
390
- data: route.openapi.schema
391
- }).toOpenAPI()
390
+ schema: route.openapi.schema.toOpenAPI()
392
391
  }
393
392
  }
394
393
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kaito-http/core",
3
3
  "type": "module",
4
- "version": "4.0.0-beta.24",
4
+ "version": "4.0.0-beta.25",
5
5
  "author": "Alistair Smith <hi@alistair.sh>",
6
6
  "repository": "https://github.com/kaito-http/kaito",
7
7
  "dependencies": {