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

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.
@@ -830,6 +830,88 @@ var KLiteral = class _KLiteral extends BaseSchema {
830
830
  visit() {
831
831
  }
832
832
  };
833
+ var KRecord = class _KRecord extends BaseSchema {
834
+ static create = (keys, values) => new _KRecord({ keys, values });
835
+ serialize(value) {
836
+ const result = {};
837
+ for (const key in value) {
838
+ if (!Object.prototype.hasOwnProperty.call(value, key)) continue;
839
+ const keySerialize = this.def.keys.serialize(key);
840
+ const valueSerialize = this.def.values.serialize(value[key]);
841
+ result[keySerialize] = valueSerialize;
842
+ }
843
+ return result;
844
+ }
845
+ toOpenAPI() {
846
+ const baseSchema = this.getSchemaObject();
847
+ return {
848
+ ...baseSchema,
849
+ type: "object",
850
+ propertyNames: this.def.keys.toOpenAPI(),
851
+ additionalProperties: this.def.values.toOpenAPI()
852
+ };
853
+ }
854
+ parseSafe(json) {
855
+ return ParseContext.result((ctx) => {
856
+ if (typeof json !== "object" || json === null || Array.isArray(json)) {
857
+ return ctx.addIssue("Expected object", []);
858
+ }
859
+ const result = {};
860
+ for (const key in json) {
861
+ if (!Object.prototype.hasOwnProperty.call(json, key)) continue;
862
+ const keyParse = this.def.keys.parseSafe(key);
863
+ if (!keyParse.success) {
864
+ return ctx.addIssues(keyParse.issues, [key]);
865
+ }
866
+ const value = json[keyParse.result];
867
+ const valueParse = this.def.values.parseSafe(value);
868
+ if (!valueParse.success) {
869
+ return ctx.addIssues(valueParse.issues, [key]);
870
+ }
871
+ result[keyParse.result] = valueParse.result;
872
+ }
873
+ return result;
874
+ });
875
+ }
876
+ parse(json) {
877
+ const result = this.parseSafe(json);
878
+ if (!result.success) {
879
+ throw new SchemaError(result.issues);
880
+ }
881
+ return result.result;
882
+ }
883
+ visit(visitor) {
884
+ visitor(this.def.keys);
885
+ visitor(this.def.values);
886
+ }
887
+ };
888
+ var KLazy = class _KLazy extends BaseSchema {
889
+ schema;
890
+ static create = (getter) => new _KLazy({ getter });
891
+ getSchema() {
892
+ if (!this.schema) {
893
+ this.schema = this.def.getter();
894
+ }
895
+ return this.schema;
896
+ }
897
+ serialize(value) {
898
+ return this.getSchema().serialize(value);
899
+ }
900
+ toOpenAPI() {
901
+ return this.getSchema().toOpenAPI();
902
+ }
903
+ parseSafe(json) {
904
+ return this.getSchema().parseSafe(json);
905
+ }
906
+ parse(json) {
907
+ return this.getSchema().parse(json);
908
+ }
909
+ visit(visitor) {
910
+ const schema = this.getSchema();
911
+ visitor(schema);
912
+ schema.visit(visitor);
913
+ }
914
+ };
833
915
  var k = {
834
916
  string: KString.create,
835
917
  number: KNumber.create,
@@ -837,10 +919,21 @@ var k = {
837
919
  array: KArray.create,
838
920
  null: KNull.create,
839
921
  ref: KRef.create,
922
+ record: KRecord.create,
840
923
  object: KObject.create,
841
924
  scalar: KScalar.create,
842
925
  literal: KLiteral.create,
843
926
  union: KUnion.create,
927
+ lazy: KLazy.create,
928
+ /**
929
+ * Schema for any valid JSON value
930
+ */
931
+ json: () => {
932
+ const jsonSchema = k.lazy(
933
+ () => k.union([k.string(), k.number(), k.boolean(), k.null(), k.array(jsonSchema), k.record(k.string(), jsonSchema)])
934
+ );
935
+ return jsonSchema;
936
+ },
844
937
  /**
845
938
  * @internal
846
939
  * @experimental
@@ -865,5 +958,7 @@ export {
865
958
  KScalar,
866
959
  KUnion,
867
960
  KLiteral,
961
+ KRecord,
962
+ KLazy,
868
963
  k
869
964
  };
package/dist/index.cjs CHANGED
@@ -23,11 +23,13 @@ __export(index_exports, {
23
23
  BaseSchema: () => BaseSchema,
24
24
  KArray: () => KArray,
25
25
  KBoolean: () => KBoolean,
26
+ KLazy: () => KLazy,
26
27
  KLiteral: () => KLiteral,
27
28
  KNull: () => KNull,
28
29
  KNumber: () => KNumber,
29
30
  KObject: () => KObject,
30
31
  KObjectFromURLSearchParams: () => KObjectFromURLSearchParams,
32
+ KRecord: () => KRecord,
31
33
  KRef: () => KRef,
32
34
  KScalar: () => KScalar,
33
35
  KString: () => KString,
@@ -101,14 +103,14 @@ var KaitoHead = class {
101
103
  * @param body The Kaito JSON format to be sent as the response body
102
104
  * @returns A Response instance, ready to be sent
103
105
  */
104
- toResponse(body) {
106
+ toResponse(data) {
105
107
  const init = {
106
108
  status: this.#status
107
109
  };
108
110
  if (this.#headers) {
109
111
  init.headers = this.#headers;
110
112
  }
111
- return Response.json(body, init);
113
+ return Response.json(data, init);
112
114
  }
113
115
  /**
114
116
  * Whether this KaitoHead instance has been touched/modified
@@ -988,6 +990,88 @@ var KLiteral = class _KLiteral extends BaseSchema {
988
990
  visit() {
989
991
  }
990
992
  };
993
+ var KRecord = class _KRecord extends BaseSchema {
994
+ static create = (keys, values) => new _KRecord({ keys, values });
995
+ serialize(value) {
996
+ const result = {};
997
+ for (const key in value) {
998
+ if (!Object.prototype.hasOwnProperty.call(value, key)) continue;
999
+ const keySerialize = this.def.keys.serialize(key);
1000
+ const valueSerialize = this.def.values.serialize(value[key]);
1001
+ result[keySerialize] = valueSerialize;
1002
+ }
1003
+ return result;
1004
+ }
1005
+ toOpenAPI() {
1006
+ const baseSchema = this.getSchemaObject();
1007
+ return {
1008
+ ...baseSchema,
1009
+ type: "object",
1010
+ propertyNames: this.def.keys.toOpenAPI(),
1011
+ additionalProperties: this.def.values.toOpenAPI()
1012
+ };
1013
+ }
1014
+ parseSafe(json) {
1015
+ return ParseContext.result((ctx) => {
1016
+ if (typeof json !== "object" || json === null || Array.isArray(json)) {
1017
+ return ctx.addIssue("Expected object", []);
1018
+ }
1019
+ const result = {};
1020
+ for (const key in json) {
1021
+ if (!Object.prototype.hasOwnProperty.call(json, key)) continue;
1022
+ const keyParse = this.def.keys.parseSafe(key);
1023
+ if (!keyParse.success) {
1024
+ return ctx.addIssues(keyParse.issues, [key]);
1025
+ }
1026
+ const value = json[keyParse.result];
1027
+ const valueParse = this.def.values.parseSafe(value);
1028
+ if (!valueParse.success) {
1029
+ return ctx.addIssues(valueParse.issues, [key]);
1030
+ }
1031
+ result[keyParse.result] = valueParse.result;
1032
+ }
1033
+ return result;
1034
+ });
1035
+ }
1036
+ parse(json) {
1037
+ const result = this.parseSafe(json);
1038
+ if (!result.success) {
1039
+ throw new SchemaError(result.issues);
1040
+ }
1041
+ return result.result;
1042
+ }
1043
+ visit(visitor) {
1044
+ visitor(this.def.keys);
1045
+ visitor(this.def.values);
1046
+ }
1047
+ };
1048
+ var KLazy = class _KLazy extends BaseSchema {
1049
+ schema;
1050
+ static create = (getter) => new _KLazy({ getter });
1051
+ getSchema() {
1052
+ if (!this.schema) {
1053
+ this.schema = this.def.getter();
1054
+ }
1055
+ return this.schema;
1056
+ }
1057
+ serialize(value) {
1058
+ return this.getSchema().serialize(value);
1059
+ }
1060
+ toOpenAPI() {
1061
+ return this.getSchema().toOpenAPI();
1062
+ }
1063
+ parseSafe(json) {
1064
+ return this.getSchema().parseSafe(json);
1065
+ }
1066
+ parse(json) {
1067
+ return this.getSchema().parse(json);
1068
+ }
1069
+ visit(visitor) {
1070
+ const schema = this.getSchema();
1071
+ visitor(schema);
1072
+ schema.visit(visitor);
1073
+ }
1074
+ };
991
1075
  var k = {
992
1076
  string: KString.create,
993
1077
  number: KNumber.create,
@@ -995,10 +1079,21 @@ var k = {
995
1079
  array: KArray.create,
996
1080
  null: KNull.create,
997
1081
  ref: KRef.create,
1082
+ record: KRecord.create,
998
1083
  object: KObject.create,
999
1084
  scalar: KScalar.create,
1000
1085
  literal: KLiteral.create,
1001
1086
  union: KUnion.create,
1087
+ lazy: KLazy.create,
1088
+ /**
1089
+ * Schema for any valid JSON value
1090
+ */
1091
+ json: () => {
1092
+ const jsonSchema = k.lazy(
1093
+ () => k.union([k.string(), k.number(), k.boolean(), k.null(), k.array(jsonSchema), k.record(k.string(), jsonSchema)])
1094
+ );
1095
+ return jsonSchema;
1096
+ },
1002
1097
  /**
1003
1098
  * @internal
1004
1099
  * @experimental
@@ -1093,12 +1188,7 @@ var Router = class _Router {
1093
1188
  const method = req.method;
1094
1189
  const { route, params: rawParams } = findRoute(method, url.pathname);
1095
1190
  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 });
1191
+ return Response.json({ message: `Cannot ${method} ${url.pathname}` }, { status: 404 });
1102
1192
  }
1103
1193
  const request = new KaitoRequest(url, req);
1104
1194
  const head = new KaitoHead();
@@ -1136,44 +1226,30 @@ var Router = class _Router {
1136
1226
  );
1137
1227
  }
1138
1228
  const parsed = route.openapi.schema.serialize(result);
1139
- return head.toResponse({
1140
- success: true,
1141
- data: parsed
1142
- });
1229
+ return head.toResponse(parsed);
1143
1230
  }
1144
- return head.toResponse({
1145
- success: true,
1146
- data: result
1147
- });
1231
+ return head.toResponse(result);
1148
1232
  } catch (e) {
1149
1233
  const error = WrappedError.maybe(e);
1150
1234
  if (error instanceof KaitoError) {
1151
1235
  return head.status(error.status).toResponse({
1152
- success: false,
1153
- data: null,
1154
1236
  message: error.message
1155
1237
  });
1156
1238
  }
1157
1239
  if (!this.#state.config.onError) {
1158
1240
  return head.status(500).toResponse({
1159
- success: false,
1160
- data: null,
1161
1241
  message: "Internal Server Error"
1162
1242
  });
1163
1243
  }
1164
1244
  try {
1165
1245
  const { status, message } = await this.#state.config.onError(error, request);
1166
1246
  return head.status(status).toResponse({
1167
- success: false,
1168
- data: null,
1169
1247
  message
1170
1248
  });
1171
1249
  } catch (e2) {
1172
1250
  console.error("[Kaito] Failed to handle error inside `.onError()`, returning 500 and Internal Server Error");
1173
1251
  console.error(e2);
1174
1252
  return head.status(500).toResponse({
1175
- success: false,
1176
- data: null,
1177
1253
  message: "Internal Server Error"
1178
1254
  });
1179
1255
  }
@@ -1202,6 +1278,27 @@ var Router = class _Router {
1202
1278
  return response;
1203
1279
  };
1204
1280
  };
1281
+ /**
1282
+ * Create a `/openapi.json` route on this router.
1283
+ *
1284
+ * Any routes defined AFTER this method call will NOT be included in the
1285
+ * file. This is because all methods in Kaito are immutable, so there's no
1286
+ * way for the router to know about routes that were created in the future
1287
+ * on another router.
1288
+ *
1289
+ * @example
1290
+ * ```ts
1291
+ * router.get("/", () => "hey").openapi({
1292
+ * info: {
1293
+ * title: "My API",
1294
+ * version: "1.0.0",
1295
+ * },
1296
+ * });
1297
+ * ```
1298
+ *
1299
+ * @param options Options object
1300
+ * @returns
1301
+ */
1205
1302
  openapi = ({
1206
1303
  info,
1207
1304
  servers
@@ -1264,10 +1361,7 @@ var Router = class _Router {
1264
1361
  description: route.openapi?.description ?? "Successful response",
1265
1362
  content: {
1266
1363
  [contentType]: {
1267
- schema: k.object({
1268
- success: k.literal(true),
1269
- data: route.openapi.schema
1270
- }).toOpenAPI()
1364
+ schema: route.openapi.schema.toOpenAPI()
1271
1365
  }
1272
1366
  }
1273
1367
  }
@@ -1328,11 +1422,13 @@ var create = Router.create;
1328
1422
  BaseSchema,
1329
1423
  KArray,
1330
1424
  KBoolean,
1425
+ KLazy,
1331
1426
  KLiteral,
1332
1427
  KNull,
1333
1428
  KNumber,
1334
1429
  KObject,
1335
1430
  KObjectFromURLSearchParams,
1431
+ KRecord,
1336
1432
  KRef,
1337
1433
  KScalar,
1338
1434
  KString,
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as OpenAPI from 'openapi3-ts/oas31';
2
- import { JSONValue, AnySchemaFor, BaseSchema, BaseSchemaDef } from './schema/schema.cjs';
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';
2
+ import { JSONValue as JSONValue$1, AnySchemaFor, BaseSchema, BaseSchemaDef } from './schema/schema.cjs';
3
+ export { ArrayChecks, ArrayDef, BooleanDef, Issue, JSONPrimitive, KArray, KBoolean, KLazy, KLiteral, KNull, KNumber, KObject, KObjectFromURLSearchParams, KRecord, KRef, KScalar, KString, KUnion, LazyDef, LiteralDef, NullDef, NumberChecks, NumberDef, NumberFormat, ObjectDef, ParseContext, ParseResult, RecordDef, 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
 
6
6
  declare class WrappedError<T> extends Error {
@@ -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,18 @@ 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>> & {
136
- description?: string;
137
- } : JSONOutputSpec<ResultOutput, Extract<ResultInput, JSONValue>> & {
138
- description?: string;
139
- };
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> = {
161
+ type OutputSpec<ResultInput, ResultOutput> = ResultInput extends KaitoSSEResponse<infer R> ? SSEOutputSpec<Extract<R, JSONValue$1>> : JSONOutputSpec<ResultOutput, Extract<ResultInput, JSONValue$1>>;
162
+ 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
163
  body?: AnySchemaFor<Body>;
142
164
  query?: {
143
165
  [Key in keyof Query]: AnySchemaFor<Query[Key]>;
@@ -154,16 +176,6 @@ type AnyRoute = Route<any, any, any, any, any, any, any, any, any, any>;
154
176
  * A helper to check if the environment is Node.js-like and the `NODE_ENV` environment variable is set to `'development'`
155
177
  */
156
178
  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
179
  type MaybePromise<T> = T | Promise<T>;
168
180
  type KaitoMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
169
181
  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 +272,4 @@ interface KaitoConfig<ContextFrom, Input extends readonly unknown[]> {
260
272
  */
261
273
  declare const create: <Context = null, Input extends readonly unknown[] = []>(config?: KaitoConfig<Context, Input>) => Router<Context, Context, never, never, Input>;
262
274
 
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 };
275
+ 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,6 +1,6 @@
1
1
  import * as OpenAPI from 'openapi3-ts/oas31';
2
- import { JSONValue, AnySchemaFor, BaseSchema, BaseSchemaDef } from './schema/schema.js';
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';
2
+ import { JSONValue as JSONValue$1, AnySchemaFor, BaseSchema, BaseSchemaDef } from './schema/schema.js';
3
+ export { ArrayChecks, ArrayDef, BooleanDef, Issue, JSONPrimitive, KArray, KBoolean, KLazy, KLiteral, KNull, KNumber, KObject, KObjectFromURLSearchParams, KRecord, KRef, KScalar, KString, KUnion, LazyDef, LiteralDef, NullDef, NumberChecks, NumberDef, NumberFormat, ObjectDef, ParseContext, ParseResult, RecordDef, 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
 
6
6
  declare class WrappedError<T> extends Error {
@@ -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,18 @@ 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>> & {
136
- description?: string;
137
- } : JSONOutputSpec<ResultOutput, Extract<ResultInput, JSONValue>> & {
138
- description?: string;
139
- };
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> = {
161
+ type OutputSpec<ResultInput, ResultOutput> = ResultInput extends KaitoSSEResponse<infer R> ? SSEOutputSpec<Extract<R, JSONValue$1>> : JSONOutputSpec<ResultOutput, Extract<ResultInput, JSONValue$1>>;
162
+ 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
163
  body?: AnySchemaFor<Body>;
142
164
  query?: {
143
165
  [Key in keyof Query]: AnySchemaFor<Query[Key]>;
@@ -154,16 +176,6 @@ type AnyRoute = Route<any, any, any, any, any, any, any, any, any, any>;
154
176
  * A helper to check if the environment is Node.js-like and the `NODE_ENV` environment variable is set to `'development'`
155
177
  */
156
178
  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
179
  type MaybePromise<T> = T | Promise<T>;
168
180
  type KaitoMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
169
181
  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 +272,4 @@ interface KaitoConfig<ContextFrom, Input extends readonly unknown[]> {
260
272
  */
261
273
  declare const create: <Context = null, Input extends readonly unknown[] = []>(config?: KaitoConfig<Context, Input>) => Router<Context, Context, never, never, Input>;
262
274
 
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 };
275
+ 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
@@ -2,11 +2,13 @@ import {
2
2
  BaseSchema,
3
3
  KArray,
4
4
  KBoolean,
5
+ KLazy,
5
6
  KLiteral,
6
7
  KNull,
7
8
  KNumber,
8
9
  KObject,
9
10
  KObjectFromURLSearchParams,
11
+ KRecord,
10
12
  KRef,
11
13
  KScalar,
12
14
  KString,
@@ -16,7 +18,7 @@ import {
16
18
  SchemaError,
17
19
  isPrimitiveJSONValue,
18
20
  k
19
- } from "./chunk-IEGYJT4R.js";
21
+ } from "./chunk-BJVNFSCY.js";
20
22
 
21
23
  // src/router/router.ts
22
24
  import "openapi3-ts/oas31";
@@ -72,14 +74,14 @@ var KaitoHead = class {
72
74
  * @param body The Kaito JSON format to be sent as the response body
73
75
  * @returns A Response instance, ready to be sent
74
76
  */
75
- toResponse(body) {
77
+ toResponse(data) {
76
78
  const init = {
77
79
  status: this.#status
78
80
  };
79
81
  if (this.#headers) {
80
82
  init.headers = this.#headers;
81
83
  }
82
- return Response.json(body, init);
84
+ return Response.json(data, init);
83
85
  }
84
86
  /**
85
87
  * Whether this KaitoHead instance has been touched/modified
@@ -214,12 +216,7 @@ var Router = class _Router {
214
216
  const method = req.method;
215
217
  const { route, params: rawParams } = findRoute(method, url.pathname);
216
218
  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 });
219
+ return Response.json({ message: `Cannot ${method} ${url.pathname}` }, { status: 404 });
223
220
  }
224
221
  const request = new KaitoRequest(url, req);
225
222
  const head = new KaitoHead();
@@ -257,44 +254,30 @@ var Router = class _Router {
257
254
  );
258
255
  }
259
256
  const parsed = route.openapi.schema.serialize(result);
260
- return head.toResponse({
261
- success: true,
262
- data: parsed
263
- });
257
+ return head.toResponse(parsed);
264
258
  }
265
- return head.toResponse({
266
- success: true,
267
- data: result
268
- });
259
+ return head.toResponse(result);
269
260
  } catch (e) {
270
261
  const error = WrappedError.maybe(e);
271
262
  if (error instanceof KaitoError) {
272
263
  return head.status(error.status).toResponse({
273
- success: false,
274
- data: null,
275
264
  message: error.message
276
265
  });
277
266
  }
278
267
  if (!this.#state.config.onError) {
279
268
  return head.status(500).toResponse({
280
- success: false,
281
- data: null,
282
269
  message: "Internal Server Error"
283
270
  });
284
271
  }
285
272
  try {
286
273
  const { status, message } = await this.#state.config.onError(error, request);
287
274
  return head.status(status).toResponse({
288
- success: false,
289
- data: null,
290
275
  message
291
276
  });
292
277
  } catch (e2) {
293
278
  console.error("[Kaito] Failed to handle error inside `.onError()`, returning 500 and Internal Server Error");
294
279
  console.error(e2);
295
280
  return head.status(500).toResponse({
296
- success: false,
297
- data: null,
298
281
  message: "Internal Server Error"
299
282
  });
300
283
  }
@@ -323,6 +306,27 @@ var Router = class _Router {
323
306
  return response;
324
307
  };
325
308
  };
309
+ /**
310
+ * Create a `/openapi.json` route on this router.
311
+ *
312
+ * Any routes defined AFTER this method call will NOT be included in the
313
+ * file. This is because all methods in Kaito are immutable, so there's no
314
+ * way for the router to know about routes that were created in the future
315
+ * on another router.
316
+ *
317
+ * @example
318
+ * ```ts
319
+ * router.get("/", () => "hey").openapi({
320
+ * info: {
321
+ * title: "My API",
322
+ * version: "1.0.0",
323
+ * },
324
+ * });
325
+ * ```
326
+ *
327
+ * @param options Options object
328
+ * @returns
329
+ */
326
330
  openapi = ({
327
331
  info,
328
332
  servers
@@ -385,10 +389,7 @@ var Router = class _Router {
385
389
  description: route.openapi?.description ?? "Successful response",
386
390
  content: {
387
391
  [contentType]: {
388
- schema: k.object({
389
- success: k.literal(true),
390
- data: route.openapi.schema
391
- }).toOpenAPI()
392
+ schema: route.openapi.schema.toOpenAPI()
392
393
  }
393
394
  }
394
395
  }
@@ -448,11 +449,13 @@ export {
448
449
  BaseSchema,
449
450
  KArray,
450
451
  KBoolean,
452
+ KLazy,
451
453
  KLiteral,
452
454
  KNull,
453
455
  KNumber,
454
456
  KObject,
455
457
  KObjectFromURLSearchParams,
458
+ KRecord,
456
459
  KRef,
457
460
  KScalar,
458
461
  KString,
@@ -23,11 +23,13 @@ __export(schema_exports, {
23
23
  BaseSchema: () => BaseSchema,
24
24
  KArray: () => KArray,
25
25
  KBoolean: () => KBoolean,
26
+ KLazy: () => KLazy,
26
27
  KLiteral: () => KLiteral,
27
28
  KNull: () => KNull,
28
29
  KNumber: () => KNumber,
29
30
  KObject: () => KObject,
30
31
  KObjectFromURLSearchParams: () => KObjectFromURLSearchParams,
32
+ KRecord: () => KRecord,
31
33
  KRef: () => KRef,
32
34
  KScalar: () => KScalar,
33
35
  KString: () => KString,
@@ -870,6 +872,88 @@ var KLiteral = class _KLiteral extends BaseSchema {
870
872
  visit() {
871
873
  }
872
874
  };
875
+ var KRecord = class _KRecord extends BaseSchema {
876
+ static create = (keys, values) => new _KRecord({ keys, values });
877
+ serialize(value) {
878
+ const result = {};
879
+ for (const key in value) {
880
+ if (!Object.prototype.hasOwnProperty.call(value, key)) continue;
881
+ const keySerialize = this.def.keys.serialize(key);
882
+ const valueSerialize = this.def.values.serialize(value[key]);
883
+ result[keySerialize] = valueSerialize;
884
+ }
885
+ return result;
886
+ }
887
+ toOpenAPI() {
888
+ const baseSchema = this.getSchemaObject();
889
+ return {
890
+ ...baseSchema,
891
+ type: "object",
892
+ propertyNames: this.def.keys.toOpenAPI(),
893
+ additionalProperties: this.def.values.toOpenAPI()
894
+ };
895
+ }
896
+ parseSafe(json) {
897
+ return ParseContext.result((ctx) => {
898
+ if (typeof json !== "object" || json === null || Array.isArray(json)) {
899
+ return ctx.addIssue("Expected object", []);
900
+ }
901
+ const result = {};
902
+ for (const key in json) {
903
+ if (!Object.prototype.hasOwnProperty.call(json, key)) continue;
904
+ const keyParse = this.def.keys.parseSafe(key);
905
+ if (!keyParse.success) {
906
+ return ctx.addIssues(keyParse.issues, [key]);
907
+ }
908
+ const value = json[keyParse.result];
909
+ const valueParse = this.def.values.parseSafe(value);
910
+ if (!valueParse.success) {
911
+ return ctx.addIssues(valueParse.issues, [key]);
912
+ }
913
+ result[keyParse.result] = valueParse.result;
914
+ }
915
+ return result;
916
+ });
917
+ }
918
+ parse(json) {
919
+ const result = this.parseSafe(json);
920
+ if (!result.success) {
921
+ throw new SchemaError(result.issues);
922
+ }
923
+ return result.result;
924
+ }
925
+ visit(visitor) {
926
+ visitor(this.def.keys);
927
+ visitor(this.def.values);
928
+ }
929
+ };
930
+ var KLazy = class _KLazy extends BaseSchema {
931
+ schema;
932
+ static create = (getter) => new _KLazy({ getter });
933
+ getSchema() {
934
+ if (!this.schema) {
935
+ this.schema = this.def.getter();
936
+ }
937
+ return this.schema;
938
+ }
939
+ serialize(value) {
940
+ return this.getSchema().serialize(value);
941
+ }
942
+ toOpenAPI() {
943
+ return this.getSchema().toOpenAPI();
944
+ }
945
+ parseSafe(json) {
946
+ return this.getSchema().parseSafe(json);
947
+ }
948
+ parse(json) {
949
+ return this.getSchema().parse(json);
950
+ }
951
+ visit(visitor) {
952
+ const schema = this.getSchema();
953
+ visitor(schema);
954
+ schema.visit(visitor);
955
+ }
956
+ };
873
957
  var k = {
874
958
  string: KString.create,
875
959
  number: KNumber.create,
@@ -877,10 +961,21 @@ var k = {
877
961
  array: KArray.create,
878
962
  null: KNull.create,
879
963
  ref: KRef.create,
964
+ record: KRecord.create,
880
965
  object: KObject.create,
881
966
  scalar: KScalar.create,
882
967
  literal: KLiteral.create,
883
968
  union: KUnion.create,
969
+ lazy: KLazy.create,
970
+ /**
971
+ * Schema for any valid JSON value
972
+ */
973
+ json: () => {
974
+ const jsonSchema = k.lazy(
975
+ () => k.union([k.string(), k.number(), k.boolean(), k.null(), k.array(jsonSchema), k.record(k.string(), jsonSchema)])
976
+ );
977
+ return jsonSchema;
978
+ },
884
979
  /**
885
980
  * @internal
886
981
  * @experimental
@@ -892,11 +987,13 @@ var k = {
892
987
  BaseSchema,
893
988
  KArray,
894
989
  KBoolean,
990
+ KLazy,
895
991
  KLiteral,
896
992
  KNull,
897
993
  KNumber,
898
994
  KObject,
899
995
  KObjectFromURLSearchParams,
996
+ KRecord,
900
997
  KRef,
901
998
  KScalar,
902
999
  KString,
@@ -53,7 +53,10 @@ declare abstract class BaseSchema<Input extends JSONValue, Output, Def extends B
53
53
  abstract serialize(value: Output): Input;
54
54
  protected readonly def: Def;
55
55
  abstract toOpenAPI(): SchemaObject | ReferenceObject;
56
- protected getSchemaObject(): SchemaObject;
56
+ protected getSchemaObject(): {
57
+ description?: string;
58
+ example?: Input;
59
+ };
57
60
  protected clone(def: Partial<Def>): this;
58
61
  protected constructor(def: Def);
59
62
  or<OtherInput extends JSONValue, OtherOutput, Def extends BaseSchemaDef<OtherInput>>(other: BaseSchema<OtherInput, OtherOutput, Def>): KUnion<(this | BaseSchema<OtherInput, OtherOutput, Def>)["_input"], (this | BaseSchema<OtherInput, OtherOutput, Def>)["_output"]>;
@@ -322,6 +325,31 @@ declare class KLiteral<Value extends string | number | boolean> extends BaseSche
322
325
  parseSafe(json: unknown): ParseResult<Value>;
323
326
  visit(): void;
324
327
  }
328
+ interface RecordDef<KeyInput extends string, KeyOutput extends string, ValueInput extends JSONValue, ValueOutput> extends BaseSchemaDef<Record<KeyInput, ValueInput>> {
329
+ keys: BaseSchema<KeyInput, KeyOutput, BaseSchemaDef<KeyInput>>;
330
+ values: BaseSchema<ValueInput, ValueOutput, BaseSchemaDef<ValueInput>>;
331
+ }
332
+ declare class KRecord<KeyInput extends string, KeyOutput extends string, ValueInput extends JSONValue, ValueOutput> extends BaseSchema<Record<KeyInput, ValueInput>, Record<KeyOutput, ValueOutput>, RecordDef<KeyInput, KeyOutput, ValueInput, ValueOutput>> {
333
+ static create: <KeyInput_1 extends string, KeyOutput_1 extends string, ValueInput_1 extends JSONValue, ValueOutput_1>(keys: BaseSchema<KeyInput_1, KeyOutput_1, BaseSchemaDef<KeyInput_1>>, values: BaseSchema<ValueInput_1, ValueOutput_1, BaseSchemaDef<ValueInput_1>>) => KRecord<KeyInput_1, KeyOutput_1, ValueInput_1, ValueOutput_1>;
334
+ serialize(value: Record<KeyOutput, ValueOutput>): Record<KeyInput, ValueInput>;
335
+ toOpenAPI(): SchemaObject;
336
+ parseSafe(json: unknown): ParseResult<Record<KeyOutput, ValueOutput>>;
337
+ parse(json: unknown): Record<KeyOutput, ValueOutput>;
338
+ visit(visitor: (schema: BaseSchema<any, any, any>) => void): void;
339
+ }
340
+ interface LazyDef<Input extends JSONValue, Output> extends BaseSchemaDef<Input> {
341
+ getter: () => BaseSchema<Input, Output, BaseSchemaDef<Input>>;
342
+ }
343
+ declare class KLazy<Input extends JSONValue, Output> extends BaseSchema<Input, Output, LazyDef<Input, Output>> {
344
+ private schema?;
345
+ static create: <Input_1 extends JSONValue, Output_1>(getter: () => BaseSchema<Input_1, Output_1, BaseSchemaDef<Input_1>>) => KLazy<Input_1, Output_1>;
346
+ private getSchema;
347
+ serialize(value: Output): Input;
348
+ toOpenAPI(): SchemaObject | ReferenceObject;
349
+ parseSafe(json: unknown): ParseResult<Output>;
350
+ parse(json: unknown): Output;
351
+ visit(visitor: (schema: BaseSchema<any, any, any>) => void): void;
352
+ }
325
353
  declare const k: {
326
354
  string: () => KString;
327
355
  number: () => KNumber;
@@ -329,10 +357,16 @@ declare const k: {
329
357
  array: <ItemsInput extends JSONValue, ItemsOutput, Def extends BaseSchemaDef<ItemsInput>>(items: BaseSchema<ItemsInput, ItemsOutput, Def>) => KArray<ItemsInput, ItemsOutput>;
330
358
  null: () => KNull;
331
359
  ref: <Input extends Record<keyof Output, JSONValue>, Output extends Record<keyof Input, any>>(name: string, shape: { [K in keyof Input | keyof Output]: BaseSchema<Input[K], Output[K], BaseSchemaDef<Input[K]>>; }) => KRef<Input, Output>;
360
+ record: <KeyInput extends string, KeyOutput extends string, ValueInput extends JSONValue, ValueOutput>(keys: BaseSchema<KeyInput, KeyOutput, BaseSchemaDef<KeyInput>>, values: BaseSchema<ValueInput, ValueOutput, BaseSchemaDef<ValueInput>>) => KRecord<KeyInput, KeyOutput, ValueInput, ValueOutput>;
332
361
  object: <Input extends Record<keyof Output, any>, Output extends Record<keyof Input, any>>(shape: { [K in keyof Input | keyof Output]: BaseSchema<Input[K], Output[K], BaseSchemaDef<Input[K]>>; }) => KObject<Input, Output>;
333
362
  scalar: <ClientRepresentation extends JSONPrimitive, ServerRepresentation>(options: ScalarOptions<ClientRepresentation, ServerRepresentation>) => KScalar<ClientRepresentation, ServerRepresentation>;
334
363
  literal: <Value extends string | number | boolean>(value: Value) => KLiteral<Value>;
335
364
  union: <Items extends [a: BaseSchema<JSONValue, unknown, BaseSchemaDef<JSONValue>>, b: BaseSchema<JSONValue, unknown, BaseSchemaDef<JSONValue>>, ...remaining: BaseSchema<JSONValue, unknown, BaseSchemaDef<JSONValue>>[]]>(items: Items) => KUnion<Items[number]["_input"], Items[number]["_output"]>;
365
+ lazy: <Input extends JSONValue, Output>(getter: () => BaseSchema<Input, Output, BaseSchemaDef<Input>>) => KLazy<Input, Output>;
366
+ /**
367
+ * Schema for any valid JSON value
368
+ */
369
+ json: () => BaseSchema<JSONValue, JSONValue, BaseSchemaDef<JSONValue>>;
336
370
  /**
337
371
  * @internal
338
372
  * @experimental
@@ -340,4 +374,4 @@ declare const k: {
340
374
  objectFromURLSearchParams: <Input extends Record<keyof Output, JSONValue>, Output extends Record<keyof Input, JSONValue>>(shape: { [K in keyof Input | keyof Output]: BaseSchema<Input[K], Output[K], BaseSchemaDef<Input[K]>>; }) => KObjectFromURLSearchParams<Input, Output>;
341
375
  };
342
376
 
343
- export { type AnySchemaFor, type ArrayChecks, type ArrayDef, BaseSchema, type BaseSchemaDef, type BooleanDef, type Issue, type JSONPrimitive, type JSONValue, KArray, KBoolean, KLiteral, KNull, KNumber, KObject, KObjectFromURLSearchParams, KRef, KScalar, KString, KUnion, type LiteralDef, type NullDef, type NumberChecks, type NumberDef, type NumberFormat, type ObjectDef, ParseContext, type ParseResult, type RefDef, STRING_FORMAT_REGEXES, type ScalarDef, type ScalarOptions, SchemaError, type StringChecks, type StringDef, type StringFormat, type UnionDef, isPrimitiveJSONValue, k };
377
+ export { type AnySchemaFor, type ArrayChecks, type ArrayDef, BaseSchema, type BaseSchemaDef, type BooleanDef, type Issue, type JSONPrimitive, type JSONValue, KArray, KBoolean, KLazy, KLiteral, KNull, KNumber, KObject, KObjectFromURLSearchParams, KRecord, KRef, KScalar, KString, KUnion, type LazyDef, type LiteralDef, type NullDef, type NumberChecks, type NumberDef, type NumberFormat, type ObjectDef, ParseContext, type ParseResult, type RecordDef, type RefDef, STRING_FORMAT_REGEXES, type ScalarDef, type ScalarOptions, SchemaError, type StringChecks, type StringDef, type StringFormat, type UnionDef, isPrimitiveJSONValue, k };
@@ -53,7 +53,10 @@ declare abstract class BaseSchema<Input extends JSONValue, Output, Def extends B
53
53
  abstract serialize(value: Output): Input;
54
54
  protected readonly def: Def;
55
55
  abstract toOpenAPI(): SchemaObject | ReferenceObject;
56
- protected getSchemaObject(): SchemaObject;
56
+ protected getSchemaObject(): {
57
+ description?: string;
58
+ example?: Input;
59
+ };
57
60
  protected clone(def: Partial<Def>): this;
58
61
  protected constructor(def: Def);
59
62
  or<OtherInput extends JSONValue, OtherOutput, Def extends BaseSchemaDef<OtherInput>>(other: BaseSchema<OtherInput, OtherOutput, Def>): KUnion<(this | BaseSchema<OtherInput, OtherOutput, Def>)["_input"], (this | BaseSchema<OtherInput, OtherOutput, Def>)["_output"]>;
@@ -322,6 +325,31 @@ declare class KLiteral<Value extends string | number | boolean> extends BaseSche
322
325
  parseSafe(json: unknown): ParseResult<Value>;
323
326
  visit(): void;
324
327
  }
328
+ interface RecordDef<KeyInput extends string, KeyOutput extends string, ValueInput extends JSONValue, ValueOutput> extends BaseSchemaDef<Record<KeyInput, ValueInput>> {
329
+ keys: BaseSchema<KeyInput, KeyOutput, BaseSchemaDef<KeyInput>>;
330
+ values: BaseSchema<ValueInput, ValueOutput, BaseSchemaDef<ValueInput>>;
331
+ }
332
+ declare class KRecord<KeyInput extends string, KeyOutput extends string, ValueInput extends JSONValue, ValueOutput> extends BaseSchema<Record<KeyInput, ValueInput>, Record<KeyOutput, ValueOutput>, RecordDef<KeyInput, KeyOutput, ValueInput, ValueOutput>> {
333
+ static create: <KeyInput_1 extends string, KeyOutput_1 extends string, ValueInput_1 extends JSONValue, ValueOutput_1>(keys: BaseSchema<KeyInput_1, KeyOutput_1, BaseSchemaDef<KeyInput_1>>, values: BaseSchema<ValueInput_1, ValueOutput_1, BaseSchemaDef<ValueInput_1>>) => KRecord<KeyInput_1, KeyOutput_1, ValueInput_1, ValueOutput_1>;
334
+ serialize(value: Record<KeyOutput, ValueOutput>): Record<KeyInput, ValueInput>;
335
+ toOpenAPI(): SchemaObject;
336
+ parseSafe(json: unknown): ParseResult<Record<KeyOutput, ValueOutput>>;
337
+ parse(json: unknown): Record<KeyOutput, ValueOutput>;
338
+ visit(visitor: (schema: BaseSchema<any, any, any>) => void): void;
339
+ }
340
+ interface LazyDef<Input extends JSONValue, Output> extends BaseSchemaDef<Input> {
341
+ getter: () => BaseSchema<Input, Output, BaseSchemaDef<Input>>;
342
+ }
343
+ declare class KLazy<Input extends JSONValue, Output> extends BaseSchema<Input, Output, LazyDef<Input, Output>> {
344
+ private schema?;
345
+ static create: <Input_1 extends JSONValue, Output_1>(getter: () => BaseSchema<Input_1, Output_1, BaseSchemaDef<Input_1>>) => KLazy<Input_1, Output_1>;
346
+ private getSchema;
347
+ serialize(value: Output): Input;
348
+ toOpenAPI(): SchemaObject | ReferenceObject;
349
+ parseSafe(json: unknown): ParseResult<Output>;
350
+ parse(json: unknown): Output;
351
+ visit(visitor: (schema: BaseSchema<any, any, any>) => void): void;
352
+ }
325
353
  declare const k: {
326
354
  string: () => KString;
327
355
  number: () => KNumber;
@@ -329,10 +357,16 @@ declare const k: {
329
357
  array: <ItemsInput extends JSONValue, ItemsOutput, Def extends BaseSchemaDef<ItemsInput>>(items: BaseSchema<ItemsInput, ItemsOutput, Def>) => KArray<ItemsInput, ItemsOutput>;
330
358
  null: () => KNull;
331
359
  ref: <Input extends Record<keyof Output, JSONValue>, Output extends Record<keyof Input, any>>(name: string, shape: { [K in keyof Input | keyof Output]: BaseSchema<Input[K], Output[K], BaseSchemaDef<Input[K]>>; }) => KRef<Input, Output>;
360
+ record: <KeyInput extends string, KeyOutput extends string, ValueInput extends JSONValue, ValueOutput>(keys: BaseSchema<KeyInput, KeyOutput, BaseSchemaDef<KeyInput>>, values: BaseSchema<ValueInput, ValueOutput, BaseSchemaDef<ValueInput>>) => KRecord<KeyInput, KeyOutput, ValueInput, ValueOutput>;
332
361
  object: <Input extends Record<keyof Output, any>, Output extends Record<keyof Input, any>>(shape: { [K in keyof Input | keyof Output]: BaseSchema<Input[K], Output[K], BaseSchemaDef<Input[K]>>; }) => KObject<Input, Output>;
333
362
  scalar: <ClientRepresentation extends JSONPrimitive, ServerRepresentation>(options: ScalarOptions<ClientRepresentation, ServerRepresentation>) => KScalar<ClientRepresentation, ServerRepresentation>;
334
363
  literal: <Value extends string | number | boolean>(value: Value) => KLiteral<Value>;
335
364
  union: <Items extends [a: BaseSchema<JSONValue, unknown, BaseSchemaDef<JSONValue>>, b: BaseSchema<JSONValue, unknown, BaseSchemaDef<JSONValue>>, ...remaining: BaseSchema<JSONValue, unknown, BaseSchemaDef<JSONValue>>[]]>(items: Items) => KUnion<Items[number]["_input"], Items[number]["_output"]>;
365
+ lazy: <Input extends JSONValue, Output>(getter: () => BaseSchema<Input, Output, BaseSchemaDef<Input>>) => KLazy<Input, Output>;
366
+ /**
367
+ * Schema for any valid JSON value
368
+ */
369
+ json: () => BaseSchema<JSONValue, JSONValue, BaseSchemaDef<JSONValue>>;
336
370
  /**
337
371
  * @internal
338
372
  * @experimental
@@ -340,4 +374,4 @@ declare const k: {
340
374
  objectFromURLSearchParams: <Input extends Record<keyof Output, JSONValue>, Output extends Record<keyof Input, JSONValue>>(shape: { [K in keyof Input | keyof Output]: BaseSchema<Input[K], Output[K], BaseSchemaDef<Input[K]>>; }) => KObjectFromURLSearchParams<Input, Output>;
341
375
  };
342
376
 
343
- export { type AnySchemaFor, type ArrayChecks, type ArrayDef, BaseSchema, type BaseSchemaDef, type BooleanDef, type Issue, type JSONPrimitive, type JSONValue, KArray, KBoolean, KLiteral, KNull, KNumber, KObject, KObjectFromURLSearchParams, KRef, KScalar, KString, KUnion, type LiteralDef, type NullDef, type NumberChecks, type NumberDef, type NumberFormat, type ObjectDef, ParseContext, type ParseResult, type RefDef, STRING_FORMAT_REGEXES, type ScalarDef, type ScalarOptions, SchemaError, type StringChecks, type StringDef, type StringFormat, type UnionDef, isPrimitiveJSONValue, k };
377
+ export { type AnySchemaFor, type ArrayChecks, type ArrayDef, BaseSchema, type BaseSchemaDef, type BooleanDef, type Issue, type JSONPrimitive, type JSONValue, KArray, KBoolean, KLazy, KLiteral, KNull, KNumber, KObject, KObjectFromURLSearchParams, KRecord, KRef, KScalar, KString, KUnion, type LazyDef, type LiteralDef, type NullDef, type NumberChecks, type NumberDef, type NumberFormat, type ObjectDef, ParseContext, type ParseResult, type RecordDef, type RefDef, STRING_FORMAT_REGEXES, type ScalarDef, type ScalarOptions, SchemaError, type StringChecks, type StringDef, type StringFormat, type UnionDef, isPrimitiveJSONValue, k };
@@ -2,11 +2,13 @@ import {
2
2
  BaseSchema,
3
3
  KArray,
4
4
  KBoolean,
5
+ KLazy,
5
6
  KLiteral,
6
7
  KNull,
7
8
  KNumber,
8
9
  KObject,
9
10
  KObjectFromURLSearchParams,
11
+ KRecord,
10
12
  KRef,
11
13
  KScalar,
12
14
  KString,
@@ -16,16 +18,18 @@ import {
16
18
  SchemaError,
17
19
  isPrimitiveJSONValue,
18
20
  k
19
- } from "../chunk-IEGYJT4R.js";
21
+ } from "../chunk-BJVNFSCY.js";
20
22
  export {
21
23
  BaseSchema,
22
24
  KArray,
23
25
  KBoolean,
26
+ KLazy,
24
27
  KLiteral,
25
28
  KNull,
26
29
  KNumber,
27
30
  KObject,
28
31
  KObjectFromURLSearchParams,
32
+ KRecord,
29
33
  KRef,
30
34
  KScalar,
31
35
  KString,
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.26",
5
5
  "author": "Alistair Smith <hi@alistair.sh>",
6
6
  "repository": "https://github.com/kaito-http/kaito",
7
7
  "dependencies": {