@kaito-http/core 2.9.5 → 3.0.0-beta.3

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