diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..995fca4 --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +NODE_ENV=production \ No newline at end of file diff --git a/.gitignore b/.gitignore index e63bf21..ac2fb13 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules .vimsession .env -.env.prod \ No newline at end of file +.env.prod +package-lock.json \ No newline at end of file diff --git a/package.json b/package.json index 3db13a4..34303bd 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "start": "tsx src/index.ts", "compile": "tsc --build tsconfig.json", "lint": "eslint .", - "dev": "tsx watch src/index.ts" + "dev": "tsx watch --env-file=./.env src/index.ts" }, "dependencies": { "@hono/node-server": "^1.7.0", @@ -15,9 +15,10 @@ }, "devDependencies": { "@hazmi35/eslint-config": "^13.3.1", - "@hono/zod-validator": "^0.1.11", "@tsconfig/node-lts": "^20.1.1", "@types/node": "^20.11.20", + "pino": "^8.19.0", + "pino-pretty": "^10.3.1", "tsx": "^3.12.2", "zod": "^3.22.4" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6dbfee2..bd00d39 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,15 +19,18 @@ devDependencies: '@hazmi35/eslint-config': specifier: ^13.3.1 version: 13.3.1(@eslint/eslintrc@3.0.1)(@stylistic/eslint-plugin@1.6.2)(@typescript-eslint/eslint-plugin@7.0.2)(@typescript-eslint/parser@7.0.2)(eslint-config-prettier@9.1.0)(eslint-import-resolver-typescript@3.6.1)(eslint-plugin-import@2.29.1)(eslint-plugin-jsdoc@48.2.0)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.1.1)(eslint-plugin-tsdoc@0.2.17)(eslint-plugin-unicorn@51.0.1)(eslint@8.56.0)(globals@14.0.0)(typescript@5.3.3) - '@hono/zod-validator': - specifier: ^0.1.11 - version: 0.1.11(hono@4.0.5)(zod@3.22.4) '@tsconfig/node-lts': specifier: ^20.1.1 version: 20.1.1 '@types/node': specifier: ^20.11.20 version: 20.11.20 + pino: + specifier: ^8.19.0 + version: 8.19.0 + pino-pretty: + specifier: ^10.3.1 + version: 10.3.1 tsx: specifier: ^3.12.2 version: 3.14.0 @@ -366,16 +369,6 @@ packages: engines: {node: '>=18.14.1'} dev: false - /@hono/zod-validator@0.1.11(hono@4.0.5)(zod@3.22.4): - resolution: {integrity: sha512-PQXeHUP0+36qpRt8yfeD7N2jbK3ETlGvSN6dMof/HwUC/APRokQRjpXZm4rrlG71Ft0aWE01+Bm4XejqPie5Uw==} - peerDependencies: - hono: '>=3.9.0' - zod: ^3.19.1 - dependencies: - hono: 4.0.5 - zod: 3.22.4 - dev: true - /@humanwhocodes/config-array@0.11.14: resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -737,6 +730,13 @@ packages: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true + /abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + dependencies: + event-target-shim: 5.0.1 + dev: true + /acorn-jsx@5.3.2(acorn@8.11.3): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -868,6 +868,11 @@ packages: is-shared-array-buffer: 1.0.3 dev: true + /atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + dev: true + /available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -879,6 +884,10 @@ packages: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: true + /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -914,6 +923,13 @@ packages: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: true + /builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} @@ -995,6 +1011,10 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true + /colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + dev: true + /comment-parser@1.4.1: resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} engines: {node: '>= 12.0.0'} @@ -1019,6 +1039,10 @@ packages: which: 2.0.2 dev: true + /dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + dev: true + /debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -1089,6 +1113,12 @@ packages: resolution: {integrity: sha512-4nToZ5jlPO14W82NkF32wyjhYqQByVaDmLy4J2/tYcAbJfgO2TKJC780Az1V13gzq4l73CJ0yuyalpXvxXXD9A==} dev: true + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: true + /enhanced-resolve@5.15.0: resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==} engines: {node: '>=10.13.0'} @@ -1553,6 +1583,20 @@ packages: engines: {node: '>=0.10.0'} dev: true + /event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + dev: true + + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + dev: true + + /fast-copy@3.0.1: + resolution: {integrity: sha512-Knr7NOtK3HWRYGtHoJrjkaWepqT8thIVGAwt0p0aUs1zqkAzXZV4vo9fFNwyb5fcqK1GKYFYxldQdIDVKhUAfA==} + dev: true + /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true @@ -1576,6 +1620,15 @@ packages: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true + /fast-redact@3.3.0: + resolution: {integrity: sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ==} + engines: {node: '>=6'} + dev: true + + /fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + dev: true + /fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} dependencies: @@ -1801,14 +1854,23 @@ packages: function-bind: 1.1.2 dev: true + /help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + dev: true + /hono@4.0.5: resolution: {integrity: sha512-6LEGL1Pf3+dLjVA0NJxAB/3FJ6S3W5qxd/XOG7Wl9YOrpMRZT9lt83R4Ojs8dO6GbAUSutI7zTyjStnSn9sbEg==} engines: {node: '>=16.0.0'} + dev: false /hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} dev: true + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: true + /ignore@5.3.1: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} @@ -1991,6 +2053,11 @@ packages: resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} dev: true + /joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + dev: true + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: true @@ -2191,6 +2258,11 @@ packages: es-abstract: 1.22.4 dev: true + /on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + dev: true + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: @@ -2297,6 +2369,54 @@ packages: engines: {node: '>=12'} dev: true + /pino-abstract-transport@1.1.0: + resolution: {integrity: sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==} + dependencies: + readable-stream: 4.5.2 + split2: 4.2.0 + dev: true + + /pino-pretty@10.3.1: + resolution: {integrity: sha512-az8JbIYeN/1iLj2t0jR9DV48/LQ3RC6hZPpapKPkb84Q+yTidMCpgWxIT3N0flnBDilyBQ1luWNpOeJptjdp/g==} + hasBin: true + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 3.0.1 + fast-safe-stringify: 2.1.1 + help-me: 5.0.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 1.1.0 + pump: 3.0.0 + readable-stream: 4.5.2 + secure-json-parse: 2.7.0 + sonic-boom: 3.8.0 + strip-json-comments: 3.1.1 + dev: true + + /pino-std-serializers@6.2.2: + resolution: {integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==} + dev: true + + /pino@8.19.0: + resolution: {integrity: sha512-oswmokxkav9bADfJ2ifrvfHUwad6MLp73Uat0IkQWY3iAw5xTRoznXbXksZs8oaOUMpmhVWD+PZogNzllWpJaA==} + hasBin: true + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.3.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 1.1.0 + pino-std-serializers: 6.2.2 + process-warning: 3.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.4.3 + sonic-boom: 3.8.0 + thread-stream: 2.4.1 + dev: true + /pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} @@ -2312,6 +2432,22 @@ packages: engines: {node: '>= 0.8.0'} dev: true + /process-warning@3.0.0: + resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} + dev: true + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: true + + /pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: true + /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -2321,6 +2457,10 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true + /quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + dev: true + /read-pkg-up@7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} engines: {node: '>=8'} @@ -2340,6 +2480,22 @@ packages: type-fest: 0.6.0 dev: true + /readable-stream@4.5.2: + resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + dev: true + + /real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + dev: true + /reflect-metadata@0.2.1: resolution: {integrity: sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==} dev: false @@ -2419,6 +2575,10 @@ packages: isarray: 2.0.5 dev: true + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true + /safe-regex-test@1.0.3: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} @@ -2428,6 +2588,15 @@ packages: is-regex: 1.1.4 dev: true + /safe-stable-stringify@2.4.3: + resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} + engines: {node: '>=10'} + dev: true + + /secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + dev: true + /semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -2495,6 +2664,12 @@ packages: engines: {node: '>=8'} dev: true + /sonic-boom@3.8.0: + resolution: {integrity: sha512-ybz6OYOUjoQQCQ/i4LU8kaToD8ACtYP+Cj5qd2AO36bwbdewxWJ3ArmJ2cr6AvxlL2o0PqnCcPGUgkILbfkaCA==} + dependencies: + atomic-sleep: 1.0.0 + dev: true + /source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} dependencies: @@ -2536,6 +2711,11 @@ packages: resolution: {integrity: sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==} dev: true + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + dev: true + /string.prototype.trim@1.2.8: resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} engines: {node: '>= 0.4'} @@ -2561,6 +2741,12 @@ packages: es-abstract: 1.22.4 dev: true + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: true + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -2613,6 +2799,12 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true + /thread-stream@2.4.1: + resolution: {integrity: sha512-d/Ex2iWd1whipbT681JmTINKw0ZwOUBZm7+Gjs64DHuX34mmw8vJL2bFAaNacaW72zYiTJxSHi5abUuOi5nsfg==} + dependencies: + real-require: 0.2.0 + dev: true + /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} diff --git a/src/App/Decorator/Validator.ts b/src/App/Decorator/Validator.ts index f4c5318..fc8f7d0 100644 --- a/src/App/Decorator/Validator.ts +++ b/src/App/Decorator/Validator.ts @@ -1,11 +1,12 @@ import "reflect-metadata"; -import { zValidator } from "@hono/zod-validator"; import type { ValidationTargets } from "hono"; +import { validator as honoValidator } from "hono/validator"; import { z } from "zod"; import { MetadataValidatorConstant } from "App/Types/ControllerConstant.js"; import type Controller from "Controller/Controller.js"; +import { onValidateError } from "Function/OnValidateError.js"; -type ZodData = { [VK in keyof V]: any }; +export type ZodData = { [VK in keyof V]: any }; /** * Validate data for route. @@ -18,7 +19,13 @@ export default function validator(method: keyof ValidationTargets, const targetFunc = descriptor.value as Function; Reflect.defineMetadata( MetadataValidatorConstant, - zValidator(method, z.object(data)), + honoValidator(method, (val, c) => { + const parsed = z.object(data).safeParse(val); + + if (!parsed.success) return onValidateError(c, data); + + return parsed.data; + }), targetFunc ); }; diff --git a/src/App/Function/InjectController.ts b/src/App/Function/InjectController.ts index a5fb58a..4e9cabd 100644 --- a/src/App/Function/InjectController.ts +++ b/src/App/Function/InjectController.ts @@ -2,6 +2,7 @@ import { join } from "node:path"; import { NoDefaultExportError, IsNotConstructorError } from "App/Error/AppError.js"; import type { DefaultHonoApp } from "App/Types/ControllerTypes.js"; import Controller from "Controller/Controller.js"; +import Logger from "Logger.js"; import traversalFileScan from "./TraversalFileScan.js"; type ImportController = { @@ -17,6 +18,7 @@ export default async function injectController(app: DefaultHonoApp): Promise): boolean { + const ret = header["content-type"]; + if (!ret) return false; + if (ret !== "application/json") return false; + return true; +} diff --git a/src/App/Function/OnError.ts b/src/App/Function/OnError.ts deleted file mode 100644 index 415b3b5..0000000 --- a/src/App/Function/OnError.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { Context, Env } from "hono"; - -export default function onError(err: Error, c: Context): Response { - const errMessage = err.message; - - console.error(err); - return c.json({ - message: "Something happened, but don't worry maybe it's you or our developer.", - errMessage - }, 500); -} diff --git a/src/Controller/Controller.ts b/src/Controller/Controller.ts index 621600c..ff91970 100644 --- a/src/Controller/Controller.ts +++ b/src/Controller/Controller.ts @@ -10,6 +10,7 @@ import type { DefaultHonoApp, DefaultHonoFunctionContext } from "App/Types/ControllerTypes.js"; +import Logger from "Logger.js"; /** * Base of Controller class. @@ -49,6 +50,7 @@ export default class Controller { } ctx.push(func); + Logger.info(`Register ${metadata.method}:${metadata.path} route`); // TODO [2024-03-01]: How to bypass this? // eslint-disable-next-line @typescript-eslint/ban-ts-comment diff --git a/src/Function/OnError.ts b/src/Function/OnError.ts new file mode 100644 index 0000000..ebbb2eb --- /dev/null +++ b/src/Function/OnError.ts @@ -0,0 +1,45 @@ +import { randomUUID } from "node:crypto"; +import type { Context, Env } from "hono"; +import type { HTTPException } from "hono/http-exception"; +import type { StatusCode } from "hono/utils/http-status"; +import isJson from "App/Function/IsJson.js"; +import Logger from "Logger.js"; + +type ErrorRecord = { + message: string; + errMessage?: string; + uuidErr?: string; +}; + +export default function onError(err: Error, c: Context): Response { + const errResponse: ErrorRecord = { + message: "" + }; + errResponse.message = "Something happened, but don't worry maybe it's you or our developer."; + errResponse.errMessage = err.message; + let code: StatusCode = 500; + + // Expecting this is HTTPError + if (Object.keys(err).includes("status")) { + const newErr = err as HTTPException; + code = newErr.status; + + errResponse.message = newErr.message; + delete errResponse.errMessage; + } + + // If fatal error + if (code === 500) { + errResponse.uuidErr = randomUUID(); + Logger.child({ uuid: errResponse.uuidErr }).error(err, "Fatal error on server"); + } + + const jsonMethod = isJson(c.req.header()); + if (jsonMethod) return c.json(errResponse, code); + + // You can improve on this side, this is just example. + let msgText = errResponse.message; + if (errResponse.errMessage !== undefined) msgText += `\n${errResponse.errMessage}`; + if (errResponse.uuidErr !== undefined) msgText += `\nUUID Code: ${errResponse.uuidErr}`; + return c.text(msgText, code); +} diff --git a/src/Function/OnNotFound.ts b/src/Function/OnNotFound.ts new file mode 100644 index 0000000..f60e75e --- /dev/null +++ b/src/Function/OnNotFound.ts @@ -0,0 +1,12 @@ +import type { Context } from "hono"; +import isJson from "App/Function/IsJson.js"; + +export function onNotFound(c: Context): Response { + const message = "Path not found."; + const code = 404; + + const jsonMethod = isJson(c.req.header()); + if (jsonMethod) return c.json({ message }, code); + + return c.text(message, code); +} diff --git a/src/Function/OnValidateError.ts b/src/Function/OnValidateError.ts new file mode 100644 index 0000000..003e55b --- /dev/null +++ b/src/Function/OnValidateError.ts @@ -0,0 +1,14 @@ +import type { Context } from "hono"; +import type { ZodData } from "App/Decorator/Validator.js"; +import isJson from "App/Function/IsJson.js"; + +export function onValidateError(c: Context, data: ZodData): Response { + const message = "Bad request performed."; + const code = 400; + const propsOnServer = Object.keys(data); + + const jsonMethod = isJson(c.req.header()); + if (jsonMethod) return c.json({ message, propsOnServer }, code); + + return c.text(message, code); +} diff --git a/src/Function/SampleFunction.ts b/src/Function/SampleFunction.ts deleted file mode 100644 index 6540c31..0000000 --- a/src/Function/SampleFunction.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default function sampleFunction(): void { - console.log("And this is John Cena!!!"); - console.log("Tet tenet teeeeet."); -} diff --git a/src/Initialize.ts b/src/Initialize.ts index 3e11945..2a1e0e3 100644 --- a/src/Initialize.ts +++ b/src/Initialize.ts @@ -1,7 +1,9 @@ import { logger } from "hono/logger"; import injectController from "App/Function/InjectController.js"; -import onError from "App/Function/OnError.js"; import type { DefaultHonoApp } from "App/Types/ControllerTypes.js"; +import onError from "Function/OnError.js"; +import { onNotFound } from "Function/OnNotFound.js"; +import Logger from "Logger.js"; export async function initialize(app: DefaultHonoApp): Promise { /** @@ -11,11 +13,16 @@ export async function initialize(app: DefaultHonoApp): Promise { */ // Initialize Logger - app.use(logger()); + app.use(logger((msg: string, ...rest: string[]) => { + Logger.info(msg, ...rest); + })); // When error is spawned app.onError(onError); + // When is not found + app.notFound(onNotFound); + /** * The rest of initialize ends here. After this, system will * collecting all of Controllers files. diff --git a/src/Logger.ts b/src/Logger.ts new file mode 100644 index 0000000..296c16b --- /dev/null +++ b/src/Logger.ts @@ -0,0 +1,25 @@ +import process from "node:process"; +import type { LoggerOptions } from "pino"; +import { pino } from "pino"; + +/** + * You can modify Logger traits in here. + * Check documentation on https://getpino.io/ + */ +const PinoTraits: LoggerOptions = { + formatters: { + level: (label: string) => ({ level: label.toUpperCase() }) + } +}; + +// Colorize print if in Development +if (process.env.NODE_ENV !== "production") { + PinoTraits.transport = { + target: "pino-pretty", + options: { + colorize: true + } + }; +} + +export default pino(PinoTraits); diff --git a/src/index.ts b/src/index.ts index f71f73a..7789e9e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,12 +1,13 @@ import { serve } from "@hono/node-server"; import { Hono } from "hono"; import { initialize } from "Initialize.js"; +import Logger from "Logger.js"; const app = new Hono(); const port = 3_000; await initialize(app); -console.log(`Server is running on port ${port}`); +Logger.info(`Server is running on port ${port}`); serve({ fetch: app.fetch, port