@kaito-http/core 2.0.2 → 2.1.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.
@@ -0,0 +1,5 @@
1
+ export declare class WrappedError<T> extends Error {
2
+ readonly data: T;
3
+ static from<T>(maybeError: T): (T & Error) | WrappedError<T>;
4
+ constructor(data: T);
5
+ }
@@ -0,0 +1,13 @@
1
+ /// <reference types="node" />
2
+ import { IncomingMessage } from 'http';
3
+ import { Method } from './util';
4
+ export declare class KaitoRequest {
5
+ readonly raw: IncomingMessage;
6
+ constructor(raw: IncomingMessage);
7
+ get fullURL(): string;
8
+ get url(): URL;
9
+ get method(): Method;
10
+ get protocol(): 'http' | 'https';
11
+ get headers(): import("http").IncomingHttpHeaders;
12
+ get hostname(): string;
13
+ }
@@ -0,0 +1,21 @@
1
+ /// <reference types="node" />
2
+ import { ServerResponse } from 'http';
3
+ export declare type ErroredAPIResponse = {
4
+ success: false;
5
+ data: null;
6
+ message: string;
7
+ };
8
+ export declare type SuccessfulAPIResponse<T> = {
9
+ success: true;
10
+ data: T;
11
+ message: 'OK';
12
+ };
13
+ export declare type APIResponse<T> = ErroredAPIResponse | SuccessfulAPIResponse<T>;
14
+ export declare type AnyResponse = APIResponse<unknown>;
15
+ export declare class KaitoResponse<T = unknown> {
16
+ readonly raw: ServerResponse;
17
+ constructor(raw: ServerResponse);
18
+ header(key: string, value: string | readonly string[]): this;
19
+ status(code: number): this;
20
+ json(data: APIResponse<T>): this;
21
+ }
@@ -1,13 +1,10 @@
1
1
  /// <reference types="node" />
2
- import { FastifyReply, FastifyRequest } from 'fastify';
2
+ import http from 'http';
3
3
  import { z, ZodTypeAny } from 'zod';
4
- export declare enum Method {
5
- GET = "GET",
6
- POST = "POST",
7
- PATCH = "PATCH",
8
- DELETE = "DELETE"
9
- }
10
- export declare type GetContext<T> = (req: FastifyRequest, res: FastifyReply) => Promise<T>;
4
+ import { KaitoRequest } from './req';
5
+ import { KaitoResponse } from './res';
6
+ import { Method } from './util';
7
+ export declare type GetContext<T> = (req: KaitoRequest, res: KaitoResponse) => Promise<T>;
11
8
  declare type Never = [never];
12
9
  export declare function createGetContext<T>(getContext: GetContext<T>): GetContext<T>;
13
10
  export declare type InferContext<T> = T extends GetContext<infer Value> ? Value : never;
@@ -42,7 +39,7 @@ export declare class Router<Ctx, Procs extends ProcsInit<Ctx>> {
42
39
  input?: Input | undefined;
43
40
  run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
44
41
  }> & {
45
- method: Method.GET;
42
+ method: "GET";
46
43
  name: Name;
47
44
  }>>;
48
45
  readonly post: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
@@ -52,7 +49,17 @@ export declare class Router<Ctx, Procs extends ProcsInit<Ctx>> {
52
49
  input?: Input | undefined;
53
50
  run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
54
51
  }> & {
55
- method: Method.POST;
52
+ method: "POST";
53
+ name: Name;
54
+ }>>;
55
+ readonly put: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
56
+ input?: Input | undefined;
57
+ run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
58
+ }>) => Router<Ctx, Procs & Record<Name, Readonly<{
59
+ input?: Input | undefined;
60
+ run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
61
+ }> & {
62
+ method: "PUT";
56
63
  name: Name;
57
64
  }>>;
58
65
  readonly patch: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
@@ -62,7 +69,7 @@ export declare class Router<Ctx, Procs extends ProcsInit<Ctx>> {
62
69
  input?: Input | undefined;
63
70
  run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
64
71
  }> & {
65
- method: Method.PATCH;
72
+ method: "PATCH";
66
73
  name: Name;
67
74
  }>>;
68
75
  readonly delete: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
@@ -72,17 +79,77 @@ export declare class Router<Ctx, Procs extends ProcsInit<Ctx>> {
72
79
  input?: Input | undefined;
73
80
  run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
74
81
  }> & {
75
- method: Method.DELETE;
82
+ method: "DELETE";
83
+ name: Name;
84
+ }>>;
85
+ readonly head: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
86
+ input?: Input | undefined;
87
+ run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
88
+ }>) => Router<Ctx, Procs & Record<Name, Readonly<{
89
+ input?: Input | undefined;
90
+ run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
91
+ }> & {
92
+ method: "HEAD";
93
+ name: Name;
94
+ }>>;
95
+ readonly options: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
96
+ input?: Input | undefined;
97
+ run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
98
+ }>) => Router<Ctx, Procs & Record<Name, Readonly<{
99
+ input?: Input | undefined;
100
+ run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
101
+ }> & {
102
+ method: "OPTIONS";
103
+ name: Name;
104
+ }>>;
105
+ readonly connect: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
106
+ input?: Input | undefined;
107
+ run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
108
+ }>) => Router<Ctx, Procs & Record<Name, Readonly<{
109
+ input?: Input | undefined;
110
+ run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
111
+ }> & {
112
+ method: "CONNECT";
113
+ name: Name;
114
+ }>>;
115
+ readonly trace: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
116
+ input?: Input | undefined;
117
+ run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
118
+ }>) => Router<Ctx, Procs & Record<Name, Readonly<{
119
+ input?: Input | undefined;
120
+ run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
121
+ }> & {
122
+ method: "TRACE";
123
+ name: Name;
124
+ }>>;
125
+ readonly acl: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
126
+ input?: Input | undefined;
127
+ run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
128
+ }>) => Router<Ctx, Procs & Record<Name, Readonly<{
129
+ input?: Input | undefined;
130
+ run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
131
+ }> & {
132
+ method: "ACL";
133
+ name: Name;
134
+ }>>;
135
+ readonly bind: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
136
+ input?: Input | undefined;
137
+ run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
138
+ }>) => Router<Ctx, Procs & Record<Name, Readonly<{
139
+ input?: Input | undefined;
140
+ run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
141
+ }> & {
142
+ method: "BIND";
76
143
  name: Name;
77
144
  }>>;
78
145
  }
79
146
  export declare class KaitoError extends Error {
80
- readonly code: number;
147
+ readonly status: number;
81
148
  readonly cause?: Error | undefined;
82
- constructor(code: number, message: string, cause?: Error | undefined);
149
+ constructor(status: number, message: string, cause?: Error | undefined);
83
150
  }
84
151
  export declare function createRouter<Ctx>(): Router<Ctx, {}>;
85
- export declare type InferApiResponseType<R extends AnyRouter<unknown>, M extends Method, Path extends Extract<Values<ReturnType<R['getProcs']>>, {
152
+ export declare type InferAPIResponseType<R extends AnyRouter<unknown>, M extends Method, Path extends Extract<Values<ReturnType<R['getProcs']>>, {
86
153
  method: M;
87
154
  }>['name']> = ReturnType<ReturnType<R['getProcs']>[Path]['run']> extends Promise<infer V> ? V : never;
88
155
  export declare function createServer<Ctx, R extends Router<Ctx, ProcsInit<Ctx>>>(config: {
@@ -90,12 +157,12 @@ export declare function createServer<Ctx, R extends Router<Ctx, ProcsInit<Ctx>>>
90
157
  router: R;
91
158
  onError(error: {
92
159
  error: Error;
93
- req: FastifyRequest;
94
- res: FastifyReply;
160
+ req: KaitoRequest;
161
+ res: KaitoResponse;
95
162
  }): Promise<{
96
- code: number;
163
+ status: number;
97
164
  message: string;
98
165
  }>;
99
166
  log?: ((message: string) => unknown) | false;
100
- }): import("fastify").FastifyInstance<import("http").Server, import("http").IncomingMessage, import("http").ServerResponse, import("fastify").FastifyLoggerInstance> & PromiseLike<import("fastify").FastifyInstance<import("http").Server, import("http").IncomingMessage, import("http").ServerResponse, import("fastify").FastifyLoggerInstance>>;
167
+ }): http.Server;
101
168
  export {};
@@ -0,0 +1,4 @@
1
+ import { KaitoRequest } from './req';
2
+ export declare function getLastEntryInMultiHeaderValue(headerValue: string | string[]): string;
3
+ export declare type Method = 'ACL' | 'BIND' | 'CHECKOUT' | 'CONNECT' | 'COPY' | 'DELETE' | 'GET' | 'HEAD' | 'LINK' | 'LOCK' | 'M-SEARCH' | 'MERGE' | 'MKACTIVITY' | 'MKCALENDAR' | 'MKCOL' | 'MOVE' | 'NOTIFY' | 'OPTIONS' | 'PATCH' | 'POST' | 'PRI' | 'PROPFIND' | 'PROPPATCH' | 'PURGE' | 'PUT' | 'REBIND' | 'REPORT' | 'SEARCH' | 'SOURCE' | 'SUBSCRIBE' | 'TRACE' | 'UNBIND' | 'UNLINK' | 'UNLOCK' | 'UNSUBSCRIBE';
4
+ export declare function getInput(req: KaitoRequest): Promise<unknown>;
@@ -2,11 +2,14 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var fastify = require('fastify');
5
+ var http = require('http');
6
+ var tls = require('tls');
7
+ var getRawBody = require('raw-body');
6
8
 
7
9
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
8
10
 
9
- var fastify__default = /*#__PURE__*/_interopDefault(fastify);
11
+ var http__default = /*#__PURE__*/_interopDefault(http);
12
+ var getRawBody__default = /*#__PURE__*/_interopDefault(getRawBody);
10
13
 
11
14
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
12
15
  try {
@@ -97,14 +100,128 @@ function _objectSpread2(target) {
97
100
  return target;
98
101
  }
99
102
 
100
- exports.Method = void 0;
103
+ class WrappedError extends Error {
104
+ static from(maybeError) {
105
+ if (maybeError instanceof Error) {
106
+ return maybeError;
107
+ }
108
+
109
+ return new WrappedError(maybeError);
110
+ }
111
+
112
+ constructor(data) {
113
+ super('Something was thrown, but it was not an instance of Error, so a WrappedError was created.');
114
+ this.data = data;
115
+ }
116
+
117
+ }
118
+
119
+ function getLastEntryInMultiHeaderValue(headerValue) {
120
+ var normalized = Array.isArray(headerValue) ? headerValue.join(',') : headerValue;
121
+ var lastIndex = normalized.lastIndexOf(',');
122
+ return lastIndex === -1 ? normalized.trim() : normalized.slice(lastIndex + 1).trim();
123
+ } // Type for import('http').METHODS
124
+
125
+ function getInput(_x) {
126
+ return _getInput.apply(this, arguments);
127
+ }
128
+
129
+ function _getInput() {
130
+ _getInput = _asyncToGenerator(function* (req) {
131
+ if (req.method === 'GET') {
132
+ var input = req.url.searchParams.get('input');
133
+
134
+ if (!input) {
135
+ return null;
136
+ }
137
+
138
+ return JSON.parse(input);
139
+ }
140
+
141
+ var buffer = yield getRawBody__default["default"](req.raw);
142
+
143
+ switch (req.headers['content-type']) {
144
+ case 'application/json':
145
+ {
146
+ return JSON.parse(buffer.toString());
147
+ }
148
+
149
+ default:
150
+ {
151
+ return null;
152
+ }
153
+ }
154
+ });
155
+ return _getInput.apply(this, arguments);
156
+ }
157
+
158
+ class KaitoRequest {
159
+ constructor(raw) {
160
+ this.raw = raw;
161
+ }
101
162
 
102
- (function (Method) {
103
- Method["GET"] = "GET";
104
- Method["POST"] = "POST";
105
- Method["PATCH"] = "PATCH";
106
- Method["DELETE"] = "DELETE";
107
- })(exports.Method || (exports.Method = {}));
163
+ get fullURL() {
164
+ var _this$raw$url;
165
+
166
+ return "".concat(this.protocol, "://").concat(this.hostname).concat((_this$raw$url = this.raw.url) !== null && _this$raw$url !== void 0 ? _this$raw$url : '');
167
+ }
168
+
169
+ get url() {
170
+ return new URL(this.fullURL);
171
+ }
172
+
173
+ get method() {
174
+ if (!this.raw.method) {
175
+ throw new Error('Request method is not defined, somehow...');
176
+ }
177
+
178
+ return this.raw.method;
179
+ }
180
+
181
+ get protocol() {
182
+ if (this.raw.socket instanceof tls.TLSSocket) {
183
+ return this.raw.socket.encrypted ? 'https' : 'http';
184
+ }
185
+
186
+ return 'http';
187
+ }
188
+
189
+ get headers() {
190
+ return this.raw.headers;
191
+ }
192
+
193
+ get hostname() {
194
+ var _this$raw$headers$hos, _this$raw$headers$Au;
195
+
196
+ 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 : []);
197
+ }
198
+
199
+ }
200
+
201
+ class KaitoResponse {
202
+ constructor(raw) {
203
+ this.raw = raw;
204
+ }
205
+
206
+ header(key, value) {
207
+ this.raw.setHeader(key, value);
208
+ return this;
209
+ }
210
+
211
+ status(code) {
212
+ this.raw.statusCode = code;
213
+ return this;
214
+ }
215
+
216
+ json(data) {
217
+ var json = JSON.stringify(data);
218
+ this.raw.setHeader('Content-Type', 'application/json');
219
+ this.raw.setHeader('Content-Length', Buffer.byteLength(json));
220
+ this.raw.end(json);
221
+ return this;
222
+ }
223
+
224
+ }
108
225
 
109
226
  function createGetContext(getContext) {
110
227
  return getContext;
@@ -135,13 +252,27 @@ class Router {
135
252
  return new Router(mergedProcs);
136
253
  });
137
254
 
138
- _defineProperty(this, "get", this.create(exports.Method.GET));
255
+ _defineProperty(this, "get", this.create('GET'));
256
+
257
+ _defineProperty(this, "post", this.create('POST'));
258
+
259
+ _defineProperty(this, "put", this.create('PUT'));
260
+
261
+ _defineProperty(this, "patch", this.create('PATCH'));
139
262
 
140
- _defineProperty(this, "post", this.create(exports.Method.POST));
263
+ _defineProperty(this, "delete", this.create('DELETE'));
141
264
 
142
- _defineProperty(this, "patch", this.create(exports.Method.PATCH));
265
+ _defineProperty(this, "head", this.create('HEAD'));
143
266
 
144
- _defineProperty(this, "delete", this.create(exports.Method.DELETE));
267
+ _defineProperty(this, "options", this.create('OPTIONS'));
268
+
269
+ _defineProperty(this, "connect", this.create('CONNECT'));
270
+
271
+ _defineProperty(this, "trace", this.create('TRACE'));
272
+
273
+ _defineProperty(this, "acl", this.create('ACL'));
274
+
275
+ _defineProperty(this, "bind", this.create('BIND'));
145
276
 
146
277
  this.procs = procs;
147
278
  }
@@ -152,9 +283,9 @@ class Router {
152
283
 
153
284
  }
154
285
  class KaitoError extends Error {
155
- constructor(code, message, cause) {
286
+ constructor(status, message, cause) {
156
287
  super(message);
157
- this.code = code;
288
+ this.status = status;
158
289
  this.cause = cause;
159
290
  }
160
291
 
@@ -163,79 +294,78 @@ function createRouter() {
163
294
  return new Router({});
164
295
  }
165
296
  function createServer(config) {
166
- var tree = config.router.getProcs();
167
- var app = fastify__default["default"]();
168
- app.setErrorHandler( /*#__PURE__*/function () {
169
- var _ref = _asyncToGenerator(function* (error, req, res) {
170
- if (error instanceof KaitoError) {
171
- yield res.status(error.code).send({
172
- success: false,
173
- data: null,
174
- message: error.message
175
- });
176
- return;
177
- }
178
-
179
- var {
180
- code,
181
- message
182
- } = yield config.onError({
183
- error,
184
- req,
185
- res
186
- }).catch(() => ({
187
- code: 500,
188
- message: 'Something went wrong'
189
- }));
190
- yield res.status(code).send({
191
- success: false,
192
- data: null,
193
- message
194
- });
195
- });
196
-
197
- return function (_x, _x2, _x3) {
198
- return _ref.apply(this, arguments);
199
- };
200
- }());
201
- app.all('*', /*#__PURE__*/function () {
202
- var _ref2 = _asyncToGenerator(function* (req, res) {
203
- var _handler$input$parse, _handler$input;
204
-
205
- var logMessage = "".concat(req.hostname, " ").concat(req.method, " ").concat(req.url);
297
+ var log = message => {
298
+ if (config.log === undefined) {
299
+ console.log(message);
300
+ } else if (config.log) {
301
+ config.log(message);
302
+ }
303
+ };
206
304
 
207
- if (config.log === undefined) {
208
- console.log(logMessage);
209
- } else if (config.log) {
210
- config.log(logMessage);
211
- }
305
+ var tree = config.router.getProcs();
306
+ var server = http__default["default"].createServer( /*#__PURE__*/function () {
307
+ var _ref = _asyncToGenerator(function* (incomingMessage, serverResponse) {
308
+ var start = Date.now();
309
+ var req = new KaitoRequest(incomingMessage);
310
+ var res = new KaitoResponse(serverResponse);
212
311
 
213
- var url = new URL("".concat(req.protocol, "://").concat(req.hostname).concat(req.url));
214
- var handler = tree[url.pathname];
312
+ try {
313
+ var _handler$input, _yield$getInput;
215
314
 
216
- if (!handler) {
217
- throw new KaitoError(404, "Cannot ".concat(req.method, " this route."));
218
- }
315
+ var handler = tree[req.url.pathname];
219
316
 
220
- var context = yield config.getContext(req, res); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
317
+ if (!handler) {
318
+ throw new KaitoError(404, "Cannot ".concat(req.method, " this route."));
319
+ }
221
320
 
222
- var input = (_handler$input$parse = (_handler$input = handler.input) === null || _handler$input === void 0 ? void 0 : _handler$input.parse(req.method === 'GET' ? req.query : req.body)) !== null && _handler$input$parse !== void 0 ? _handler$input$parse : null;
223
- yield res.send({
224
- success: true,
225
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
226
- data: yield handler.run({
321
+ var input = (_handler$input = handler.input) === null || _handler$input === void 0 ? void 0 : _handler$input.parse((_yield$getInput = yield getInput(req)) !== null && _yield$getInput !== void 0 ? _yield$getInput : undefined);
322
+ var context = yield config.getContext(req, res);
323
+ var data = yield handler.run({
227
324
  ctx: context,
228
325
  input
229
- }),
230
- message: 'OK'
231
- });
326
+ });
327
+ res.json({
328
+ success: true,
329
+ data,
330
+ message: 'OK'
331
+ });
332
+ } catch (error) {
333
+ if (error instanceof KaitoError) {
334
+ res.status(error.status).json({
335
+ success: false,
336
+ data: null,
337
+ message: error.message
338
+ });
339
+ return;
340
+ }
341
+
342
+ var {
343
+ status: _status,
344
+ message: _message
345
+ } = yield config.onError({
346
+ error: WrappedError.from(error),
347
+ req,
348
+ res
349
+ }).catch(() => ({
350
+ status: 500,
351
+ message: 'Something went wrong'
352
+ }));
353
+ res.status(_status).json({
354
+ success: false,
355
+ data: null,
356
+ message: _message
357
+ });
358
+ } finally {
359
+ var finish = Date.now();
360
+ log("".concat(req.method, " ").concat(req.fullURL, " ").concat(res.raw.statusCode, " ").concat(finish - start, "ms"));
361
+ }
232
362
  });
233
363
 
234
- return function (_x4, _x5) {
235
- return _ref2.apply(this, arguments);
364
+ return function (_x, _x2) {
365
+ return _ref.apply(this, arguments);
236
366
  };
237
367
  }());
238
- return app;
368
+ return server;
239
369
  }
240
370
 
241
371
  exports.KaitoError = KaitoError;
@@ -2,11 +2,14 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var fastify = require('fastify');
5
+ var http = require('http');
6
+ var tls = require('tls');
7
+ var getRawBody = require('raw-body');
6
8
 
7
9
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
8
10
 
9
- var fastify__default = /*#__PURE__*/_interopDefault(fastify);
11
+ var http__default = /*#__PURE__*/_interopDefault(http);
12
+ var getRawBody__default = /*#__PURE__*/_interopDefault(getRawBody);
10
13
 
11
14
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
12
15
  try {
@@ -97,14 +100,128 @@ function _objectSpread2(target) {
97
100
  return target;
98
101
  }
99
102
 
100
- exports.Method = void 0;
103
+ class WrappedError extends Error {
104
+ static from(maybeError) {
105
+ if (maybeError instanceof Error) {
106
+ return maybeError;
107
+ }
108
+
109
+ return new WrappedError(maybeError);
110
+ }
111
+
112
+ constructor(data) {
113
+ super('Something was thrown, but it was not an instance of Error, so a WrappedError was created.');
114
+ this.data = data;
115
+ }
116
+
117
+ }
118
+
119
+ function getLastEntryInMultiHeaderValue(headerValue) {
120
+ var normalized = Array.isArray(headerValue) ? headerValue.join(',') : headerValue;
121
+ var lastIndex = normalized.lastIndexOf(',');
122
+ return lastIndex === -1 ? normalized.trim() : normalized.slice(lastIndex + 1).trim();
123
+ } // Type for import('http').METHODS
124
+
125
+ function getInput(_x) {
126
+ return _getInput.apply(this, arguments);
127
+ }
128
+
129
+ function _getInput() {
130
+ _getInput = _asyncToGenerator(function* (req) {
131
+ if (req.method === 'GET') {
132
+ var input = req.url.searchParams.get('input');
133
+
134
+ if (!input) {
135
+ return null;
136
+ }
137
+
138
+ return JSON.parse(input);
139
+ }
140
+
141
+ var buffer = yield getRawBody__default["default"](req.raw);
142
+
143
+ switch (req.headers['content-type']) {
144
+ case 'application/json':
145
+ {
146
+ return JSON.parse(buffer.toString());
147
+ }
148
+
149
+ default:
150
+ {
151
+ return null;
152
+ }
153
+ }
154
+ });
155
+ return _getInput.apply(this, arguments);
156
+ }
157
+
158
+ class KaitoRequest {
159
+ constructor(raw) {
160
+ this.raw = raw;
161
+ }
101
162
 
102
- (function (Method) {
103
- Method["GET"] = "GET";
104
- Method["POST"] = "POST";
105
- Method["PATCH"] = "PATCH";
106
- Method["DELETE"] = "DELETE";
107
- })(exports.Method || (exports.Method = {}));
163
+ get fullURL() {
164
+ var _this$raw$url;
165
+
166
+ return "".concat(this.protocol, "://").concat(this.hostname).concat((_this$raw$url = this.raw.url) !== null && _this$raw$url !== void 0 ? _this$raw$url : '');
167
+ }
168
+
169
+ get url() {
170
+ return new URL(this.fullURL);
171
+ }
172
+
173
+ get method() {
174
+ if (!this.raw.method) {
175
+ throw new Error('Request method is not defined, somehow...');
176
+ }
177
+
178
+ return this.raw.method;
179
+ }
180
+
181
+ get protocol() {
182
+ if (this.raw.socket instanceof tls.TLSSocket) {
183
+ return this.raw.socket.encrypted ? 'https' : 'http';
184
+ }
185
+
186
+ return 'http';
187
+ }
188
+
189
+ get headers() {
190
+ return this.raw.headers;
191
+ }
192
+
193
+ get hostname() {
194
+ var _this$raw$headers$hos, _this$raw$headers$Au;
195
+
196
+ 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 : []);
197
+ }
198
+
199
+ }
200
+
201
+ class KaitoResponse {
202
+ constructor(raw) {
203
+ this.raw = raw;
204
+ }
205
+
206
+ header(key, value) {
207
+ this.raw.setHeader(key, value);
208
+ return this;
209
+ }
210
+
211
+ status(code) {
212
+ this.raw.statusCode = code;
213
+ return this;
214
+ }
215
+
216
+ json(data) {
217
+ var json = JSON.stringify(data);
218
+ this.raw.setHeader('Content-Type', 'application/json');
219
+ this.raw.setHeader('Content-Length', Buffer.byteLength(json));
220
+ this.raw.end(json);
221
+ return this;
222
+ }
223
+
224
+ }
108
225
 
109
226
  function createGetContext(getContext) {
110
227
  return getContext;
@@ -135,13 +252,27 @@ class Router {
135
252
  return new Router(mergedProcs);
136
253
  });
137
254
 
138
- _defineProperty(this, "get", this.create(exports.Method.GET));
255
+ _defineProperty(this, "get", this.create('GET'));
256
+
257
+ _defineProperty(this, "post", this.create('POST'));
258
+
259
+ _defineProperty(this, "put", this.create('PUT'));
260
+
261
+ _defineProperty(this, "patch", this.create('PATCH'));
139
262
 
140
- _defineProperty(this, "post", this.create(exports.Method.POST));
263
+ _defineProperty(this, "delete", this.create('DELETE'));
141
264
 
142
- _defineProperty(this, "patch", this.create(exports.Method.PATCH));
265
+ _defineProperty(this, "head", this.create('HEAD'));
143
266
 
144
- _defineProperty(this, "delete", this.create(exports.Method.DELETE));
267
+ _defineProperty(this, "options", this.create('OPTIONS'));
268
+
269
+ _defineProperty(this, "connect", this.create('CONNECT'));
270
+
271
+ _defineProperty(this, "trace", this.create('TRACE'));
272
+
273
+ _defineProperty(this, "acl", this.create('ACL'));
274
+
275
+ _defineProperty(this, "bind", this.create('BIND'));
145
276
 
146
277
  this.procs = procs;
147
278
  }
@@ -152,9 +283,9 @@ class Router {
152
283
 
153
284
  }
154
285
  class KaitoError extends Error {
155
- constructor(code, message, cause) {
286
+ constructor(status, message, cause) {
156
287
  super(message);
157
- this.code = code;
288
+ this.status = status;
158
289
  this.cause = cause;
159
290
  }
160
291
 
@@ -163,79 +294,78 @@ function createRouter() {
163
294
  return new Router({});
164
295
  }
165
296
  function createServer(config) {
166
- var tree = config.router.getProcs();
167
- var app = fastify__default["default"]();
168
- app.setErrorHandler( /*#__PURE__*/function () {
169
- var _ref = _asyncToGenerator(function* (error, req, res) {
170
- if (error instanceof KaitoError) {
171
- yield res.status(error.code).send({
172
- success: false,
173
- data: null,
174
- message: error.message
175
- });
176
- return;
177
- }
178
-
179
- var {
180
- code,
181
- message
182
- } = yield config.onError({
183
- error,
184
- req,
185
- res
186
- }).catch(() => ({
187
- code: 500,
188
- message: 'Something went wrong'
189
- }));
190
- yield res.status(code).send({
191
- success: false,
192
- data: null,
193
- message
194
- });
195
- });
196
-
197
- return function (_x, _x2, _x3) {
198
- return _ref.apply(this, arguments);
199
- };
200
- }());
201
- app.all('*', /*#__PURE__*/function () {
202
- var _ref2 = _asyncToGenerator(function* (req, res) {
203
- var _handler$input$parse, _handler$input;
204
-
205
- var logMessage = "".concat(req.hostname, " ").concat(req.method, " ").concat(req.url);
297
+ var log = message => {
298
+ if (config.log === undefined) {
299
+ console.log(message);
300
+ } else if (config.log) {
301
+ config.log(message);
302
+ }
303
+ };
206
304
 
207
- if (config.log === undefined) {
208
- console.log(logMessage);
209
- } else if (config.log) {
210
- config.log(logMessage);
211
- }
305
+ var tree = config.router.getProcs();
306
+ var server = http__default["default"].createServer( /*#__PURE__*/function () {
307
+ var _ref = _asyncToGenerator(function* (incomingMessage, serverResponse) {
308
+ var start = Date.now();
309
+ var req = new KaitoRequest(incomingMessage);
310
+ var res = new KaitoResponse(serverResponse);
212
311
 
213
- var url = new URL("".concat(req.protocol, "://").concat(req.hostname).concat(req.url));
214
- var handler = tree[url.pathname];
312
+ try {
313
+ var _handler$input, _yield$getInput;
215
314
 
216
- if (!handler) {
217
- throw new KaitoError(404, "Cannot ".concat(req.method, " this route."));
218
- }
315
+ var handler = tree[req.url.pathname];
219
316
 
220
- var context = yield config.getContext(req, res); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
317
+ if (!handler) {
318
+ throw new KaitoError(404, "Cannot ".concat(req.method, " this route."));
319
+ }
221
320
 
222
- var input = (_handler$input$parse = (_handler$input = handler.input) === null || _handler$input === void 0 ? void 0 : _handler$input.parse(req.method === 'GET' ? req.query : req.body)) !== null && _handler$input$parse !== void 0 ? _handler$input$parse : null;
223
- yield res.send({
224
- success: true,
225
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
226
- data: yield handler.run({
321
+ var input = (_handler$input = handler.input) === null || _handler$input === void 0 ? void 0 : _handler$input.parse((_yield$getInput = yield getInput(req)) !== null && _yield$getInput !== void 0 ? _yield$getInput : undefined);
322
+ var context = yield config.getContext(req, res);
323
+ var data = yield handler.run({
227
324
  ctx: context,
228
325
  input
229
- }),
230
- message: 'OK'
231
- });
326
+ });
327
+ res.json({
328
+ success: true,
329
+ data,
330
+ message: 'OK'
331
+ });
332
+ } catch (error) {
333
+ if (error instanceof KaitoError) {
334
+ res.status(error.status).json({
335
+ success: false,
336
+ data: null,
337
+ message: error.message
338
+ });
339
+ return;
340
+ }
341
+
342
+ var {
343
+ status: _status,
344
+ message: _message
345
+ } = yield config.onError({
346
+ error: WrappedError.from(error),
347
+ req,
348
+ res
349
+ }).catch(() => ({
350
+ status: 500,
351
+ message: 'Something went wrong'
352
+ }));
353
+ res.status(_status).json({
354
+ success: false,
355
+ data: null,
356
+ message: _message
357
+ });
358
+ } finally {
359
+ var finish = Date.now();
360
+ log("".concat(req.method, " ").concat(req.fullURL, " ").concat(res.raw.statusCode, " ").concat(finish - start, "ms"));
361
+ }
232
362
  });
233
363
 
234
- return function (_x4, _x5) {
235
- return _ref2.apply(this, arguments);
364
+ return function (_x, _x2) {
365
+ return _ref.apply(this, arguments);
236
366
  };
237
367
  }());
238
- return app;
368
+ return server;
239
369
  }
240
370
 
241
371
  exports.KaitoError = KaitoError;
@@ -1,4 +1,6 @@
1
- import fastify from 'fastify';
1
+ import http from 'http';
2
+ import { TLSSocket } from 'tls';
3
+ import getRawBody from 'raw-body';
2
4
 
3
5
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
4
6
  try {
@@ -89,14 +91,128 @@ function _objectSpread2(target) {
89
91
  return target;
90
92
  }
91
93
 
92
- var Method;
94
+ class WrappedError extends Error {
95
+ static from(maybeError) {
96
+ if (maybeError instanceof Error) {
97
+ return maybeError;
98
+ }
99
+
100
+ return new WrappedError(maybeError);
101
+ }
102
+
103
+ constructor(data) {
104
+ super('Something was thrown, but it was not an instance of Error, so a WrappedError was created.');
105
+ this.data = data;
106
+ }
107
+
108
+ }
109
+
110
+ function getLastEntryInMultiHeaderValue(headerValue) {
111
+ var normalized = Array.isArray(headerValue) ? headerValue.join(',') : headerValue;
112
+ var lastIndex = normalized.lastIndexOf(',');
113
+ return lastIndex === -1 ? normalized.trim() : normalized.slice(lastIndex + 1).trim();
114
+ } // Type for import('http').METHODS
115
+
116
+ function getInput(_x) {
117
+ return _getInput.apply(this, arguments);
118
+ }
119
+
120
+ function _getInput() {
121
+ _getInput = _asyncToGenerator(function* (req) {
122
+ if (req.method === 'GET') {
123
+ var input = req.url.searchParams.get('input');
124
+
125
+ if (!input) {
126
+ return null;
127
+ }
128
+
129
+ return JSON.parse(input);
130
+ }
131
+
132
+ var buffer = yield getRawBody(req.raw);
133
+
134
+ switch (req.headers['content-type']) {
135
+ case 'application/json':
136
+ {
137
+ return JSON.parse(buffer.toString());
138
+ }
139
+
140
+ default:
141
+ {
142
+ return null;
143
+ }
144
+ }
145
+ });
146
+ return _getInput.apply(this, arguments);
147
+ }
148
+
149
+ class KaitoRequest {
150
+ constructor(raw) {
151
+ this.raw = raw;
152
+ }
93
153
 
94
- (function (Method) {
95
- Method["GET"] = "GET";
96
- Method["POST"] = "POST";
97
- Method["PATCH"] = "PATCH";
98
- Method["DELETE"] = "DELETE";
99
- })(Method || (Method = {}));
154
+ get fullURL() {
155
+ var _this$raw$url;
156
+
157
+ return "".concat(this.protocol, "://").concat(this.hostname).concat((_this$raw$url = this.raw.url) !== null && _this$raw$url !== void 0 ? _this$raw$url : '');
158
+ }
159
+
160
+ get url() {
161
+ return new URL(this.fullURL);
162
+ }
163
+
164
+ get method() {
165
+ if (!this.raw.method) {
166
+ throw new Error('Request method is not defined, somehow...');
167
+ }
168
+
169
+ return this.raw.method;
170
+ }
171
+
172
+ get protocol() {
173
+ if (this.raw.socket instanceof TLSSocket) {
174
+ return this.raw.socket.encrypted ? 'https' : 'http';
175
+ }
176
+
177
+ return 'http';
178
+ }
179
+
180
+ get headers() {
181
+ return this.raw.headers;
182
+ }
183
+
184
+ get hostname() {
185
+ var _this$raw$headers$hos, _this$raw$headers$Au;
186
+
187
+ 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 : []);
188
+ }
189
+
190
+ }
191
+
192
+ class KaitoResponse {
193
+ constructor(raw) {
194
+ this.raw = raw;
195
+ }
196
+
197
+ header(key, value) {
198
+ this.raw.setHeader(key, value);
199
+ return this;
200
+ }
201
+
202
+ status(code) {
203
+ this.raw.statusCode = code;
204
+ return this;
205
+ }
206
+
207
+ json(data) {
208
+ var json = JSON.stringify(data);
209
+ this.raw.setHeader('Content-Type', 'application/json');
210
+ this.raw.setHeader('Content-Length', Buffer.byteLength(json));
211
+ this.raw.end(json);
212
+ return this;
213
+ }
214
+
215
+ }
100
216
 
101
217
  function createGetContext(getContext) {
102
218
  return getContext;
@@ -127,13 +243,27 @@ class Router {
127
243
  return new Router(mergedProcs);
128
244
  });
129
245
 
130
- _defineProperty(this, "get", this.create(Method.GET));
246
+ _defineProperty(this, "get", this.create('GET'));
247
+
248
+ _defineProperty(this, "post", this.create('POST'));
249
+
250
+ _defineProperty(this, "put", this.create('PUT'));
251
+
252
+ _defineProperty(this, "patch", this.create('PATCH'));
131
253
 
132
- _defineProperty(this, "post", this.create(Method.POST));
254
+ _defineProperty(this, "delete", this.create('DELETE'));
133
255
 
134
- _defineProperty(this, "patch", this.create(Method.PATCH));
256
+ _defineProperty(this, "head", this.create('HEAD'));
135
257
 
136
- _defineProperty(this, "delete", this.create(Method.DELETE));
258
+ _defineProperty(this, "options", this.create('OPTIONS'));
259
+
260
+ _defineProperty(this, "connect", this.create('CONNECT'));
261
+
262
+ _defineProperty(this, "trace", this.create('TRACE'));
263
+
264
+ _defineProperty(this, "acl", this.create('ACL'));
265
+
266
+ _defineProperty(this, "bind", this.create('BIND'));
137
267
 
138
268
  this.procs = procs;
139
269
  }
@@ -144,9 +274,9 @@ class Router {
144
274
 
145
275
  }
146
276
  class KaitoError extends Error {
147
- constructor(code, message, cause) {
277
+ constructor(status, message, cause) {
148
278
  super(message);
149
- this.code = code;
279
+ this.status = status;
150
280
  this.cause = cause;
151
281
  }
152
282
 
@@ -155,79 +285,78 @@ function createRouter() {
155
285
  return new Router({});
156
286
  }
157
287
  function createServer(config) {
158
- var tree = config.router.getProcs();
159
- var app = fastify();
160
- app.setErrorHandler( /*#__PURE__*/function () {
161
- var _ref = _asyncToGenerator(function* (error, req, res) {
162
- if (error instanceof KaitoError) {
163
- yield res.status(error.code).send({
164
- success: false,
165
- data: null,
166
- message: error.message
167
- });
168
- return;
169
- }
170
-
171
- var {
172
- code,
173
- message
174
- } = yield config.onError({
175
- error,
176
- req,
177
- res
178
- }).catch(() => ({
179
- code: 500,
180
- message: 'Something went wrong'
181
- }));
182
- yield res.status(code).send({
183
- success: false,
184
- data: null,
185
- message
186
- });
187
- });
188
-
189
- return function (_x, _x2, _x3) {
190
- return _ref.apply(this, arguments);
191
- };
192
- }());
193
- app.all('*', /*#__PURE__*/function () {
194
- var _ref2 = _asyncToGenerator(function* (req, res) {
195
- var _handler$input$parse, _handler$input;
196
-
197
- var logMessage = "".concat(req.hostname, " ").concat(req.method, " ").concat(req.url);
288
+ var log = message => {
289
+ if (config.log === undefined) {
290
+ console.log(message);
291
+ } else if (config.log) {
292
+ config.log(message);
293
+ }
294
+ };
198
295
 
199
- if (config.log === undefined) {
200
- console.log(logMessage);
201
- } else if (config.log) {
202
- config.log(logMessage);
203
- }
296
+ var tree = config.router.getProcs();
297
+ var server = http.createServer( /*#__PURE__*/function () {
298
+ var _ref = _asyncToGenerator(function* (incomingMessage, serverResponse) {
299
+ var start = Date.now();
300
+ var req = new KaitoRequest(incomingMessage);
301
+ var res = new KaitoResponse(serverResponse);
204
302
 
205
- var url = new URL("".concat(req.protocol, "://").concat(req.hostname).concat(req.url));
206
- var handler = tree[url.pathname];
303
+ try {
304
+ var _handler$input, _yield$getInput;
207
305
 
208
- if (!handler) {
209
- throw new KaitoError(404, "Cannot ".concat(req.method, " this route."));
210
- }
306
+ var handler = tree[req.url.pathname];
211
307
 
212
- var context = yield config.getContext(req, res); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
308
+ if (!handler) {
309
+ throw new KaitoError(404, "Cannot ".concat(req.method, " this route."));
310
+ }
213
311
 
214
- var input = (_handler$input$parse = (_handler$input = handler.input) === null || _handler$input === void 0 ? void 0 : _handler$input.parse(req.method === 'GET' ? req.query : req.body)) !== null && _handler$input$parse !== void 0 ? _handler$input$parse : null;
215
- yield res.send({
216
- success: true,
217
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
218
- data: yield handler.run({
312
+ var input = (_handler$input = handler.input) === null || _handler$input === void 0 ? void 0 : _handler$input.parse((_yield$getInput = yield getInput(req)) !== null && _yield$getInput !== void 0 ? _yield$getInput : undefined);
313
+ var context = yield config.getContext(req, res);
314
+ var data = yield handler.run({
219
315
  ctx: context,
220
316
  input
221
- }),
222
- message: 'OK'
223
- });
317
+ });
318
+ res.json({
319
+ success: true,
320
+ data,
321
+ message: 'OK'
322
+ });
323
+ } catch (error) {
324
+ if (error instanceof KaitoError) {
325
+ res.status(error.status).json({
326
+ success: false,
327
+ data: null,
328
+ message: error.message
329
+ });
330
+ return;
331
+ }
332
+
333
+ var {
334
+ status: _status,
335
+ message: _message
336
+ } = yield config.onError({
337
+ error: WrappedError.from(error),
338
+ req,
339
+ res
340
+ }).catch(() => ({
341
+ status: 500,
342
+ message: 'Something went wrong'
343
+ }));
344
+ res.status(_status).json({
345
+ success: false,
346
+ data: null,
347
+ message: _message
348
+ });
349
+ } finally {
350
+ var finish = Date.now();
351
+ log("".concat(req.method, " ").concat(req.fullURL, " ").concat(res.raw.statusCode, " ").concat(finish - start, "ms"));
352
+ }
224
353
  });
225
354
 
226
- return function (_x4, _x5) {
227
- return _ref2.apply(this, arguments);
355
+ return function (_x, _x2) {
356
+ return _ref.apply(this, arguments);
228
357
  };
229
358
  }());
230
- return app;
359
+ return server;
231
360
  }
232
361
 
233
- export { KaitoError, Method, Router, createGetContext, createRouter, createServer };
362
+ export { KaitoError, Router, createGetContext, createRouter, createServer };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaito-http/core",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "description": "Functional HTTP Framework for TypeScript",
5
5
  "repository": "https://github.com/kaito-http/kaito",
6
6
  "author": "Alistair Smith <hi@alistair.sh>",
@@ -11,7 +11,6 @@
11
11
  "devDependencies": {
12
12
  "@types/body-parser": "^1.19.2",
13
13
  "@types/node": "^17.0.24",
14
- "@types/node-fetch": "^2.6.1",
15
14
  "typescript": "4.6",
16
15
  "zod": "^3.14.4"
17
16
  },
@@ -20,10 +19,6 @@
20
19
  "readme.md",
21
20
  "dist"
22
21
  ],
23
- "dependencies": {
24
- "colorette": "^2.0.16",
25
- "fastify": "^3.28.0"
26
- },
27
22
  "bugs": {
28
23
  "url": "https://github.com/kaito-http/kaito/issues"
29
24
  },
@@ -33,8 +28,10 @@
33
28
  },
34
29
  "keywords": [
35
30
  "typescript",
36
- "fastify",
37
31
  "http",
38
32
  "framework"
39
- ]
33
+ ],
34
+ "dependencies": {
35
+ "raw-body": "^2.5.1"
36
+ }
40
37
  }