From c986884ed508e2cd2ecba463d1fb2b445881f31c Mon Sep 17 00:00:00 2001 From: calli Date: Mon, 28 Apr 2025 17:55:31 +0300 Subject: [PATCH] Improve logging and handle errors beter --- package-lock.json | 365 +++++++++++++++++++++++++++++++++++++++ package.json | 3 + src/pages/api/env.ts | 46 ++++- src/pages/api/praisal.ts | 36 +++- src/pages/api/refresh.ts | 44 ++++- src/pages/api/revoke.ts | 43 ++++- src/pages/api/token.ts | 100 ++++++++--- src/utils.ts | 13 -- src/utils/logger.ts | 18 ++ src/utils/utils.ts | 22 +++ 10 files changed, 631 insertions(+), 59 deletions(-) delete mode 100644 src/utils.ts create mode 100644 src/utils/logger.ts create mode 100644 src/utils/utils.ts diff --git a/package-lock.json b/package-lock.json index 1462667..2ba917c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@mui/material": "^5.13.5", "@sentry/nextjs": "^8.2.1", "@types/node": "20.3.1", + "@types/pino": "^7.0.4", "@types/react": "18.2.12", "@types/react-dom": "18.2.5", "autoprefixer": "10.4.14", @@ -25,6 +26,8 @@ "luxon": "^3.6.1", "next": "^14.2.23", "next-plausible": "^3.12.0", + "pino": "^9.6.0", + "pino-pretty": "^13.0.0", "react": "^18.3.1", "react-chartjs-2": "^5.3.0", "react-color": "^2.19.3", @@ -2561,6 +2564,15 @@ "@types/pg": "*" } }, + "node_modules/@types/pino": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@types/pino/-/pino-7.0.4.tgz", + "integrity": "sha512-yKw1UbZOTe7vP1xMQT+oz3FexwgIpBTrM+AC62vWgAkNRULgLTJWfYX+H5/sKPm8VXFbIcXkC3VZPyuaNioZFg==", + "license": "MIT", + "dependencies": { + "pino": "*" + } + }, "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", @@ -3175,6 +3187,15 @@ "node": ">= 0.4" } }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/autoprefixer": { "version": "10.4.14", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", @@ -3713,6 +3734,12 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -3845,6 +3872,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -5046,6 +5082,12 @@ "node": ">=6" } }, + "node_modules/fast-copy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5102,6 +5144,21 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, "node_modules/fast-uri": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", @@ -5607,6 +5664,12 @@ "node": ">= 0.4" } }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "license": "MIT" + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -6302,6 +6365,15 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -6942,6 +7014,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -7189,6 +7270,67 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pino": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.6.0.tgz", + "integrity": "sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^4.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.0.0.tgz", + "integrity": "sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA==", + "license": "MIT", + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^3.0.2", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pump": "^3.0.0", + "secure-json-parse": "^2.4.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", + "license": "MIT" + }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", @@ -7332,6 +7474,22 @@ "node": ">=6.0.0" } }, + "node_modules/process-warning": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.1.tgz", + "integrity": "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -7393,6 +7551,12 @@ } ] }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, "node_modules/raf-schd": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", @@ -7548,6 +7712,15 @@ "node": ">=8.10.0" } }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, "node_modules/redux": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", @@ -7900,6 +8073,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -7928,6 +8110,12 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", + "license": "BSD-3-Clause" + }, "node_modules/semver": { "version": "7.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz", @@ -8210,6 +8398,15 @@ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, + "node_modules/sonic-boom": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", + "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -8248,6 +8445,15 @@ "node": ">=0.10.0" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/stacktrace-parser": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", @@ -8746,6 +8952,15 @@ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" }, + "node_modules/thread-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + } + }, "node_modules/three": { "version": "0.154.0", "resolved": "https://registry.npmjs.org/three/-/three-0.154.0.tgz", @@ -11006,6 +11221,14 @@ "@types/pg": "*" } }, + "@types/pino": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@types/pino/-/pino-7.0.4.tgz", + "integrity": "sha512-yKw1UbZOTe7vP1xMQT+oz3FexwgIpBTrM+AC62vWgAkNRULgLTJWfYX+H5/sKPm8VXFbIcXkC3VZPyuaNioZFg==", + "requires": { + "pino": "*" + } + }, "@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", @@ -11494,6 +11717,11 @@ "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", "dev": true }, + "atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" + }, "autoprefixer": { "version": "10.4.14", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", @@ -11828,6 +12056,11 @@ "simple-swizzle": "^0.2.2" } }, + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -11928,6 +12161,11 @@ "is-data-view": "^1.0.1" } }, + "dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==" + }, "debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -12757,6 +12995,11 @@ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" }, + "fast-copy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==" + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -12807,6 +13050,16 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==" + }, + "fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + }, "fast-uri": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", @@ -13135,6 +13388,11 @@ "function-bind": "^1.1.2" } }, + "help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==" + }, "hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -13565,6 +13823,11 @@ } } }, + "joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -13985,6 +14248,11 @@ "es-object-atoms": "^1.0.0" } }, + "on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -14151,6 +14419,57 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, + "pino": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.6.0.tgz", + "integrity": "sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg==", + "requires": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^4.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + } + }, + "pino-abstract-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "requires": { + "split2": "^4.0.0" + } + }, + "pino-pretty": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.0.0.tgz", + "integrity": "sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA==", + "requires": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^3.0.2", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pump": "^3.0.0", + "secure-json-parse": "^2.4.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^3.1.1" + } + }, + "pino-std-serializers": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==" + }, "possible-typed-array-names": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", @@ -14235,6 +14554,11 @@ "fast-diff": "^1.1.2" } }, + "process-warning": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.1.tgz", + "integrity": "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==" + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -14274,6 +14598,11 @@ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, + "quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" + }, "raf-schd": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", @@ -14393,6 +14722,11 @@ "picomatch": "^2.2.1" } }, + "real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==" + }, "redux": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", @@ -14608,6 +14942,11 @@ "is-regex": "^1.2.1" } }, + "safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==" + }, "scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -14627,6 +14966,11 @@ "ajv-keywords": "^3.5.2" } }, + "secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==" + }, "semver": { "version": "7.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz", @@ -14818,6 +15162,14 @@ } } }, + "sonic-boom": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", + "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==", + "requires": { + "atomic-sleep": "^1.0.0" + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -14846,6 +15198,11 @@ } } }, + "split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" + }, "stacktrace-parser": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", @@ -15177,6 +15534,14 @@ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" }, + "thread-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "requires": { + "real-require": "^0.2.0" + } + }, "three": { "version": "0.154.0", "resolved": "https://registry.npmjs.org/three/-/three-0.154.0.tgz", diff --git a/package.json b/package.json index cf70796..9c71392 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@mui/material": "^5.13.5", "@sentry/nextjs": "^8.2.1", "@types/node": "20.3.1", + "@types/pino": "^7.0.4", "@types/react": "18.2.12", "@types/react-dom": "18.2.5", "autoprefixer": "10.4.14", @@ -27,6 +28,8 @@ "luxon": "^3.6.1", "next": "^14.2.23", "next-plausible": "^3.12.0", + "pino": "^9.6.0", + "pino-pretty": "^13.0.0", "react": "^18.3.1", "react-chartjs-2": "^5.3.0", "react-color": "^2.19.3", diff --git a/src/pages/api/env.ts b/src/pages/api/env.ts index 71af247..73526c8 100644 --- a/src/pages/api/env.ts +++ b/src/pages/api/env.ts @@ -1,11 +1,51 @@ import { NextApiRequest, NextApiResponse } from "next"; +import logger from "@/utils/logger"; const handler = async (req: NextApiRequest, res: NextApiResponse) => { if (req.method === "GET") { - const EVE_SSO_CALLBACK_URL = process.env.EVE_SSO_CALLBACK_URL; - const EVE_SSO_CLIENT_ID = process.env.EVE_SSO_CLIENT_ID; - res.json({ EVE_SSO_CLIENT_ID, EVE_SSO_CALLBACK_URL }); + logger.info({ + event: 'env_request_start' + }); + + try { + const EVE_SSO_CALLBACK_URL = process.env.EVE_SSO_CALLBACK_URL; + const EVE_SSO_CLIENT_ID = process.env.EVE_SSO_CLIENT_ID; + + if (!EVE_SSO_CALLBACK_URL || !EVE_SSO_CLIENT_ID) { + logger.error({ + event: 'env_request_failed', + reason: 'missing_env_vars', + vars: { + hasCallbackUrl: !!EVE_SSO_CALLBACK_URL, + hasClientId: !!EVE_SSO_CLIENT_ID + } + }); + return res.status(500).json({ error: 'Missing required environment variables' }); + } + + logger.info({ + event: 'env_request_success', + vars: { + hasCallbackUrl: true, + hasClientId: true + } + }); + + return res.json({ EVE_SSO_CLIENT_ID, EVE_SSO_CALLBACK_URL }); + } catch (e) { + logger.error({ + event: 'env_request_failed', + reason: 'unexpected_error', + error: e + }); + return res.status(500).json({ error: 'Internal server error' }); + } } else { + logger.warn({ + event: 'invalid_method', + method: req.method, + path: req.url + }); res.status(404).end(); } }; diff --git a/src/pages/api/praisal.ts b/src/pages/api/praisal.ts index d82d55a..e8e2d71 100644 --- a/src/pages/api/praisal.ts +++ b/src/pages/api/praisal.ts @@ -1,19 +1,45 @@ import { getPraisal } from "@/eve-praisal"; import { NextApiRequest, NextApiResponse } from "next"; +import logger from "@/utils/logger"; const handler = async (req: NextApiRequest, res: NextApiResponse) => { if (req.method === "POST") { - const praisalRequest: { quantity: number; type_id: number }[] = JSON.parse( - req.body - ); + logger.info({ + event: 'praisal_request_start' + }); + try { + const praisalRequest: { quantity: number; type_id: number }[] = JSON.parse( + req.body + ); + + logger.info({ + event: 'praisal_request_parsed', + items: praisalRequest.length + }); + const praisal = await getPraisal(praisalRequest); + + logger.info({ + event: 'praisal_request_success', + items: praisalRequest.length + }); + return res.json(praisal); } catch (e) { - console.log(e); - res.status(404).end(); + logger.error({ + event: 'praisal_request_failed', + error: e, + body: req.body + }); + return res.status(500).json({ error: 'Failed to get praisal' }); } } else { + logger.warn({ + event: 'invalid_method', + method: req.method, + path: req.url + }); res.status(404).end(); } }; diff --git a/src/pages/api/refresh.ts b/src/pages/api/refresh.ts index ae916bd..962654a 100644 --- a/src/pages/api/refresh.ts +++ b/src/pages/api/refresh.ts @@ -1,7 +1,8 @@ import { AccessToken } from "@/types"; -import { extractCharacterFromToken } from "@/utils"; +import { extractCharacterFromToken } from "@/utils/utils"; import { NextApiRequest, NextApiResponse } from "next"; import crypto from "crypto-js"; +import logger from "@/utils/logger"; const EVE_SSO_TOKEN_URL = "https://login.eveonline.com/v2/oauth/token"; const EVE_SSO_CLIENT_ID = process.env.EVE_SSO_CLIENT_ID ?? ""; @@ -10,6 +11,14 @@ const EVE_SSO_SECRET = process.env.EVE_SSO_SECRET ?? ""; const handler = async (req: NextApiRequest, res: NextApiResponse) => { if (req.method === "POST") { const accessToken: AccessToken = req.body; + logger.info({ + event: 'token_refresh_start', + character: { + name: accessToken.character.name, + characterId: accessToken.character.characterId + } + }); + const params = new URLSearchParams({ grant_type: "refresh_token", refresh_token: crypto.AES.decrypt( @@ -33,7 +42,20 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { body: params, headers, }).then((res) => res.json()); + const character = extractCharacterFromToken(response); + if (!character) { + logger.error({ + event: 'token_refresh_failed', + reason: 'character_extraction_failed', + character: { + name: accessToken.character.name, + characterId: accessToken.character.characterId + } + }); + return res.json({ ...accessToken, needsLogin: true }); + } + const token: AccessToken = { access_token: response.access_token, token_type: response.token_type, @@ -51,12 +73,26 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { planetConfig: accessToken.planetConfig ?? [], }; - console.log("Refresh", character.name, character.characterId); + logger.info({ + event: 'token_refresh_success', + character: { + name: character.name, + characterId: character.characterId + } + }); return res.json(token); } catch (e) { - console.log(e); - res.json({ ...accessToken, needsLogin: true }); + logger.error({ + event: 'token_refresh_failed', + reason: 'api_error', + error: e, + character: { + name: accessToken.character.name, + characterId: accessToken.character.characterId + } + }); + return res.json({ ...accessToken, needsLogin: true }); } } else { res.status(404).end(); diff --git a/src/pages/api/revoke.ts b/src/pages/api/revoke.ts index 70d7793..37704ea 100644 --- a/src/pages/api/revoke.ts +++ b/src/pages/api/revoke.ts @@ -1,6 +1,7 @@ import { AccessToken } from "@/types"; import { NextApiRequest, NextApiResponse } from "next"; import crypto from "crypto-js"; +import logger from "@/utils/logger"; const EVE_SSO_REVOKE_URL = "https://login.eveonline.com/v2/oauth/revoke"; const EVE_SSO_CLIENT_ID = process.env.EVE_SSO_CLIENT_ID ?? ""; @@ -9,6 +10,14 @@ const EVE_SSO_SECRET = process.env.EVE_SSO_SECRET ?? ""; const handler = async (req: NextApiRequest, res: NextApiResponse) => { if (req.method === "POST") { const accessToken: AccessToken = req.body; + logger.info({ + event: 'token_revoke_start', + character: { + name: accessToken.character.name, + characterId: accessToken.character.characterId + } + }); + const params = new URLSearchParams({ grant_type: "refresh_token", refresh_token: crypto.AES.decrypt( @@ -27,24 +36,42 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { }; try { - await fetch(EVE_SSO_REVOKE_URL, { + const response = await fetch(EVE_SSO_REVOKE_URL, { method: "POST", body: params, headers, - }).then((res) => res.json()); + }); - console.log( - "Revoke", - accessToken.character.name, - accessToken.character.characterId - ); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + logger.info({ + event: 'token_revoke_success', + character: { + name: accessToken.character.name, + characterId: accessToken.character.characterId + } + }); return res.end(); } catch (e) { - console.log(e); + logger.error({ + event: 'token_revoke_failed', + error: e, + character: { + name: accessToken.character.name, + characterId: accessToken.character.characterId + } + }); return res.status(500).end(); } } else { + logger.warn({ + event: 'invalid_method', + method: req.method, + path: req.url + }); res.status(404).end(); } }; diff --git a/src/pages/api/token.ts b/src/pages/api/token.ts index 4bf1d1d..c85d36c 100644 --- a/src/pages/api/token.ts +++ b/src/pages/api/token.ts @@ -1,7 +1,8 @@ import { AccessToken } from "@/types"; -import { extractCharacterFromToken } from "@/utils"; +import { extractCharacterFromToken } from "@/utils/utils"; import { NextApiRequest, NextApiResponse } from "next"; import crypto from "crypto-js"; +import logger from "@/utils/logger"; const EVE_SSO_TOKEN_URL = "https://login.eveonline.com/v2/oauth/token"; const EVE_SSO_CLIENT_ID = process.env.EVE_SSO_CLIENT_ID ?? ""; @@ -10,7 +11,19 @@ const EVE_SSO_SECRET = process.env.EVE_SSO_SECRET ?? ""; const handler = async (req: NextApiRequest, res: NextApiResponse) => { if (req.method === "GET") { const code = req.query.code as string; - if (!code || code === undefined) return res.status(404).end(); + if (!code || code === undefined) { + logger.warn({ + event: 'token_request_failed', + reason: 'missing_code', + query: req.query + }); + return res.status(404).end(); + } + + logger.info({ + event: 'token_request_start', + code: code + }); const params = new URLSearchParams({ grant_type: "authorization_code", @@ -26,34 +39,69 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { "User-Agent": "https://github.com/calli-eve/eve-pi", }; - const response = await fetch(EVE_SSO_TOKEN_URL, { - method: "POST", - body: params, - headers, - }).then((res) => res.json()); + try { + const response = await fetch(EVE_SSO_TOKEN_URL, { + method: "POST", + body: params, + headers, + }); - const character = extractCharacterFromToken(response); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } - console.log("Login", character.name, character.characterId); + const data = await response.json(); + const character = extractCharacterFromToken(data); - const token: AccessToken = { - access_token: response.access_token, - token_type: response.token_type, - refresh_token: crypto.AES.encrypt( - response.refresh_token, - EVE_SSO_SECRET, - ).toString(), - expires_at: Date.now() + response.expires_in * 1000, - character, - needsLogin: false, - account: "-", - comment: "", - system: "", - planets: [], - planetConfig: [], - }; - res.json(token); + if (!character) { + logger.error({ + event: 'token_request_failed', + reason: 'character_extraction_failed', + data + }); + return res.status(500).end(); + } + + logger.info({ + event: 'token_request_success', + character: { + name: character.name, + characterId: character.characterId + } + }); + + const token: AccessToken = { + access_token: data.access_token, + token_type: data.token_type, + refresh_token: crypto.AES.encrypt( + data.refresh_token, + EVE_SSO_SECRET, + ).toString(), + expires_at: Date.now() + data.expires_in * 1000, + character, + needsLogin: false, + account: "-", + comment: "", + system: "", + planets: [], + planetConfig: [], + }; + return res.json(token); + } catch (e) { + logger.error({ + event: 'token_request_failed', + reason: 'api_error', + error: e, + code: code + }); + return res.status(500).end(); + } } else { + logger.warn({ + event: 'invalid_method', + method: req.method, + path: req.url + }); res.status(404).end(); } }; diff --git a/src/utils.ts b/src/utils.ts deleted file mode 100644 index be874d5..0000000 --- a/src/utils.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { AccessToken, Character } from "./types"; - -export const extractCharacterFromToken = (token: AccessToken): Character => { - const decodedToken = parseJwt(token.access_token); - return { - name: decodedToken.name, - characterId: decodedToken.sub.split(":")[2], - }; -}; - -const parseJwt = (token: string) => { - return JSON.parse(Buffer.from(token.split(".")[1], "base64").toString()); -}; diff --git a/src/utils/logger.ts b/src/utils/logger.ts new file mode 100644 index 0000000..4f62aee --- /dev/null +++ b/src/utils/logger.ts @@ -0,0 +1,18 @@ +import pino from 'pino'; + +const logger = pino({ + level: process.env.LOG_LEVEL || 'info', + transport: { + target: 'pino-pretty', + options: { + colorize: true, + translateTime: 'SYS:standard', + ignore: 'pid,hostname', + }, + }, + base: { + env: process.env.NODE_ENV, + }, +}); + +export default logger; \ No newline at end of file diff --git a/src/utils/utils.ts b/src/utils/utils.ts new file mode 100644 index 0000000..80a2182 --- /dev/null +++ b/src/utils/utils.ts @@ -0,0 +1,22 @@ +import { AccessToken, Character } from "../types"; + +export const extractCharacterFromToken = (token: AccessToken): Character | null => { + const decodedToken = parseJwt(token.access_token); + if (!decodedToken || !decodedToken.name || !decodedToken.sub) { + return null; + } + return { + name: decodedToken.name, + characterId: decodedToken.sub.split(":")[2], + }; +}; + +const parseJwt = (token: string | undefined) => { + if (!token) return null; + try { + return JSON.parse(Buffer.from(token.split(".")[1], "base64").toString()); + } catch (error) { + console.error('Failed to parse JWT token:', error); + return null; + } +};