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