@kaito-http/core 3.0.0-beta.1 → 3.0.0-beta.10

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