@kaito-http/core 2.5.0 → 2.7.0

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.
@@ -4,9 +4,12 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var node_tls = require('node:tls');
6
6
  var contentType = require('content-type');
7
+ var node_stream = require('node:stream');
8
+ var consumers = require('node:stream/consumers');
7
9
  var getRawBody = require('raw-body');
8
10
  var cookie = require('cookie');
9
11
  var fmw = require('find-my-way');
12
+ var zod = require('zod');
10
13
  var http = require('node:http');
11
14
 
12
15
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
@@ -38,26 +41,21 @@ class WrappedError extends Error {
38
41
  if (maybeError instanceof Error) {
39
42
  return maybeError;
40
43
  }
41
-
42
44
  return WrappedError.from(maybeError);
43
45
  }
44
-
45
46
  static from(data) {
46
47
  return new WrappedError(data);
47
48
  }
48
-
49
49
  constructor(data) {
50
50
  super('Something was thrown, but it was not an instance of Error, so a WrappedError was created.');
51
51
  this.data = data;
52
52
  }
53
-
54
53
  }
55
54
  class KaitoError extends Error {
56
55
  constructor(status, message) {
57
56
  super(message);
58
57
  this.status = status;
59
58
  }
60
-
61
59
  }
62
60
 
63
61
  function _defineProperty(obj, key, value) {
@@ -71,7 +69,6 @@ function _defineProperty(obj, key, value) {
71
69
  } else {
72
70
  obj[key] = value;
73
71
  }
74
-
75
72
  return obj;
76
73
  }
77
74
 
@@ -83,29 +80,24 @@ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
83
80
  reject(error);
84
81
  return;
85
82
  }
86
-
87
83
  if (info.done) {
88
84
  resolve(value);
89
85
  } else {
90
86
  Promise.resolve(value).then(_next, _throw);
91
87
  }
92
88
  }
93
-
94
89
  function _asyncToGenerator(fn) {
95
90
  return function () {
96
91
  var self = this,
97
- args = arguments;
92
+ args = arguments;
98
93
  return new Promise(function (resolve, reject) {
99
94
  var gen = fn.apply(self, args);
100
-
101
95
  function _next(value) {
102
96
  asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
103
97
  }
104
-
105
98
  function _throw(err) {
106
99
  asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
107
100
  }
108
-
109
101
  _next(undefined);
110
102
  });
111
103
  };
@@ -119,154 +111,124 @@ function getLastEntryInMultiHeaderValue(headerValue) {
119
111
  var lastIndex = normalized.lastIndexOf(',');
120
112
  return lastIndex === -1 ? normalized.trim() : normalized.slice(lastIndex + 1).trim();
121
113
  }
122
- function getInput(_x) {
123
- return _getInput.apply(this, arguments);
114
+ function getBody(_x) {
115
+ return _getBody.apply(this, arguments);
124
116
  }
125
-
126
- function _getInput() {
127
- _getInput = _asyncToGenerator(function* (req) {
128
- if (req.method === 'GET') {
129
- var input = req.url.searchParams.get('input');
130
-
131
- if (!input) {
132
- return null;
133
- }
134
-
135
- return JSON.parse(input);
136
- }
137
-
138
- var buffer = yield getRawBody__default["default"](req.raw);
139
-
117
+ function _getBody() {
118
+ _getBody = _asyncToGenerator(function* (req) {
140
119
  if (!req.headers['content-type']) {
141
120
  return null;
142
121
  }
143
-
122
+ var buffer = yield getRawBody__default["default"](req.raw);
144
123
  var {
145
124
  type
146
125
  } = contentType.parse(req.headers['content-type']);
147
-
148
126
  switch (type) {
149
127
  case 'application/json':
150
128
  {
151
- return JSON.parse(buffer.toString());
129
+ return consumers.json(node_stream.Readable.from(buffer));
152
130
  }
153
-
154
131
  default:
155
132
  {
156
133
  if (process.env.NODE_ENV === 'development') {
157
134
  console.warn('[kaito] Unsupported content type:', type);
158
135
  console.warn('[kaito] This message is only shown in development mode.');
159
136
  }
160
-
161
137
  return null;
162
138
  }
163
139
  }
164
140
  });
165
- return _getInput.apply(this, arguments);
141
+ return _getBody.apply(this, arguments);
166
142
  }
167
143
 
168
144
  class KaitoRequest {
169
145
  constructor(raw) {
170
146
  _defineProperty(this, "_url", null);
171
-
172
147
  this.raw = raw;
173
148
  }
149
+
174
150
  /**
175
151
  * The full URL of the request, including the protocol, hostname, and path.
176
152
  * Note: does not include the query string or hash
177
153
  */
178
-
179
-
180
154
  get fullURL() {
181
155
  var _this$raw$url;
182
-
183
156
  return "".concat(this.protocol, "://").concat(this.hostname).concat((_this$raw$url = this.raw.url) !== null && _this$raw$url !== void 0 ? _this$raw$url : '');
184
157
  }
158
+
185
159
  /**
186
160
  * A new URL instance for the full URL of the request.
187
161
  */
188
-
189
-
190
162
  get url() {
191
163
  if (this._url) {
192
164
  return this._url;
193
165
  }
194
-
195
166
  this._url = new URL(this.fullURL);
196
167
  return this._url;
197
168
  }
169
+
198
170
  /**
199
171
  * The HTTP method of the request.
200
172
  */
201
-
202
-
203
173
  get method() {
204
174
  if (!this.raw.method) {
205
175
  throw new Error('Request method is not defined, somehow...');
206
176
  }
207
-
208
177
  return this.raw.method;
209
178
  }
179
+
210
180
  /**
211
181
  * The protocol of the request, either `http` or `https`.
212
182
  */
213
-
214
-
215
183
  get protocol() {
216
184
  if (this.raw.socket instanceof node_tls.TLSSocket) {
217
185
  return this.raw.socket.encrypted ? 'https' : 'http';
218
186
  }
219
-
220
187
  return 'http';
221
188
  }
189
+
222
190
  /**
223
191
  * The request headers
224
192
  */
225
-
226
-
227
193
  get headers() {
228
194
  return this.raw.headers;
229
195
  }
196
+
230
197
  /**
231
198
  * The hostname of the request.
232
199
  */
233
-
234
-
235
200
  get hostname() {
236
201
  var _this$raw$headers$hos, _this$raw$headers$Au;
237
-
238
202
  return (_this$raw$headers$hos = this.raw.headers.host) !== null && _this$raw$headers$hos !== void 0 ? _this$raw$headers$hos : getLastEntryInMultiHeaderValue((_this$raw$headers$Au = this.raw.headers[':authority']) !== null && _this$raw$headers$Au !== void 0 ? _this$raw$headers$Au : []);
239
203
  }
240
-
241
204
  }
242
205
 
243
206
  class KaitoResponse {
244
207
  constructor(raw) {
245
208
  this.raw = raw;
246
209
  }
210
+
247
211
  /**
248
212
  * Send a response
249
213
  * @param key The key of the header
250
214
  * @param value The value of the header
251
215
  * @returns The response object
252
216
  */
253
-
254
-
255
217
  header(key, value) {
256
218
  this.raw.setHeader(key, value);
257
219
  return this;
258
220
  }
221
+
259
222
  /**
260
223
  * Set the status code of the response
261
224
  * @param code The status code
262
225
  * @returns The response object
263
226
  */
264
-
265
-
266
227
  status(code) {
267
228
  this.raw.statusCode = code;
268
229
  return this;
269
230
  }
231
+
270
232
  /**
271
233
  * Set a cookie
272
234
  * @param name The name of the cookie
@@ -274,19 +236,16 @@ class KaitoResponse {
274
236
  * @param options The options for the cookie
275
237
  * @returns The response object
276
238
  */
277
-
278
-
279
239
  cookie(name, value, options) {
280
240
  this.raw.setHeader('Set-Cookie', cookie.serialize(name, value, options));
281
241
  return this;
282
242
  }
243
+
283
244
  /**
284
245
  * Send a JSON APIResponse body
285
246
  * @param data The data to send
286
247
  * @returns The response object
287
248
  */
288
-
289
-
290
249
  json(data) {
291
250
  var json = JSON.stringify(data);
292
251
  this.raw.setHeader('Content-Type', 'application/json');
@@ -294,66 +253,112 @@ class KaitoResponse {
294
253
  this.raw.end(json);
295
254
  return this;
296
255
  }
297
-
298
256
  }
299
257
 
300
258
  function ownKeys(object, enumerableOnly) {
301
259
  var keys = Object.keys(object);
302
-
303
260
  if (Object.getOwnPropertySymbols) {
304
261
  var symbols = Object.getOwnPropertySymbols(object);
305
-
306
- if (enumerableOnly) {
307
- symbols = symbols.filter(function (sym) {
308
- return Object.getOwnPropertyDescriptor(object, sym).enumerable;
309
- });
310
- }
311
-
312
- keys.push.apply(keys, symbols);
262
+ enumerableOnly && (symbols = symbols.filter(function (sym) {
263
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
264
+ })), keys.push.apply(keys, symbols);
313
265
  }
314
-
315
266
  return keys;
316
267
  }
317
-
318
268
  function _objectSpread2(target) {
319
269
  for (var i = 1; i < arguments.length; i++) {
320
- var source = arguments[i] != null ? arguments[i] : {};
321
-
322
- if (i % 2) {
323
- ownKeys(Object(source), true).forEach(function (key) {
324
- _defineProperty(target, key, source[key]);
325
- });
326
- } else if (Object.getOwnPropertyDescriptors) {
327
- Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
328
- } else {
329
- ownKeys(Object(source)).forEach(function (key) {
330
- Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
331
- });
332
- }
270
+ var source = null != arguments[i] ? arguments[i] : {};
271
+ i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
272
+ _defineProperty(target, key, source[key]);
273
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
274
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
275
+ });
333
276
  }
334
-
335
277
  return target;
336
278
  }
337
279
 
338
280
  class Router {
281
+ static handle(server, route, options) {
282
+ return _asyncToGenerator(function* () {
283
+ try {
284
+ var _yield$route$body$par, _route$body;
285
+ var ctx = yield server.getContext(options.req, options.res);
286
+ var body = (_yield$route$body$par = yield (_route$body = route.body) === null || _route$body === void 0 ? void 0 : _route$body.parse(yield getBody(options.req))) !== null && _yield$route$body$par !== void 0 ? _yield$route$body$par : undefined;
287
+ var query = route.query ? zod.z.object(route.query).parse(Object.fromEntries(options.req.url.searchParams.entries())) : {};
288
+ var result = yield route.run({
289
+ ctx,
290
+ body,
291
+ query,
292
+ params: options.params
293
+ });
294
+ options.res.status(200).json({
295
+ success: true,
296
+ data: result,
297
+ message: 'OK'
298
+ });
299
+ return {
300
+ success: true,
301
+ data: result
302
+ };
303
+ } catch (e) {
304
+ var error = WrappedError.maybe(e);
305
+ if (error instanceof KaitoError) {
306
+ options.res.status(error.status).json({
307
+ success: false,
308
+ data: null,
309
+ message: error.message
310
+ });
311
+ return;
312
+ }
313
+ var {
314
+ status,
315
+ message
316
+ } = yield server.onError({
317
+ error,
318
+ req: options.req,
319
+ res: options.res
320
+ }).catch(() => ({
321
+ status: 500,
322
+ message: 'Internal Server Error'
323
+ }));
324
+ options.res.status(status).json({
325
+ success: false,
326
+ data: null,
327
+ message
328
+ });
329
+ return {
330
+ success: false,
331
+ data: {
332
+ status,
333
+ message
334
+ }
335
+ };
336
+ }
337
+ })();
338
+ }
339
339
  constructor(routes) {
340
- _defineProperty(this, "add", route => new Router([...this.routes, route]));
341
-
340
+ _defineProperty(this, "old_add", route => new Router([...this.routes, route]));
341
+ _defineProperty(this, "add", (method, path, route) => {
342
+ var merged = _objectSpread2(_objectSpread2({}, typeof route === 'object' ? route : {
343
+ run: route
344
+ }), {}, {
345
+ method,
346
+ path
347
+ });
348
+ return new Router([...this.routes, merged]);
349
+ });
342
350
  _defineProperty(this, "merge", (pathPrefix, other) => {
343
351
  var newRoutes = other.routes.map(route => _objectSpread2(_objectSpread2({}, route), {}, {
344
352
  path: "".concat(pathPrefix).concat(route.path)
345
353
  }));
346
354
  return new Router([...this.routes, ...newRoutes]);
347
355
  });
348
-
349
356
  _defineProperty(this, "toFindMyWay", server => {
350
357
  var instance = fmw__default["default"]({
351
358
  ignoreTrailingSlash: true,
352
-
353
359
  defaultRoute(req, serverResponse) {
354
360
  return _asyncToGenerator(function* () {
355
361
  var _req$url;
356
-
357
362
  var res = new KaitoResponse(serverResponse);
358
363
  var message = "Cannot ".concat(req.method, " ").concat((_req$url = req.url) !== null && _req$url !== void 0 ? _req$url : '/');
359
364
  res.status(404).json({
@@ -370,9 +375,7 @@ class Router {
370
375
  };
371
376
  })();
372
377
  }
373
-
374
378
  });
375
-
376
379
  var _loop = function _loop(route) {
377
380
  var handler = /*#__PURE__*/function () {
378
381
  var _ref = _asyncToGenerator(function* (incomingMessage, serverResponse, params) {
@@ -384,146 +387,72 @@ class Router {
384
387
  res
385
388
  });
386
389
  });
387
-
388
390
  return function handler(_x, _x2, _x3) {
389
391
  return _ref.apply(this, arguments);
390
392
  };
391
393
  }();
392
-
393
394
  if (route.method === '*') {
394
395
  instance.all(route.path, handler);
395
396
  return "continue";
396
397
  }
397
-
398
398
  instance.on(route.method, route.path, handler);
399
399
  };
400
-
401
400
  for (var route of this.routes) {
402
401
  var _ret = _loop(route);
403
-
404
402
  if (_ret === "continue") continue;
405
403
  }
406
-
407
404
  return instance;
408
405
  });
409
-
410
406
  this.routes = routes;
411
407
  }
412
408
 
413
- static handle(server, route, options) {
414
- return _asyncToGenerator(function* () {
415
- try {
416
- var _route$input$parse, _route$input;
417
-
418
- var ctx = yield server.getContext(options.req, options.res);
419
- var body = yield getInput(options.req);
420
- var input = (_route$input$parse = (_route$input = route.input) === null || _route$input === void 0 ? void 0 : _route$input.parse(body)) !== null && _route$input$parse !== void 0 ? _route$input$parse : undefined;
421
- var result = yield route.run({
422
- ctx,
423
- input,
424
- params: options.params
425
- });
426
- options.res.status(200).json({
427
- success: true,
428
- data: result,
429
- message: 'OK'
430
- });
431
- return {
432
- success: true,
433
- data: result
434
- };
435
- } catch (e) {
436
- var error = WrappedError.maybe(e);
437
-
438
- if (error instanceof KaitoError) {
439
- options.res.status(error.status).json({
440
- success: false,
441
- data: null,
442
- message: error.message
443
- });
444
- return;
445
- }
446
-
447
- var {
448
- status,
449
- message
450
- } = yield server.onError({
451
- error,
452
- req: options.req,
453
- res: options.res
454
- }).catch(() => ({
455
- status: 500,
456
- message: 'Internal Server Error'
457
- }));
458
- options.res.status(status).json({
459
- success: false,
460
- data: null,
461
- message
462
- });
463
- return {
464
- success: false,
465
- data: {
466
- status,
467
- message
468
- }
469
- };
470
- }
471
- })();
472
- }
473
-
409
+ /**
410
+ * Adds a new route to the router
411
+ * @param route The route specification to add to this router
412
+ * @returns A new router with this route added
413
+ * @deprecated Use `Router#add` instead
414
+ */
474
415
  }
475
-
476
416
  _defineProperty(Router, "create", () => new Router([]));
477
417
 
478
418
  function createFMWServer(config) {
479
419
  var _config$rawRoutes;
480
-
481
420
  var fmw = config.router.toFindMyWay(config);
482
421
  var rawRoutes = (_config$rawRoutes = config.rawRoutes) !== null && _config$rawRoutes !== void 0 ? _config$rawRoutes : {};
483
-
484
422
  for (var method in rawRoutes) {
485
423
  if (!Object.prototype.hasOwnProperty.call(rawRoutes, method)) {
486
424
  continue;
487
425
  }
488
-
489
426
  var routes = rawRoutes[method];
490
-
491
427
  if (!routes || routes.length === 0) {
492
428
  continue;
493
429
  }
494
-
495
430
  for (var route of routes) {
496
431
  if (method === '*') {
497
432
  fmw.all(route.path, route.handler);
498
433
  continue;
499
434
  }
500
-
501
435
  fmw[method.toLowerCase()](route.path, route.handler);
502
436
  }
503
437
  }
504
-
505
438
  var server = http__namespace.createServer( /*#__PURE__*/function () {
506
439
  var _ref = _asyncToGenerator(function* (req, res) {
507
440
  var before;
508
-
509
441
  if (config.before) {
510
442
  before = yield config.before(req, res);
511
443
  } else {
512
- before = null;
513
- } // If the user has sent a response (e.g. replying to CORS), we don't want to do anything else.
514
-
444
+ before = undefined;
445
+ }
515
446
 
447
+ // If the user has sent a response (e.g. replying to CORS), we don't want to do anything else.
516
448
  if (res.headersSent) {
517
449
  return;
518
450
  }
519
-
520
451
  var result = yield fmw.lookup(req, res);
521
-
522
452
  if ('after' in config && config.after) {
523
453
  yield config.after(before, result);
524
454
  }
525
455
  });
526
-
527
456
  return function (_x, _x2) {
528
457
  return _ref.apply(this, arguments);
529
458
  };
@@ -545,5 +474,5 @@ exports.WrappedError = WrappedError;
545
474
  exports.createFMWServer = createFMWServer;
546
475
  exports.createGetContext = createGetContext;
547
476
  exports.createServer = createServer;
548
- exports.getInput = getInput;
477
+ exports.getBody = getBody;
549
478
  exports.getLastEntryInMultiHeaderValue = getLastEntryInMultiHeaderValue;