@kaito-http/core 4.0.0-beta.29 → 4.0.0-beta.30

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.
@@ -756,6 +756,7 @@ var KScalar = class _KScalar extends BaseSchema {
756
756
  };
757
757
  var KUnion = class _KUnion extends BaseSchema {
758
758
  static create = (items) => new _KUnion({ items });
759
+ static enum = (values) => k.union(values.map((v) => k.literal(v)));
759
760
  serialize(value) {
760
761
  for (const option of this.def.items) {
761
762
  try {
@@ -830,6 +831,41 @@ var KLiteral = class _KLiteral extends BaseSchema {
830
831
  visit() {
831
832
  }
832
833
  };
834
+ var KNativeEnum = class _KNativeEnum extends BaseSchema {
835
+ static create = (enumObject) => new _KNativeEnum({ enum: enumObject });
836
+ serialize(value) {
837
+ return value;
838
+ }
839
+ toOpenAPI() {
840
+ const baseSchema = this.getSchemaObject();
841
+ const actualValues = Object.keys(this.def.enum).filter((key) => Number.isNaN(Number(key))).map((key) => this.def.enum[key]);
842
+ const uniqueValues = [...new Set(actualValues)];
843
+ const type = typeof uniqueValues[0] === "number" ? "number" : "string";
844
+ return {
845
+ ...baseSchema,
846
+ type,
847
+ enum: uniqueValues
848
+ };
849
+ }
850
+ parseSafe(json) {
851
+ return ParseContext.result((ctx) => {
852
+ const actualValues = Object.keys(this.def.enum).filter((key) => Number.isNaN(Number(key))).map((key) => this.def.enum[key]);
853
+ if (!actualValues.includes(json)) {
854
+ return ctx.addIssue(`Expected one of: ${actualValues.join(", ")}`, []);
855
+ }
856
+ return json;
857
+ });
858
+ }
859
+ parse(json) {
860
+ const result = this.parseSafe(json);
861
+ if (!result.success) {
862
+ throw new SchemaError(result.issues);
863
+ }
864
+ return result.result;
865
+ }
866
+ visit() {
867
+ }
868
+ };
833
869
  var KRecord = class _KRecord extends BaseSchema {
834
870
  static create = (keys, values) => new _KRecord({ keys, values });
835
871
  serialize(value) {
@@ -923,6 +959,8 @@ var k = {
923
959
  object: KObject.create,
924
960
  scalar: KScalar.create,
925
961
  literal: KLiteral.create,
962
+ enum: KUnion.enum,
963
+ nativeEnum: KNativeEnum.create,
926
964
  union: KUnion.create,
927
965
  lazy: KLazy.create,
928
966
  /**
@@ -958,6 +996,7 @@ export {
958
996
  KScalar,
959
997
  KUnion,
960
998
  KLiteral,
999
+ KNativeEnum,
961
1000
  KRecord,
962
1001
  KLazy,
963
1002
  k
@@ -0,0 +1,92 @@
1
+ // src/stream/stream.ts
2
+ var KaitoSSEResponse = class {
3
+ events;
4
+ constructor(events) {
5
+ this.events = events;
6
+ }
7
+ };
8
+ function sseEventToString(event) {
9
+ const lines = [];
10
+ if (event.event) {
11
+ lines.push(`event:${event.event}`);
12
+ }
13
+ if (event.id) {
14
+ lines.push(`id:${event.id}`);
15
+ }
16
+ if (event.retry) {
17
+ lines.push(`retry:${event.retry}`);
18
+ }
19
+ if (event.data !== void 0) {
20
+ lines.push(`data:${JSON.stringify(event.data)}`);
21
+ }
22
+ return lines.join("\n");
23
+ }
24
+ var SSEController = class {
25
+ controller;
26
+ constructor(controller) {
27
+ this.controller = controller;
28
+ }
29
+ enqueue(event) {
30
+ this.controller.enqueue(event);
31
+ }
32
+ close() {
33
+ this.controller.close();
34
+ }
35
+ [Symbol.dispose]() {
36
+ this.close();
37
+ }
38
+ };
39
+ function sseFromSource(source) {
40
+ const start = source.start;
41
+ const pull = source.pull;
42
+ const cancel = source.cancel;
43
+ const readable = new ReadableStream({
44
+ ...cancel ? { cancel } : {},
45
+ ...start ? {
46
+ start: async (controller) => {
47
+ await start(new SSEController(controller));
48
+ }
49
+ } : {},
50
+ ...pull ? {
51
+ pull: async (controller) => {
52
+ await pull(new SSEController(controller));
53
+ }
54
+ } : {}
55
+ });
56
+ return new KaitoSSEResponse(readable);
57
+ }
58
+ function sse(source) {
59
+ const evaluated = typeof source === "function" ? source() : source;
60
+ if ("next" in evaluated) {
61
+ const generator = evaluated;
62
+ return sseFromSource({
63
+ async start(controller) {
64
+ try {
65
+ for await (const event of generator) {
66
+ controller.enqueue(event);
67
+ }
68
+ } finally {
69
+ controller.close();
70
+ }
71
+ }
72
+ });
73
+ } else {
74
+ return sseFromSource(evaluated);
75
+ }
76
+ }
77
+ function sseFromAnyReadable(stream, transform) {
78
+ const transformer = new TransformStream({
79
+ transform: (chunk, controller) => {
80
+ controller.enqueue(transform(chunk));
81
+ }
82
+ });
83
+ return sse(stream.pipeThrough(transformer));
84
+ }
85
+
86
+ export {
87
+ KaitoSSEResponse,
88
+ sseEventToString,
89
+ SSEController,
90
+ sse,
91
+ sseFromAnyReadable
92
+ };
package/dist/index.cjs CHANGED
@@ -25,6 +25,7 @@ __export(index_exports, {
25
25
  KBoolean: () => KBoolean,
26
26
  KLazy: () => KLazy,
27
27
  KLiteral: () => KLiteral,
28
+ KNativeEnum: () => KNativeEnum,
28
29
  KNull: () => KNull,
29
30
  KNumber: () => KNumber,
30
31
  KObject: () => KObject,
@@ -916,6 +917,7 @@ var KScalar = class _KScalar extends BaseSchema {
916
917
  };
917
918
  var KUnion = class _KUnion extends BaseSchema {
918
919
  static create = (items) => new _KUnion({ items });
920
+ static enum = (values) => k.union(values.map((v) => k.literal(v)));
919
921
  serialize(value) {
920
922
  for (const option of this.def.items) {
921
923
  try {
@@ -990,6 +992,41 @@ var KLiteral = class _KLiteral extends BaseSchema {
990
992
  visit() {
991
993
  }
992
994
  };
995
+ var KNativeEnum = class _KNativeEnum extends BaseSchema {
996
+ static create = (enumObject) => new _KNativeEnum({ enum: enumObject });
997
+ serialize(value) {
998
+ return value;
999
+ }
1000
+ toOpenAPI() {
1001
+ const baseSchema = this.getSchemaObject();
1002
+ const actualValues = Object.keys(this.def.enum).filter((key) => Number.isNaN(Number(key))).map((key) => this.def.enum[key]);
1003
+ const uniqueValues = [...new Set(actualValues)];
1004
+ const type = typeof uniqueValues[0] === "number" ? "number" : "string";
1005
+ return {
1006
+ ...baseSchema,
1007
+ type,
1008
+ enum: uniqueValues
1009
+ };
1010
+ }
1011
+ parseSafe(json) {
1012
+ return ParseContext.result((ctx) => {
1013
+ const actualValues = Object.keys(this.def.enum).filter((key) => Number.isNaN(Number(key))).map((key) => this.def.enum[key]);
1014
+ if (!actualValues.includes(json)) {
1015
+ return ctx.addIssue(`Expected one of: ${actualValues.join(", ")}`, []);
1016
+ }
1017
+ return json;
1018
+ });
1019
+ }
1020
+ parse(json) {
1021
+ const result = this.parseSafe(json);
1022
+ if (!result.success) {
1023
+ throw new SchemaError(result.issues);
1024
+ }
1025
+ return result.result;
1026
+ }
1027
+ visit() {
1028
+ }
1029
+ };
993
1030
  var KRecord = class _KRecord extends BaseSchema {
994
1031
  static create = (keys, values) => new _KRecord({ keys, values });
995
1032
  serialize(value) {
@@ -1083,6 +1120,8 @@ var k = {
1083
1120
  object: KObject.create,
1084
1121
  scalar: KScalar.create,
1085
1122
  literal: KLiteral.create,
1123
+ enum: KUnion.enum,
1124
+ nativeEnum: KNativeEnum.create,
1086
1125
  union: KUnion.create,
1087
1126
  lazy: KLazy.create,
1088
1127
  /**
@@ -1101,19 +1140,37 @@ var k = {
1101
1140
  objectFromURLSearchParams: KObjectFromURLSearchParams.create
1102
1141
  };
1103
1142
 
1143
+ // src/stream/stream.ts
1144
+ var KaitoSSEResponse = class {
1145
+ events;
1146
+ constructor(events) {
1147
+ this.events = events;
1148
+ }
1149
+ };
1150
+ function sseEventToString(event) {
1151
+ const lines = [];
1152
+ if (event.event) {
1153
+ lines.push(`event:${event.event}`);
1154
+ }
1155
+ if (event.id) {
1156
+ lines.push(`id:${event.id}`);
1157
+ }
1158
+ if (event.retry) {
1159
+ lines.push(`retry:${event.retry}`);
1160
+ }
1161
+ if (event.data !== void 0) {
1162
+ lines.push(`data:${JSON.stringify(event.data)}`);
1163
+ }
1164
+ return lines.join("\n");
1165
+ }
1166
+
1104
1167
  // src/util.ts
1105
1168
  var isNodeLikeDev = typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.NODE_ENV === "development";
1106
1169
 
1107
1170
  // src/router/router.ts
1108
1171
  var Router = class _Router {
1109
1172
  #state;
1110
- static create = (config = {}) => {
1111
- return new _Router({
1112
- through: (context) => context,
1113
- routes: /* @__PURE__ */ new Set(),
1114
- config
1115
- });
1116
- };
1173
+ static create = (config = {}) => new _Router({ through: (context) => context, routes: /* @__PURE__ */ new Set(), config });
1117
1174
  constructor(state) {
1118
1175
  this.#state = state;
1119
1176
  }
@@ -1205,6 +1262,26 @@ var Router = class _Router {
1205
1262
  query,
1206
1263
  params: rawParams
1207
1264
  });
1265
+ if (result instanceof KaitoSSEResponse) {
1266
+ const body2 = route.openapi?.body;
1267
+ const schema = body2 && "schema" in body2 ? body2.schema : void 0;
1268
+ const stringStream = result.events.pipeThrough(
1269
+ new TransformStream({
1270
+ transform(event, controller) {
1271
+ const serialized = schema ? { ...event, data: event.data !== void 0 ? schema.serialize(event.data) : void 0 } : event;
1272
+ controller.enqueue(sseEventToString(serialized) + "\n\n");
1273
+ }
1274
+ })
1275
+ );
1276
+ const sseHeaders = new Headers(head.touched ? head.headers : void 0);
1277
+ sseHeaders.set("Content-Type", "text/event-stream");
1278
+ sseHeaders.set("Cache-Control", "no-cache");
1279
+ sseHeaders.set("Connection", "keep-alive");
1280
+ return new Response(stringStream, {
1281
+ status: head.status(),
1282
+ headers: sseHeaders
1283
+ });
1284
+ }
1208
1285
  if (result instanceof Response) {
1209
1286
  if (isNodeLikeDev) {
1210
1287
  if (head.touched) {
@@ -1219,13 +1296,8 @@ var Router = class _Router {
1219
1296
  }
1220
1297
  return result;
1221
1298
  }
1222
- if (route.openapi?.schema) {
1223
- if (route.openapi.type !== "json") {
1224
- throw new Error(
1225
- `Cannot use openapi schema for ${route.method} ${route.path} because it is not a json output type`
1226
- );
1227
- }
1228
- const parsed = route.openapi.schema.serialize(result);
1299
+ if (route.openapi && "schema" in route.openapi.body && route.openapi.body.schema) {
1300
+ const parsed = route.openapi.body.schema.serialize(result);
1229
1301
  return head.toResponse(parsed);
1230
1302
  }
1231
1303
  if (result === void 0) {
@@ -1345,7 +1417,7 @@ var Router = class _Router {
1345
1417
  paths[pathWithColonParamsReplaceWithCurlyBraces] = {};
1346
1418
  }
1347
1419
  let contentType;
1348
- const type = route.openapi.type;
1420
+ const type = route.openapi.body.type;
1349
1421
  switch (type) {
1350
1422
  case "json":
1351
1423
  contentType = "application/json";
@@ -1353,19 +1425,24 @@ var Router = class _Router {
1353
1425
  case "sse":
1354
1426
  contentType = "text/event-stream";
1355
1427
  break;
1428
+ case "response":
1429
+ contentType = "application/octet-stream";
1430
+ break;
1356
1431
  default:
1357
1432
  throw new Error(`Unknown output type in route ${route.method} ${route.path}: ${type}`);
1358
1433
  }
1359
- if (route.openapi.schema) visit(route.openapi.schema);
1434
+ if ("schema" in route.openapi.body && route.openapi.body.schema) visit(route.openapi.body.schema);
1360
1435
  if (route.body) visit(route.body);
1436
+ const responseSchema = "schema" in route.openapi.body && route.openapi.body.schema ? route.openapi.body.schema.toOpenAPI() : { type: "string" };
1361
1437
  const item = {
1438
+ ...route.openapi.summary ? { summary: route.openapi.summary } : {},
1362
1439
  description: route.openapi?.description ?? "Successful response",
1363
1440
  responses: {
1364
1441
  200: {
1365
- description: route.openapi?.description ?? "Successful response",
1442
+ description: route.openapi.body.description ?? "Successful response",
1366
1443
  content: {
1367
1444
  [contentType]: {
1368
- schema: route.openapi.schema.toOpenAPI()
1445
+ schema: responseSchema
1369
1446
  }
1370
1447
  }
1371
1448
  }
@@ -1428,6 +1505,7 @@ var create = Router.create;
1428
1505
  KBoolean,
1429
1506
  KLazy,
1430
1507
  KLiteral,
1508
+ KNativeEnum,
1431
1509
  KNull,
1432
1510
  KNumber,
1433
1511
  KObject,
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
- import { JSONValue, AnySchemaFor, BaseSchema, BaseSchemaDef } from './schema/schema.cjs';
2
- 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';
1
+ import { JSONValue, BaseSchema, AnySchemaFor } from './schema/schema.cjs';
2
+ export { ArrayChecks, ArrayDef, BaseSchemaDef, BooleanDef, Issue, JSONPrimitive, KArray, KBoolean, KLazy, KLiteral, KNativeEnum, KNull, KNumber, KObject, KObjectFromURLSearchParams, KRecord, KRef, KScalar, KString, KUnion, LazyDef, LiteralDef, NativeEnumDef, 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';
3
3
  import * as OpenAPI from 'openapi3-ts/oas31';
4
- import { KaitoSSEResponse } from './stream/stream.cjs';
4
+ import { KaitoSSEResponse, SSEEvent } from './stream/stream.cjs';
5
5
 
6
6
  declare class WrappedError<T> extends Error {
7
7
  static maybe<T>(maybeError: T): (T & Error) | WrappedError<T>;
@@ -74,7 +74,7 @@ declare class KaitoHead {
74
74
  get touched(): boolean;
75
75
  }
76
76
 
77
- type PrefixRoutesPathInner<R extends AnyRoute, Prefix extends `/${string}`> = R extends Route<infer ContextFrom, infer ContextTo, infer RouterInput, infer ResultInput, infer ResultOutput, infer Path, infer AdditionalParams, infer Method, infer Query, infer BodyOutput> ? Route<ContextFrom, ContextTo, RouterInput, ResultInput, ResultOutput, `${Prefix}${Path extends '/' ? '' : Path}`, AdditionalParams, Method, Query, BodyOutput> : never;
77
+ type PrefixRoutesPathInner<R extends AnyRoute, Prefix extends `/${string}`> = R extends Route<infer ContextFrom, infer ContextTo, infer RouterInput, infer ResultOutput, infer Path, infer AdditionalParams, infer Method, infer Query, infer BodyOutput> ? Route<ContextFrom, ContextTo, RouterInput, ResultOutput, `${Prefix}${Path extends '/' ? '' : Path}`, AdditionalParams, Method, Query, BodyOutput> : never;
78
78
  type PrefixRoutesPath<Prefix extends `/${string}`, R extends AnyRoute> = R extends R ? PrefixRoutesPathInner<R, Prefix> : never;
79
79
  type RouterState<ContextFrom, ContextTo, RequiredParams extends string, Routes extends AnyRoute, Input extends readonly unknown[]> = {
80
80
  routes: Set<Routes>;
@@ -121,15 +121,29 @@ declare class Router<ContextFrom, ContextTo, RequiredParams extends string, Rout
121
121
  openapi: ({ info, servers, }: {
122
122
  info: OpenAPI.InfoObject;
123
123
  servers?: Partial<Record<(`https://` | `http://`) | ({} & string), string>>;
124
- }) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, never, Response, "/openapi.json", RequiredParams, "GET", {}, never>, Input>;
124
+ }) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, Response, "/openapi.json", RequiredParams, "GET", {}, never>, Input>;
125
125
  private readonly method;
126
- 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>;
127
- 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>;
128
- 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>;
129
- 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>;
130
- 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>;
131
- 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>;
132
- 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>;
126
+ readonly get: <Path extends string, ResultOutput = never, 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, ResultOutput, Path, RequiredParams, "GET", Query, Body>, "body" | "path" | "method" | "router" | "openapi"> & {
127
+ openapi?: OpenAPISpecFor<ResultOutput>;
128
+ })) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultOutput, Path, RequiredParams, "GET", Query, Body>, Input>;
129
+ readonly post: <Path extends string, ResultOutput = never, 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, ResultOutput, Path, RequiredParams, "POST", Query, Body>, "path" | "method" | "router" | "openapi"> & {
130
+ openapi?: OpenAPISpecFor<ResultOutput>;
131
+ })) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultOutput, Path, RequiredParams, "POST", Query, Body>, Input>;
132
+ readonly put: <Path extends string, ResultOutput = never, 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, ResultOutput, Path, RequiredParams, "PUT", Query, Body>, "path" | "method" | "router" | "openapi"> & {
133
+ openapi?: OpenAPISpecFor<ResultOutput>;
134
+ })) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultOutput, Path, RequiredParams, "PUT", Query, Body>, Input>;
135
+ readonly patch: <Path extends string, ResultOutput = never, 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, ResultOutput, Path, RequiredParams, "PATCH", Query, Body>, "path" | "method" | "router" | "openapi"> & {
136
+ openapi?: OpenAPISpecFor<ResultOutput>;
137
+ })) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultOutput, Path, RequiredParams, "PATCH", Query, Body>, Input>;
138
+ readonly delete: <Path extends string, ResultOutput = never, 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, ResultOutput, Path, RequiredParams, "DELETE", Query, Body>, "path" | "method" | "router" | "openapi"> & {
139
+ openapi?: OpenAPISpecFor<ResultOutput>;
140
+ })) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultOutput, Path, RequiredParams, "DELETE", Query, Body>, Input>;
141
+ readonly head: <Path extends string, ResultOutput = never, 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, ResultOutput, Path, RequiredParams, "HEAD", Query, Body>, "path" | "method" | "router" | "openapi"> & {
142
+ openapi?: OpenAPISpecFor<ResultOutput>;
143
+ })) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultOutput, Path, RequiredParams, "HEAD", Query, Body>, Input>;
144
+ readonly options: <Path extends string, ResultOutput = never, 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, ResultOutput, Path, RequiredParams, "OPTIONS", Query, Body>, "path" | "method" | "router" | "openapi"> & {
145
+ openapi?: OpenAPISpecFor<ResultOutput>;
146
+ })) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultOutput, Path, RequiredParams, "OPTIONS", Query, Body>, Input>;
133
147
  through: <NextContext>(through: (context: ContextTo, params: Record<RequiredParams, string>) => MaybePromise<NextContext>) => Router<ContextFrom, NextContext, RequiredParams, Routes, Input>;
134
148
  }
135
149
 
@@ -143,29 +157,45 @@ type AnyQuery = {
143
157
  [key in string]: any;
144
158
  };
145
159
  type Through<From, To, RequiredParams extends string> = (context: From, params: Record<RequiredParams, string>) => Promise<To>;
146
- type SSEOutputSpec<Result extends JSONValue> = {
160
+ type SSEOutputSpecWithSchema = {
147
161
  type: 'sse';
148
- schema: AnySchemaFor<Result>;
162
+ schema: BaseSchema<any, any, any>;
149
163
  description?: string | undefined;
150
164
  };
151
- type JSONOutputSpec<ResultInput, ResultOutput extends JSONValue> = {
165
+ type SSEOutputSpecWithoutSchema = {
166
+ type: 'sse';
167
+ schema?: undefined;
168
+ description?: string | undefined;
169
+ };
170
+ type SSEOutputSpec = SSEOutputSpecWithSchema | SSEOutputSpecWithoutSchema;
171
+ type JSONOutputSpec = {
152
172
  type: 'json';
153
- schema: BaseSchema<ResultOutput, ResultInput, BaseSchemaDef<ResultOutput>>;
173
+ schema: BaseSchema<any, any, any>;
154
174
  description?: string | undefined;
155
175
  };
156
- type OutputSpec<ResultInput, ResultOutput> = ResultInput extends KaitoSSEResponse<infer R> ? SSEOutputSpec<Extract<R, JSONValue>> : JSONOutputSpec<ResultOutput, Extract<ResultInput, JSONValue>>;
157
- 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> = {
176
+ type ResponseOutputSpec = {
177
+ type: 'response';
178
+ description?: string | undefined;
179
+ };
180
+ type OutputSpec = SSEOutputSpec | JSONOutputSpec | ResponseOutputSpec;
181
+ type OpenAPISpec<Body extends OutputSpec = OutputSpec> = {
182
+ summary?: string;
183
+ description?: string;
184
+ body: Body;
185
+ };
186
+ type OpenAPISpecFor<ResultOutput> = 0 extends 1 & ResultOutput ? OpenAPISpec : [ResultOutput] extends [never] ? OpenAPISpec : [ResultOutput] extends [KaitoSSEResponse<any>] ? [ResultOutput extends KaitoSSEResponse<SSEEvent<infer U, any>> ? U : never] extends [JSONValue] ? OpenAPISpec<SSEOutputSpec> : OpenAPISpec<SSEOutputSpecWithSchema> : [ResultOutput] extends [Response] ? OpenAPISpec<ResponseOutputSpec> : OpenAPISpec<JSONOutputSpec>;
187
+ type Route<ContextFrom, ContextTo, RouterInput extends readonly unknown[], ResultOutput, Path extends string, AdditionalParams extends string, Method extends KaitoMethod, Query extends Record<string, JSONValue>, Body extends JSONValue> = {
158
188
  body?: AnySchemaFor<Body>;
159
189
  query?: {
160
190
  [Key in keyof Query]: AnySchemaFor<Query[Key]>;
161
191
  };
162
192
  path: Path;
163
193
  method: Method;
164
- openapi?: OutputSpec<ResultInput, ResultOutput>;
194
+ openapi?: OpenAPISpec;
165
195
  router: Router<ContextFrom, ContextTo, AdditionalParams, AnyRoute, RouterInput>;
166
196
  run(data: RouteRunData<ExtractRouteParams<Path> | AdditionalParams, ContextTo, Query, Body>): Promise<ResultOutput> | ResultOutput;
167
197
  };
168
- type AnyRoute = Route<any, any, any, any, any, any, any, any, any, any>;
198
+ type AnyRoute = Route<any, any, any, unknown, any, any, any, any, any>;
169
199
 
170
200
  /**
171
201
  * A helper to check if the environment is Node.js-like and the `NODE_ENV` environment variable is set to `'development'`
@@ -267,4 +297,4 @@ interface KaitoConfig<ContextFrom, Input extends readonly unknown[]> {
267
297
  */
268
298
  declare const create: <Context = null, Input extends readonly unknown[] = []>(config?: KaitoConfig<Context, Input>) => Router<Context, Context, never, never, Input>;
269
299
 
270
- export { type AnyQuery, type AnyRoute, AnySchemaFor, BaseSchema, BaseSchemaDef, 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 Through, WrappedError, create, isNodeLikeDev };
300
+ export { type AnyQuery, type AnyRoute, AnySchemaFor, BaseSchema, type ExtractRouteParams, type GetContext, type InferRoutes, type JSONOutputSpec, JSONValue, type KaitoConfig, KaitoError, KaitoHead, type KaitoMethod, KaitoRequest, type MaybePromise, type OpenAPISpec, type OpenAPISpecFor, type OutputSpec, type ResponseOutputSpec, type Route, type RouteRunData, Router, type RouterState, type SSEOutputSpec, type SSEOutputSpecWithSchema, type SSEOutputSpecWithoutSchema, type Through, WrappedError, create, isNodeLikeDev };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { JSONValue, AnySchemaFor, BaseSchema, BaseSchemaDef } from './schema/schema.js';
2
- 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';
1
+ import { JSONValue, BaseSchema, AnySchemaFor } from './schema/schema.js';
2
+ export { ArrayChecks, ArrayDef, BaseSchemaDef, BooleanDef, Issue, JSONPrimitive, KArray, KBoolean, KLazy, KLiteral, KNativeEnum, KNull, KNumber, KObject, KObjectFromURLSearchParams, KRecord, KRef, KScalar, KString, KUnion, LazyDef, LiteralDef, NativeEnumDef, 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';
3
3
  import * as OpenAPI from 'openapi3-ts/oas31';
4
- import { KaitoSSEResponse } from './stream/stream.js';
4
+ import { KaitoSSEResponse, SSEEvent } from './stream/stream.js';
5
5
 
6
6
  declare class WrappedError<T> extends Error {
7
7
  static maybe<T>(maybeError: T): (T & Error) | WrappedError<T>;
@@ -74,7 +74,7 @@ declare class KaitoHead {
74
74
  get touched(): boolean;
75
75
  }
76
76
 
77
- type PrefixRoutesPathInner<R extends AnyRoute, Prefix extends `/${string}`> = R extends Route<infer ContextFrom, infer ContextTo, infer RouterInput, infer ResultInput, infer ResultOutput, infer Path, infer AdditionalParams, infer Method, infer Query, infer BodyOutput> ? Route<ContextFrom, ContextTo, RouterInput, ResultInput, ResultOutput, `${Prefix}${Path extends '/' ? '' : Path}`, AdditionalParams, Method, Query, BodyOutput> : never;
77
+ type PrefixRoutesPathInner<R extends AnyRoute, Prefix extends `/${string}`> = R extends Route<infer ContextFrom, infer ContextTo, infer RouterInput, infer ResultOutput, infer Path, infer AdditionalParams, infer Method, infer Query, infer BodyOutput> ? Route<ContextFrom, ContextTo, RouterInput, ResultOutput, `${Prefix}${Path extends '/' ? '' : Path}`, AdditionalParams, Method, Query, BodyOutput> : never;
78
78
  type PrefixRoutesPath<Prefix extends `/${string}`, R extends AnyRoute> = R extends R ? PrefixRoutesPathInner<R, Prefix> : never;
79
79
  type RouterState<ContextFrom, ContextTo, RequiredParams extends string, Routes extends AnyRoute, Input extends readonly unknown[]> = {
80
80
  routes: Set<Routes>;
@@ -121,15 +121,29 @@ declare class Router<ContextFrom, ContextTo, RequiredParams extends string, Rout
121
121
  openapi: ({ info, servers, }: {
122
122
  info: OpenAPI.InfoObject;
123
123
  servers?: Partial<Record<(`https://` | `http://`) | ({} & string), string>>;
124
- }) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, never, Response, "/openapi.json", RequiredParams, "GET", {}, never>, Input>;
124
+ }) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, Response, "/openapi.json", RequiredParams, "GET", {}, never>, Input>;
125
125
  private readonly method;
126
- 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>;
127
- 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>;
128
- 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>;
129
- 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>;
130
- 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>;
131
- 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>;
132
- 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>;
126
+ readonly get: <Path extends string, ResultOutput = never, 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, ResultOutput, Path, RequiredParams, "GET", Query, Body>, "body" | "path" | "method" | "router" | "openapi"> & {
127
+ openapi?: OpenAPISpecFor<ResultOutput>;
128
+ })) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultOutput, Path, RequiredParams, "GET", Query, Body>, Input>;
129
+ readonly post: <Path extends string, ResultOutput = never, 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, ResultOutput, Path, RequiredParams, "POST", Query, Body>, "path" | "method" | "router" | "openapi"> & {
130
+ openapi?: OpenAPISpecFor<ResultOutput>;
131
+ })) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultOutput, Path, RequiredParams, "POST", Query, Body>, Input>;
132
+ readonly put: <Path extends string, ResultOutput = never, 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, ResultOutput, Path, RequiredParams, "PUT", Query, Body>, "path" | "method" | "router" | "openapi"> & {
133
+ openapi?: OpenAPISpecFor<ResultOutput>;
134
+ })) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultOutput, Path, RequiredParams, "PUT", Query, Body>, Input>;
135
+ readonly patch: <Path extends string, ResultOutput = never, 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, ResultOutput, Path, RequiredParams, "PATCH", Query, Body>, "path" | "method" | "router" | "openapi"> & {
136
+ openapi?: OpenAPISpecFor<ResultOutput>;
137
+ })) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultOutput, Path, RequiredParams, "PATCH", Query, Body>, Input>;
138
+ readonly delete: <Path extends string, ResultOutput = never, 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, ResultOutput, Path, RequiredParams, "DELETE", Query, Body>, "path" | "method" | "router" | "openapi"> & {
139
+ openapi?: OpenAPISpecFor<ResultOutput>;
140
+ })) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultOutput, Path, RequiredParams, "DELETE", Query, Body>, Input>;
141
+ readonly head: <Path extends string, ResultOutput = never, 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, ResultOutput, Path, RequiredParams, "HEAD", Query, Body>, "path" | "method" | "router" | "openapi"> & {
142
+ openapi?: OpenAPISpecFor<ResultOutput>;
143
+ })) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultOutput, Path, RequiredParams, "HEAD", Query, Body>, Input>;
144
+ readonly options: <Path extends string, ResultOutput = never, 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, ResultOutput, Path, RequiredParams, "OPTIONS", Query, Body>, "path" | "method" | "router" | "openapi"> & {
145
+ openapi?: OpenAPISpecFor<ResultOutput>;
146
+ })) => Router<ContextFrom, ContextTo, RequiredParams, Routes | Route<ContextFrom, ContextTo, Input, ResultOutput, Path, RequiredParams, "OPTIONS", Query, Body>, Input>;
133
147
  through: <NextContext>(through: (context: ContextTo, params: Record<RequiredParams, string>) => MaybePromise<NextContext>) => Router<ContextFrom, NextContext, RequiredParams, Routes, Input>;
134
148
  }
135
149
 
@@ -143,29 +157,45 @@ type AnyQuery = {
143
157
  [key in string]: any;
144
158
  };
145
159
  type Through<From, To, RequiredParams extends string> = (context: From, params: Record<RequiredParams, string>) => Promise<To>;
146
- type SSEOutputSpec<Result extends JSONValue> = {
160
+ type SSEOutputSpecWithSchema = {
147
161
  type: 'sse';
148
- schema: AnySchemaFor<Result>;
162
+ schema: BaseSchema<any, any, any>;
149
163
  description?: string | undefined;
150
164
  };
151
- type JSONOutputSpec<ResultInput, ResultOutput extends JSONValue> = {
165
+ type SSEOutputSpecWithoutSchema = {
166
+ type: 'sse';
167
+ schema?: undefined;
168
+ description?: string | undefined;
169
+ };
170
+ type SSEOutputSpec = SSEOutputSpecWithSchema | SSEOutputSpecWithoutSchema;
171
+ type JSONOutputSpec = {
152
172
  type: 'json';
153
- schema: BaseSchema<ResultOutput, ResultInput, BaseSchemaDef<ResultOutput>>;
173
+ schema: BaseSchema<any, any, any>;
154
174
  description?: string | undefined;
155
175
  };
156
- type OutputSpec<ResultInput, ResultOutput> = ResultInput extends KaitoSSEResponse<infer R> ? SSEOutputSpec<Extract<R, JSONValue>> : JSONOutputSpec<ResultOutput, Extract<ResultInput, JSONValue>>;
157
- 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> = {
176
+ type ResponseOutputSpec = {
177
+ type: 'response';
178
+ description?: string | undefined;
179
+ };
180
+ type OutputSpec = SSEOutputSpec | JSONOutputSpec | ResponseOutputSpec;
181
+ type OpenAPISpec<Body extends OutputSpec = OutputSpec> = {
182
+ summary?: string;
183
+ description?: string;
184
+ body: Body;
185
+ };
186
+ type OpenAPISpecFor<ResultOutput> = 0 extends 1 & ResultOutput ? OpenAPISpec : [ResultOutput] extends [never] ? OpenAPISpec : [ResultOutput] extends [KaitoSSEResponse<any>] ? [ResultOutput extends KaitoSSEResponse<SSEEvent<infer U, any>> ? U : never] extends [JSONValue] ? OpenAPISpec<SSEOutputSpec> : OpenAPISpec<SSEOutputSpecWithSchema> : [ResultOutput] extends [Response] ? OpenAPISpec<ResponseOutputSpec> : OpenAPISpec<JSONOutputSpec>;
187
+ type Route<ContextFrom, ContextTo, RouterInput extends readonly unknown[], ResultOutput, Path extends string, AdditionalParams extends string, Method extends KaitoMethod, Query extends Record<string, JSONValue>, Body extends JSONValue> = {
158
188
  body?: AnySchemaFor<Body>;
159
189
  query?: {
160
190
  [Key in keyof Query]: AnySchemaFor<Query[Key]>;
161
191
  };
162
192
  path: Path;
163
193
  method: Method;
164
- openapi?: OutputSpec<ResultInput, ResultOutput>;
194
+ openapi?: OpenAPISpec;
165
195
  router: Router<ContextFrom, ContextTo, AdditionalParams, AnyRoute, RouterInput>;
166
196
  run(data: RouteRunData<ExtractRouteParams<Path> | AdditionalParams, ContextTo, Query, Body>): Promise<ResultOutput> | ResultOutput;
167
197
  };
168
- type AnyRoute = Route<any, any, any, any, any, any, any, any, any, any>;
198
+ type AnyRoute = Route<any, any, any, unknown, any, any, any, any, any>;
169
199
 
170
200
  /**
171
201
  * A helper to check if the environment is Node.js-like and the `NODE_ENV` environment variable is set to `'development'`
@@ -267,4 +297,4 @@ interface KaitoConfig<ContextFrom, Input extends readonly unknown[]> {
267
297
  */
268
298
  declare const create: <Context = null, Input extends readonly unknown[] = []>(config?: KaitoConfig<Context, Input>) => Router<Context, Context, never, never, Input>;
269
299
 
270
- export { type AnyQuery, type AnyRoute, AnySchemaFor, BaseSchema, BaseSchemaDef, 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 Through, WrappedError, create, isNodeLikeDev };
300
+ export { type AnyQuery, type AnyRoute, AnySchemaFor, BaseSchema, type ExtractRouteParams, type GetContext, type InferRoutes, type JSONOutputSpec, JSONValue, type KaitoConfig, KaitoError, KaitoHead, type KaitoMethod, KaitoRequest, type MaybePromise, type OpenAPISpec, type OpenAPISpecFor, type OutputSpec, type ResponseOutputSpec, type Route, type RouteRunData, Router, type RouterState, type SSEOutputSpec, type SSEOutputSpecWithSchema, type SSEOutputSpecWithoutSchema, type Through, WrappedError, create, isNodeLikeDev };
package/dist/index.js CHANGED
@@ -1,9 +1,14 @@
1
+ import {
2
+ KaitoSSEResponse,
3
+ sseEventToString
4
+ } from "./chunk-HJ5HIYGW.js";
1
5
  import {
2
6
  BaseSchema,
3
7
  KArray,
4
8
  KBoolean,
5
9
  KLazy,
6
10
  KLiteral,
11
+ KNativeEnum,
7
12
  KNull,
8
13
  KNumber,
9
14
  KObject,
@@ -18,7 +23,7 @@ import {
18
23
  SchemaError,
19
24
  isPrimitiveJSONValue,
20
25
  k
21
- } from "./chunk-BJVNFSCY.js";
26
+ } from "./chunk-DRJX3OJG.js";
22
27
 
23
28
  // src/router/router.ts
24
29
  import "openapi3-ts/oas31";
@@ -135,13 +140,7 @@ var isNodeLikeDev = typeof process !== "undefined" && typeof process.env !== "un
135
140
  // src/router/router.ts
136
141
  var Router = class _Router {
137
142
  #state;
138
- static create = (config = {}) => {
139
- return new _Router({
140
- through: (context) => context,
141
- routes: /* @__PURE__ */ new Set(),
142
- config
143
- });
144
- };
143
+ static create = (config = {}) => new _Router({ through: (context) => context, routes: /* @__PURE__ */ new Set(), config });
145
144
  constructor(state) {
146
145
  this.#state = state;
147
146
  }
@@ -233,6 +232,26 @@ var Router = class _Router {
233
232
  query,
234
233
  params: rawParams
235
234
  });
235
+ if (result instanceof KaitoSSEResponse) {
236
+ const body2 = route.openapi?.body;
237
+ const schema = body2 && "schema" in body2 ? body2.schema : void 0;
238
+ const stringStream = result.events.pipeThrough(
239
+ new TransformStream({
240
+ transform(event, controller) {
241
+ const serialized = schema ? { ...event, data: event.data !== void 0 ? schema.serialize(event.data) : void 0 } : event;
242
+ controller.enqueue(sseEventToString(serialized) + "\n\n");
243
+ }
244
+ })
245
+ );
246
+ const sseHeaders = new Headers(head.touched ? head.headers : void 0);
247
+ sseHeaders.set("Content-Type", "text/event-stream");
248
+ sseHeaders.set("Cache-Control", "no-cache");
249
+ sseHeaders.set("Connection", "keep-alive");
250
+ return new Response(stringStream, {
251
+ status: head.status(),
252
+ headers: sseHeaders
253
+ });
254
+ }
236
255
  if (result instanceof Response) {
237
256
  if (isNodeLikeDev) {
238
257
  if (head.touched) {
@@ -247,13 +266,8 @@ var Router = class _Router {
247
266
  }
248
267
  return result;
249
268
  }
250
- if (route.openapi?.schema) {
251
- if (route.openapi.type !== "json") {
252
- throw new Error(
253
- `Cannot use openapi schema for ${route.method} ${route.path} because it is not a json output type`
254
- );
255
- }
256
- const parsed = route.openapi.schema.serialize(result);
269
+ if (route.openapi && "schema" in route.openapi.body && route.openapi.body.schema) {
270
+ const parsed = route.openapi.body.schema.serialize(result);
257
271
  return head.toResponse(parsed);
258
272
  }
259
273
  if (result === void 0) {
@@ -373,7 +387,7 @@ var Router = class _Router {
373
387
  paths[pathWithColonParamsReplaceWithCurlyBraces] = {};
374
388
  }
375
389
  let contentType;
376
- const type = route.openapi.type;
390
+ const type = route.openapi.body.type;
377
391
  switch (type) {
378
392
  case "json":
379
393
  contentType = "application/json";
@@ -381,19 +395,24 @@ var Router = class _Router {
381
395
  case "sse":
382
396
  contentType = "text/event-stream";
383
397
  break;
398
+ case "response":
399
+ contentType = "application/octet-stream";
400
+ break;
384
401
  default:
385
402
  throw new Error(`Unknown output type in route ${route.method} ${route.path}: ${type}`);
386
403
  }
387
- if (route.openapi.schema) visit(route.openapi.schema);
404
+ if ("schema" in route.openapi.body && route.openapi.body.schema) visit(route.openapi.body.schema);
388
405
  if (route.body) visit(route.body);
406
+ const responseSchema = "schema" in route.openapi.body && route.openapi.body.schema ? route.openapi.body.schema.toOpenAPI() : { type: "string" };
389
407
  const item = {
408
+ ...route.openapi.summary ? { summary: route.openapi.summary } : {},
390
409
  description: route.openapi?.description ?? "Successful response",
391
410
  responses: {
392
411
  200: {
393
- description: route.openapi?.description ?? "Successful response",
412
+ description: route.openapi.body.description ?? "Successful response",
394
413
  content: {
395
414
  [contentType]: {
396
- schema: route.openapi.schema.toOpenAPI()
415
+ schema: responseSchema
397
416
  }
398
417
  }
399
418
  }
@@ -455,6 +474,7 @@ export {
455
474
  KBoolean,
456
475
  KLazy,
457
476
  KLiteral,
477
+ KNativeEnum,
458
478
  KNull,
459
479
  KNumber,
460
480
  KObject,
@@ -25,6 +25,7 @@ __export(schema_exports, {
25
25
  KBoolean: () => KBoolean,
26
26
  KLazy: () => KLazy,
27
27
  KLiteral: () => KLiteral,
28
+ KNativeEnum: () => KNativeEnum,
28
29
  KNull: () => KNull,
29
30
  KNumber: () => KNumber,
30
31
  KObject: () => KObject,
@@ -798,6 +799,7 @@ var KScalar = class _KScalar extends BaseSchema {
798
799
  };
799
800
  var KUnion = class _KUnion extends BaseSchema {
800
801
  static create = (items) => new _KUnion({ items });
802
+ static enum = (values) => k.union(values.map((v) => k.literal(v)));
801
803
  serialize(value) {
802
804
  for (const option of this.def.items) {
803
805
  try {
@@ -872,6 +874,41 @@ var KLiteral = class _KLiteral extends BaseSchema {
872
874
  visit() {
873
875
  }
874
876
  };
877
+ var KNativeEnum = class _KNativeEnum extends BaseSchema {
878
+ static create = (enumObject) => new _KNativeEnum({ enum: enumObject });
879
+ serialize(value) {
880
+ return value;
881
+ }
882
+ toOpenAPI() {
883
+ const baseSchema = this.getSchemaObject();
884
+ const actualValues = Object.keys(this.def.enum).filter((key) => Number.isNaN(Number(key))).map((key) => this.def.enum[key]);
885
+ const uniqueValues = [...new Set(actualValues)];
886
+ const type = typeof uniqueValues[0] === "number" ? "number" : "string";
887
+ return {
888
+ ...baseSchema,
889
+ type,
890
+ enum: uniqueValues
891
+ };
892
+ }
893
+ parseSafe(json) {
894
+ return ParseContext.result((ctx) => {
895
+ const actualValues = Object.keys(this.def.enum).filter((key) => Number.isNaN(Number(key))).map((key) => this.def.enum[key]);
896
+ if (!actualValues.includes(json)) {
897
+ return ctx.addIssue(`Expected one of: ${actualValues.join(", ")}`, []);
898
+ }
899
+ return json;
900
+ });
901
+ }
902
+ parse(json) {
903
+ const result = this.parseSafe(json);
904
+ if (!result.success) {
905
+ throw new SchemaError(result.issues);
906
+ }
907
+ return result.result;
908
+ }
909
+ visit() {
910
+ }
911
+ };
875
912
  var KRecord = class _KRecord extends BaseSchema {
876
913
  static create = (keys, values) => new _KRecord({ keys, values });
877
914
  serialize(value) {
@@ -965,6 +1002,8 @@ var k = {
965
1002
  object: KObject.create,
966
1003
  scalar: KScalar.create,
967
1004
  literal: KLiteral.create,
1005
+ enum: KUnion.enum,
1006
+ nativeEnum: KNativeEnum.create,
968
1007
  union: KUnion.create,
969
1008
  lazy: KLazy.create,
970
1009
  /**
@@ -989,6 +1028,7 @@ var k = {
989
1028
  KBoolean,
990
1029
  KLazy,
991
1030
  KLiteral,
1031
+ KNativeEnum,
992
1032
  KNull,
993
1033
  KNumber,
994
1034
  KObject,
@@ -308,6 +308,7 @@ interface UnionDef<Input extends JSONValue, Output> extends BaseSchemaDef<Input>
308
308
  }
309
309
  declare class KUnion<Input extends JSONValue, Output> extends BaseSchema<Input, Output, UnionDef<Input, Output>> {
310
310
  static create: <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"]>;
311
+ static enum: <const T extends readonly [string, ...string[]]>(values: T) => KUnion<T[number], T[number]>;
311
312
  serialize(value: Output): Input;
312
313
  toOpenAPI(): SchemaObject | ReferenceObject;
313
314
  parseSafe(json: unknown): ParseResult<Output>;
@@ -325,6 +326,17 @@ declare class KLiteral<Value extends string | number | boolean> extends BaseSche
325
326
  parseSafe(json: unknown): ParseResult<Value>;
326
327
  visit(): void;
327
328
  }
329
+ interface NativeEnumDef<T extends Record<string, string | number>> extends BaseSchemaDef<T[keyof T]> {
330
+ enum: T;
331
+ }
332
+ declare class KNativeEnum<T extends Record<string, string | number>> extends BaseSchema<T[keyof T], T[keyof T], NativeEnumDef<T>> {
333
+ static create: <T_1 extends Record<string, string | number>>(enumObject: T_1) => KNativeEnum<T_1>;
334
+ serialize(value: T[keyof T]): T[keyof T];
335
+ toOpenAPI(): SchemaObject;
336
+ parseSafe(json: unknown): ParseResult<T[keyof T]>;
337
+ parse(json: unknown): T[keyof T];
338
+ visit(): void;
339
+ }
328
340
  interface RecordDef<KeyInput extends string, KeyOutput extends string, ValueInput extends JSONValue, ValueOutput> extends BaseSchemaDef<Record<KeyInput, ValueInput>> {
329
341
  keys: BaseSchema<KeyInput, KeyOutput, BaseSchemaDef<KeyInput>>;
330
342
  values: BaseSchema<ValueInput, ValueOutput, BaseSchemaDef<ValueInput>>;
@@ -361,6 +373,8 @@ declare const k: {
361
373
  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>;
362
374
  scalar: <ClientRepresentation extends JSONPrimitive, ServerRepresentation>(options: ScalarOptions<ClientRepresentation, ServerRepresentation>) => KScalar<ClientRepresentation, ServerRepresentation>;
363
375
  literal: <Value extends string | number | boolean>(value: Value) => KLiteral<Value>;
376
+ enum: <const T extends readonly [string, ...string[]]>(values: T) => KUnion<T[number], T[number]>;
377
+ nativeEnum: <T extends Record<string, string | number>>(enumObject: T) => KNativeEnum<T>;
364
378
  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
379
  lazy: <Input extends JSONValue, Output>(getter: () => BaseSchema<Input, Output, BaseSchemaDef<Input>>) => KLazy<Input, Output>;
366
380
  /**
@@ -374,4 +388,4 @@ declare const k: {
374
388
  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>;
375
389
  };
376
390
 
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 };
391
+ export { type AnySchemaFor, type ArrayChecks, type ArrayDef, BaseSchema, type BaseSchemaDef, type BooleanDef, type Issue, type JSONPrimitive, type JSONValue, KArray, KBoolean, KLazy, KLiteral, KNativeEnum, KNull, KNumber, KObject, KObjectFromURLSearchParams, KRecord, KRef, KScalar, KString, KUnion, type LazyDef, type LiteralDef, type NativeEnumDef, 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 };
@@ -308,6 +308,7 @@ interface UnionDef<Input extends JSONValue, Output> extends BaseSchemaDef<Input>
308
308
  }
309
309
  declare class KUnion<Input extends JSONValue, Output> extends BaseSchema<Input, Output, UnionDef<Input, Output>> {
310
310
  static create: <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"]>;
311
+ static enum: <const T extends readonly [string, ...string[]]>(values: T) => KUnion<T[number], T[number]>;
311
312
  serialize(value: Output): Input;
312
313
  toOpenAPI(): SchemaObject | ReferenceObject;
313
314
  parseSafe(json: unknown): ParseResult<Output>;
@@ -325,6 +326,17 @@ declare class KLiteral<Value extends string | number | boolean> extends BaseSche
325
326
  parseSafe(json: unknown): ParseResult<Value>;
326
327
  visit(): void;
327
328
  }
329
+ interface NativeEnumDef<T extends Record<string, string | number>> extends BaseSchemaDef<T[keyof T]> {
330
+ enum: T;
331
+ }
332
+ declare class KNativeEnum<T extends Record<string, string | number>> extends BaseSchema<T[keyof T], T[keyof T], NativeEnumDef<T>> {
333
+ static create: <T_1 extends Record<string, string | number>>(enumObject: T_1) => KNativeEnum<T_1>;
334
+ serialize(value: T[keyof T]): T[keyof T];
335
+ toOpenAPI(): SchemaObject;
336
+ parseSafe(json: unknown): ParseResult<T[keyof T]>;
337
+ parse(json: unknown): T[keyof T];
338
+ visit(): void;
339
+ }
328
340
  interface RecordDef<KeyInput extends string, KeyOutput extends string, ValueInput extends JSONValue, ValueOutput> extends BaseSchemaDef<Record<KeyInput, ValueInput>> {
329
341
  keys: BaseSchema<KeyInput, KeyOutput, BaseSchemaDef<KeyInput>>;
330
342
  values: BaseSchema<ValueInput, ValueOutput, BaseSchemaDef<ValueInput>>;
@@ -361,6 +373,8 @@ declare const k: {
361
373
  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>;
362
374
  scalar: <ClientRepresentation extends JSONPrimitive, ServerRepresentation>(options: ScalarOptions<ClientRepresentation, ServerRepresentation>) => KScalar<ClientRepresentation, ServerRepresentation>;
363
375
  literal: <Value extends string | number | boolean>(value: Value) => KLiteral<Value>;
376
+ enum: <const T extends readonly [string, ...string[]]>(values: T) => KUnion<T[number], T[number]>;
377
+ nativeEnum: <T extends Record<string, string | number>>(enumObject: T) => KNativeEnum<T>;
364
378
  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
379
  lazy: <Input extends JSONValue, Output>(getter: () => BaseSchema<Input, Output, BaseSchemaDef<Input>>) => KLazy<Input, Output>;
366
380
  /**
@@ -374,4 +388,4 @@ declare const k: {
374
388
  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>;
375
389
  };
376
390
 
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 };
391
+ export { type AnySchemaFor, type ArrayChecks, type ArrayDef, BaseSchema, type BaseSchemaDef, type BooleanDef, type Issue, type JSONPrimitive, type JSONValue, KArray, KBoolean, KLazy, KLiteral, KNativeEnum, KNull, KNumber, KObject, KObjectFromURLSearchParams, KRecord, KRef, KScalar, KString, KUnion, type LazyDef, type LiteralDef, type NativeEnumDef, 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 };
@@ -4,6 +4,7 @@ import {
4
4
  KBoolean,
5
5
  KLazy,
6
6
  KLiteral,
7
+ KNativeEnum,
7
8
  KNull,
8
9
  KNumber,
9
10
  KObject,
@@ -18,13 +19,14 @@ import {
18
19
  SchemaError,
19
20
  isPrimitiveJSONValue,
20
21
  k
21
- } from "../chunk-BJVNFSCY.js";
22
+ } from "../chunk-DRJX3OJG.js";
22
23
  export {
23
24
  BaseSchema,
24
25
  KArray,
25
26
  KBoolean,
26
27
  KLazy,
27
28
  KLiteral,
29
+ KNativeEnum,
28
30
  KNull,
29
31
  KNumber,
30
32
  KObject,
@@ -27,19 +27,10 @@ __export(stream_exports, {
27
27
  sseFromAnyReadable: () => sseFromAnyReadable
28
28
  });
29
29
  module.exports = __toCommonJS(stream_exports);
30
- var KaitoSSEResponse = class extends Response {
31
- constructor(body, init) {
32
- const headers = new Headers(init?.headers);
33
- headers.set("Content-Type", "text/event-stream");
34
- headers.set("Cache-Control", "no-cache");
35
- headers.set("Connection", "keep-alive");
36
- super(body, {
37
- ...init,
38
- headers
39
- });
40
- }
41
- get [Symbol.toStringTag]() {
42
- return "KaitoSSEResponse";
30
+ var KaitoSSEResponse = class {
31
+ events;
32
+ constructor(events) {
33
+ this.events = events;
43
34
  }
44
35
  };
45
36
  function sseEventToString(event) {
@@ -64,7 +55,7 @@ var SSEController = class {
64
55
  this.controller = controller;
65
56
  }
66
57
  enqueue(event) {
67
- this.controller.enqueue(sseEventToString(event) + "\n\n");
58
+ this.controller.enqueue(event);
68
59
  }
69
60
  close() {
70
61
  this.controller.close();
@@ -1,9 +1,9 @@
1
1
  import { JSONValue } from '../schema/schema.cjs';
2
2
  import 'openapi3-ts/oas31';
3
3
 
4
- declare class KaitoSSEResponse<_T> extends Response {
5
- constructor(body: ReadableStream<string>, init?: ResponseInit);
6
- get [Symbol.toStringTag](): string;
4
+ declare class KaitoSSEResponse<T> {
5
+ readonly events: ReadableStream<T>;
6
+ constructor(events: ReadableStream<T>);
7
7
  }
8
8
  type SSEEvent<T, E extends string> = ({
9
9
  data: T;
@@ -21,19 +21,19 @@ type SSEEvent<T, E extends string> = ({
21
21
  * @returns A stringified version
22
22
  */
23
23
  declare function sseEventToString(event: SSEEvent<JSONValue, string>): string;
24
- declare class SSEController<U extends JSONValue, E extends string, T extends SSEEvent<U, E>> implements Disposable {
24
+ declare class SSEController<U, E extends string, T extends SSEEvent<U, E>> implements Disposable {
25
25
  private readonly controller;
26
- constructor(controller: ReadableStreamDefaultController<string>);
26
+ constructor(controller: ReadableStreamDefaultController<T>);
27
27
  enqueue(event: T): void;
28
28
  close(): void;
29
29
  [Symbol.dispose](): void;
30
30
  }
31
- interface SSESource<U extends JSONValue, E extends string, T extends SSEEvent<U, E>> {
31
+ interface SSESource<U, E extends string, T extends SSEEvent<U, E>> {
32
32
  cancel?: UnderlyingSourceCancelCallback;
33
33
  start?(controller: SSEController<U, E, T>): Promise<void>;
34
34
  pull?(controller: SSEController<U, E, T>): Promise<void>;
35
35
  }
36
- declare function sse<U extends JSONValue, E extends string, T extends SSEEvent<U, E>>(source: SSESource<U, E, T> | AsyncGenerator<T, unknown, unknown> | (() => AsyncGenerator<T, unknown, unknown>)): KaitoSSEResponse<T>;
37
- declare function sseFromAnyReadable<R, U extends JSONValue, E extends string>(stream: ReadableStream<R>, transform: (chunk: R) => SSEEvent<U, E>): KaitoSSEResponse<SSEEvent<U, E>>;
36
+ declare function sse<U, E extends string, T extends SSEEvent<U, E>>(source: SSESource<U, E, T> | AsyncGenerator<T, unknown, unknown> | (() => AsyncGenerator<T, unknown, unknown>)): KaitoSSEResponse<T>;
37
+ declare function sseFromAnyReadable<R, U, E extends string>(stream: ReadableStream<R>, transform: (chunk: R) => SSEEvent<U, E>): KaitoSSEResponse<SSEEvent<U, E>>;
38
38
 
39
39
  export { KaitoSSEResponse, SSEController, type SSEEvent, type SSESource, sse, sseEventToString, sseFromAnyReadable };
@@ -1,9 +1,9 @@
1
1
  import { JSONValue } from '../schema/schema.js';
2
2
  import 'openapi3-ts/oas31';
3
3
 
4
- declare class KaitoSSEResponse<_T> extends Response {
5
- constructor(body: ReadableStream<string>, init?: ResponseInit);
6
- get [Symbol.toStringTag](): string;
4
+ declare class KaitoSSEResponse<T> {
5
+ readonly events: ReadableStream<T>;
6
+ constructor(events: ReadableStream<T>);
7
7
  }
8
8
  type SSEEvent<T, E extends string> = ({
9
9
  data: T;
@@ -21,19 +21,19 @@ type SSEEvent<T, E extends string> = ({
21
21
  * @returns A stringified version
22
22
  */
23
23
  declare function sseEventToString(event: SSEEvent<JSONValue, string>): string;
24
- declare class SSEController<U extends JSONValue, E extends string, T extends SSEEvent<U, E>> implements Disposable {
24
+ declare class SSEController<U, E extends string, T extends SSEEvent<U, E>> implements Disposable {
25
25
  private readonly controller;
26
- constructor(controller: ReadableStreamDefaultController<string>);
26
+ constructor(controller: ReadableStreamDefaultController<T>);
27
27
  enqueue(event: T): void;
28
28
  close(): void;
29
29
  [Symbol.dispose](): void;
30
30
  }
31
- interface SSESource<U extends JSONValue, E extends string, T extends SSEEvent<U, E>> {
31
+ interface SSESource<U, E extends string, T extends SSEEvent<U, E>> {
32
32
  cancel?: UnderlyingSourceCancelCallback;
33
33
  start?(controller: SSEController<U, E, T>): Promise<void>;
34
34
  pull?(controller: SSEController<U, E, T>): Promise<void>;
35
35
  }
36
- declare function sse<U extends JSONValue, E extends string, T extends SSEEvent<U, E>>(source: SSESource<U, E, T> | AsyncGenerator<T, unknown, unknown> | (() => AsyncGenerator<T, unknown, unknown>)): KaitoSSEResponse<T>;
37
- declare function sseFromAnyReadable<R, U extends JSONValue, E extends string>(stream: ReadableStream<R>, transform: (chunk: R) => SSEEvent<U, E>): KaitoSSEResponse<SSEEvent<U, E>>;
36
+ declare function sse<U, E extends string, T extends SSEEvent<U, E>>(source: SSESource<U, E, T> | AsyncGenerator<T, unknown, unknown> | (() => AsyncGenerator<T, unknown, unknown>)): KaitoSSEResponse<T>;
37
+ declare function sseFromAnyReadable<R, U, E extends string>(stream: ReadableStream<R>, transform: (chunk: R) => SSEEvent<U, E>): KaitoSSEResponse<SSEEvent<U, E>>;
38
38
 
39
39
  export { KaitoSSEResponse, SSEController, type SSEEvent, type SSESource, sse, sseEventToString, sseFromAnyReadable };
@@ -1,96 +1,10 @@
1
- // src/stream/stream.ts
2
- var KaitoSSEResponse = class extends Response {
3
- constructor(body, init) {
4
- const headers = new Headers(init?.headers);
5
- headers.set("Content-Type", "text/event-stream");
6
- headers.set("Cache-Control", "no-cache");
7
- headers.set("Connection", "keep-alive");
8
- super(body, {
9
- ...init,
10
- headers
11
- });
12
- }
13
- get [Symbol.toStringTag]() {
14
- return "KaitoSSEResponse";
15
- }
16
- };
17
- function sseEventToString(event) {
18
- const lines = [];
19
- if (event.event) {
20
- lines.push(`event:${event.event}`);
21
- }
22
- if (event.id) {
23
- lines.push(`id:${event.id}`);
24
- }
25
- if (event.retry) {
26
- lines.push(`retry:${event.retry}`);
27
- }
28
- if (event.data !== void 0) {
29
- lines.push(`data:${JSON.stringify(event.data)}`);
30
- }
31
- return lines.join("\n");
32
- }
33
- var SSEController = class {
34
- controller;
35
- constructor(controller) {
36
- this.controller = controller;
37
- }
38
- enqueue(event) {
39
- this.controller.enqueue(sseEventToString(event) + "\n\n");
40
- }
41
- close() {
42
- this.controller.close();
43
- }
44
- [Symbol.dispose]() {
45
- this.close();
46
- }
47
- };
48
- function sseFromSource(source) {
49
- const start = source.start;
50
- const pull = source.pull;
51
- const cancel = source.cancel;
52
- const readable = new ReadableStream({
53
- ...cancel ? { cancel } : {},
54
- ...start ? {
55
- start: async (controller) => {
56
- await start(new SSEController(controller));
57
- }
58
- } : {},
59
- ...pull ? {
60
- pull: async (controller) => {
61
- await pull(new SSEController(controller));
62
- }
63
- } : {}
64
- });
65
- return new KaitoSSEResponse(readable);
66
- }
67
- function sse(source) {
68
- const evaluated = typeof source === "function" ? source() : source;
69
- if ("next" in evaluated) {
70
- const generator = evaluated;
71
- return sseFromSource({
72
- async start(controller) {
73
- try {
74
- for await (const event of generator) {
75
- controller.enqueue(event);
76
- }
77
- } finally {
78
- controller.close();
79
- }
80
- }
81
- });
82
- } else {
83
- return sseFromSource(evaluated);
84
- }
85
- }
86
- function sseFromAnyReadable(stream, transform) {
87
- const transformer = new TransformStream({
88
- transform: (chunk, controller) => {
89
- controller.enqueue(transform(chunk));
90
- }
91
- });
92
- return sse(stream.pipeThrough(transformer));
93
- }
1
+ import {
2
+ KaitoSSEResponse,
3
+ SSEController,
4
+ sse,
5
+ sseEventToString,
6
+ sseFromAnyReadable
7
+ } from "../chunk-HJ5HIYGW.js";
94
8
  export {
95
9
  KaitoSSEResponse,
96
10
  SSEController,
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.29",
4
+ "version": "4.0.0-beta.30",
5
5
  "author": "Alistair Smith <hi@alistair.sh>",
6
6
  "repository": "https://github.com/kaito-http/kaito",
7
7
  "dependencies": {