diff --git a/bun.lock b/bun.lock index 2ba8e76..37fb69c 100644 --- a/bun.lock +++ b/bun.lock @@ -13,6 +13,7 @@ "bearer": "^0.0.20", "elysia": "^1.2.25", "elysia-http-error": "^1.3.0", + "winston": "^3.18.3", }, "devDependencies": { "bun-types": "latest", @@ -20,6 +21,10 @@ }, }, "packages": { + "@colors/colors": ["@colors/colors@1.6.0", "", {}, "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA=="], + + "@dabh/diagnostics": ["@dabh/diagnostics@2.0.8", "", { "dependencies": { "@so-ric/colorspace": "^1.1.6", "enabled": "2.0.x", "kuler": "^2.0.0" } }, "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q=="], + "@elysiajs/bearer": ["@elysiajs/bearer@1.3.0", "", { "peerDependencies": { "elysia": ">= 1.3.0" } }, "sha512-isi/dxBgXdITDtrzC152uPrGicbjjuAkKwawGhIlHiughnnm0k7fEfDk7atiGYp0g21+/qZU2jhaxEx609wtLQ=="], "@elysiajs/opentelemetry": ["@elysiajs/opentelemetry@1.3.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/instrumentation": "^0.200.0", "@opentelemetry/sdk-node": "^0.200.0" }, "peerDependencies": { "elysia": ">= 1.3.0" } }, "sha512-KFb00Hmec4jHRm9kAF8rZedJIjZ7VNk5ZrGsusb1jRZ+V5BOryJ+yp8/sGbjq4rqxmd78zjtPWPAht7wRDDfbA=="], @@ -116,6 +121,8 @@ "@sinclair/typebox": ["@sinclair/typebox@0.34.33", "", {}, "sha512-5HAV9exOMcXRUxo+9iYB5n09XxzCXnfy4VTNW4xnDv+FgjzAGY989C28BIdljKqmF+ZltUwujE3aossvcVtq6g=="], + "@so-ric/colorspace": ["@so-ric/colorspace@1.1.6", "", { "dependencies": { "color": "^5.0.2", "text-hex": "1.0.x" } }, "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw=="], + "@supabase/auth-js": ["@supabase/auth-js@2.69.1", "", { "dependencies": { "@supabase/node-fetch": "^2.6.14" } }, "sha512-FILtt5WjCNzmReeRLq5wRs3iShwmnWgBvxHfqapC/VoljJl+W8hDAyFmf1NVw3zH+ZjZ05AKxiKxVeb0HNWRMQ=="], "@supabase/functions-js": ["@supabase/functions-js@2.4.4", "", { "dependencies": { "@supabase/node-fetch": "^2.6.14" } }, "sha512-WL2p6r4AXNGwop7iwvul2BvOtuJ1YQy8EbOd0dhG1oN1q8el/BIRSFCFnWAMM/vJJlHWLi4ad22sKbKr9mvjoA=="], @@ -136,6 +143,8 @@ "@types/shimmer": ["@types/shimmer@1.2.0", "", {}, "sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg=="], + "@types/triple-beam": ["@types/triple-beam@1.3.5", "", {}, "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="], + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], "@unhead/schema": ["@unhead/schema@1.11.20", "", { "dependencies": { "hookable": "^5.5.3", "zhead": "^2.2.4" } }, "sha512-0zWykKAaJdm+/Y7yi/Yds20PrUK7XabLe9c3IRcjnwYmSWY6z0Cr19VIs3ozCj8P+GhR+/TI2mwtGlueCEYouA=="], @@ -148,6 +157,8 @@ "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], + "bearer": ["bearer@0.0.20", "", { "dependencies": { "node-cryptojs-aes": "~0.4.0" } }, "sha512-ncwiK5GXjTn7slWowxZg4XpRfrpB1acgCCfJqH+5LyN1szZBoEh+qndCp8TqTP6LqG2HgtxSiRWRjkMja1rVhg=="], "bun-types": ["bun-types@1.2.9", "", { "dependencies": { "@types/node": "*", "@types/ws": "*" } }, "sha512-dk/kOEfQbajENN/D6FyiSgOKEuUi9PWfqKQJEgwKrCMWbjS/S6tEXp178mWvWAcUSYm9ArDlWHZKO3T/4cLXiw=="], @@ -156,9 +167,13 @@ "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], - "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + "color": ["color@5.0.2", "", { "dependencies": { "color-convert": "^3.0.1", "color-string": "^2.0.0" } }, "sha512-e2hz5BzbUPcYlIRHo8ieAhYgoajrJr+hWoceg6E345TPsATMUKqDgzt8fSXZJJbxfpiPzkWyphz8yn8At7q3fA=="], + + "color-convert": ["color-convert@3.1.2", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-UNqkvCDXstVck3kdowtOTWROIJQwafjOfXSmddoDrXo4cewMKmusCeF22Q24zvjR8nwWib/3S/dfyzPItPEiJg=="], + + "color-name": ["color-name@2.0.2", "", {}, "sha512-9vEt7gE16EW7Eu7pvZnR0abW9z6ufzhXxGXZEVU9IqPdlsUiMwJeJfRtq0zePUmnbHGT9zajca7mX8zgoayo4A=="], - "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + "color-string": ["color-string@2.1.2", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-RxmjYxbWemV9gKu4zPgiZagUxbH3RQpEIO77XoSSX0ivgABDZ+h8Zuash/EMFLTI4N9QgFPOJ6JQpPZKFxa+dA=="], "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], @@ -170,8 +185,14 @@ "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "enabled": ["enabled@2.0.0", "", {}, "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="], + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "fecha": ["fecha@4.2.3", "", {}, "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="], + + "fn.name": ["fn.name@1.1.0", "", {}, "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="], + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], @@ -182,12 +203,20 @@ "import-in-the-middle": ["import-in-the-middle@1.13.2", "", { "dependencies": { "acorn": "^8.14.0", "acorn-import-attributes": "^1.9.5", "cjs-module-lexer": "^1.2.2", "module-details-from-path": "^1.0.3" } }, "sha512-Yjp9X7s2eHSXvZYQ0aye6UvwYPrVB5C2k47fuXjFKnYinAByaDZjh4t9MT2wEga9775n6WaIqyHnQhBxYtX2mg=="], + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + + "kuler": ["kuler@2.0.0", "", {}, "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="], + "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], + "logform": ["logform@2.7.0", "", { "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" } }, "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ=="], + "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], "memoirist": ["memoirist@0.3.0", "", {}, "sha512-wR+4chMgVPq+T6OOsk40u9Wlpw1Pjx66NMNiYxCQQ4EUJ7jDs3D9kTCeKdBOkvAiqXlHLVJlvYL01PvIJ1MPNg=="], @@ -200,6 +229,8 @@ "node-cryptojs-aes": ["node-cryptojs-aes@0.4.0", "", {}, "sha512-fLUhIYUwZNhvp4eDmDfTMXCQSthkgIkKFlrRVdKFlEnjBDiEiSkJMHwr9OjWHck7BTwf7T1hxjswAu+baO7ygg=="], + "one-time": ["one-time@1.0.0", "", { "dependencies": { "fn.name": "1.x.x" } }, "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g=="], + "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], @@ -208,32 +239,52 @@ "protobufjs": ["protobufjs@7.4.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw=="], + "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], "require-in-the-middle": ["require-in-the-middle@7.5.2", "", { "dependencies": { "debug": "^4.3.5", "module-details-from-path": "^1.0.3", "resolve": "^1.22.8" } }, "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ=="], "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], + "shimmer": ["shimmer@1.2.1", "", {}, "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw=="], + "stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="], + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + "text-hex": ["text-hex@1.0.0", "", {}, "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="], + "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + "triple-beam": ["triple-beam@1.4.1", "", {}, "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg=="], + "type-fest": ["type-fest@4.39.1", "", {}, "sha512-uW9qzd66uyHYxwyVBYiwS4Oi0qZyUqwjU+Oevr6ZogYiXt99EOYtwvzMSLw1c3lYo2HzJsep/NB23iEVEgjG/w=="], "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + "winston": ["winston@3.18.3", "", { "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.8", "async": "^3.2.3", "is-stream": "^2.0.0", "logform": "^2.7.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", "winston-transport": "^4.9.0" } }, "sha512-NoBZauFNNWENgsnC9YpgyYwOVrl2m58PpQ8lNHjV3kosGs7KJ7Npk9pCUE+WJlawVSe8mykWDKWFSVfs3QO9ww=="], + + "winston-transport": ["winston-transport@4.9.0", "", { "dependencies": { "logform": "^2.7.0", "readable-stream": "^3.6.2", "triple-beam": "^1.3.0" } }, "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A=="], + "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], "ws": ["ws@8.18.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w=="], @@ -360,6 +411,8 @@ "@scalar/themes/@scalar/types": ["@scalar/types@0.1.7", "", { "dependencies": { "@scalar/openapi-types": "0.2.0", "@unhead/schema": "^1.11.11", "nanoid": "^5.1.5", "type-fest": "^4.20.0", "zod": "^3.23.8" } }, "sha512-irIDYzTQG2KLvFbuTI8k2Pz/R4JR+zUUSykVTbEMatkzMmVFnn1VzNSMlODbadycwZunbnL2tA27AXed9URVjw=="], + "ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + "@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/otlp-transformer/@opentelemetry/resources": ["@opentelemetry/resources@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-rnZr6dML2z4IARI4zPGQV4arDikF/9OXZQzrC01dLmn0CZxU5U5OLd/m1T7YkGRj5UitjeoCtg/zorlgMQcdTg=="], "@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/otlp-transformer/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw=="], @@ -385,5 +438,7 @@ "@opentelemetry/sdk-node/@opentelemetry/sdk-trace-node/@opentelemetry/context-async-hooks": ["@opentelemetry/context-async-hooks@2.0.0", "", { "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-IEkJGzK1A9v3/EHjXh3s2IiFc6L4jfK+lNgKVgUjeUJQRRhnVFMIO3TAvKwonm9O1HebCuoOt98v8bZW7oVQHA=="], "@scalar/themes/@scalar/types/@scalar/openapi-types": ["@scalar/openapi-types@0.2.0", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-waiKk12cRCqyUCWTOX0K1WEVX46+hVUK+zRPzAahDJ7G0TApvbNkuy5wx7aoUyEk++HHde0XuQnshXnt8jsddA=="], + + "ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], } } diff --git a/package.json b/package.json index 9a972a3..844d476 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "@supabase/supabase-js": "^2.49.4", "bearer": "^0.0.20", "elysia": "^1.2.25", - "elysia-http-error": "^1.3.0" + "elysia-http-error": "^1.3.0", + "winston": "^3.18.3" }, "devDependencies": { "bun-types": "latest" diff --git a/src/data/relations.ts b/src/data/relations.ts index 57a5e54..3db060f 100644 --- a/src/data/relations.ts +++ b/src/data/relations.ts @@ -1,4 +1,8 @@ import { HttpError } from 'elysia-http-error'; +import { getLogger } from '../services/logger'; +import { Logger } from 'winston'; + +const logger: Logger = getLogger('relationData'); export async function createUserNode(bearer: string): Promise { const userUrl = (process.env.LIKE_URL || 'http://localhost:3000') + '/userNode'; @@ -12,12 +16,12 @@ export async function createUserNode(bearer: string): Promise { try { await fetch(request); } catch (error) { - console.error('Error creating user node:', error); + logger.error(`Error creating user node: ${error}`); throw new HttpError('Error creating user node', 500); } } -export async function fetchRecommendedCollocs(bearer: string): Promise<{userIds: string[]}> { +export async function fetchRecommendedCollocs(bearer: string): Promise { const userUrl = (process.env.LIKE_URL || 'http://localhost:3000') + '/recommendedColloc'; const request = new Request(userUrl, { method: 'get', @@ -29,7 +33,7 @@ export async function fetchRecommendedCollocs(bearer: string): Promise<{userIds: try { return await (await fetch(request)).json(); } catch (error) { - console.error('Error getting recommended Collocs:', error); + logger.error(`Error getting recommended Collocs: ${error}`); throw new HttpError('Error getting recommended Collocs', 500); } } diff --git a/src/data/user.ts b/src/data/user.ts index 93e6a0d..10662fb 100644 --- a/src/data/user.ts +++ b/src/data/user.ts @@ -2,134 +2,123 @@ import { Session } from '@supabase/supabase-js'; import { supabase } from '../libs/supabase'; import User from '../models/user'; import RegisterResponse from '../routes/responses/register'; +import { getLogger } from '../services/logger'; +import { Logger } from 'winston'; -async function authenticateUser(email: string, password: string): Promise { +const logger: Logger = getLogger('UserData') + +export async function authenticateUser(email: string, password: string): Promise { const { data, error } = await supabase.auth.signUp({ email: email, password: password, }); if (error) { - console.error('authenticateUse: Error creating user:', error); + logger.error(`authenticateUse: Error creating user: ${error}`); throw error; } return data.user!.id; } -async function refreshUser(bearer: string): Promise { +export async function refreshUser(bearer: string): Promise { const { data, error } = await supabase.auth.refreshSession({ refresh_token: bearer }); if (error) { - console.error('Error refreshing user session:', error); + logger.error(`Error refreshing user session: ${error}`); throw error; } return data.session; } -async function loginUser(email: string, password: string): Promise { - console.log('Loggin in user: ', email); +export async function loginUser(email: string, password: string): Promise { + logger.info(`Loggin in user: ${email}`); const { data, error } = await supabase.auth.signInWithPassword({ email: email, password: password, }); if (error) { - console.error('Error logging in user:', error); + logger.error(`Error logging in user: ${error}`); throw error; } - console.log('Login data: ', data); + logger.info(`Login data: ${data}`); return data.session; } -async function createUser(user: User): Promise { - console.log('Creating user: ', user); +export async function createUser(user: User): Promise { + logger.info(`Creating user: ${user}`); const { error } = await supabase.from('users').insert([user]); if (error) { - console.error('creatingUser: Error creating user:', error); + logger.error(`Error creating user: ${error}`); throw error; } } -async function createprofilePictureSignedUploadUrl(userId: string): Promise { +export async function createprofilePictureSignedUploadUrl(userId: string): Promise { const { data, error } = await supabase.storage .from('user-pictures') - .createSignedUploadUrl(`${userId}.png`); + .createSignedUploadUrl(`${userId}.jpeg`); if (error) { - console.error('creatingUser: Error creating user:', error); + logger.error(`creatingUser: Error creating user: ${error}`); throw error; } - console.log(data); return new RegisterResponse(data.path, data.token); } -async function resendEmail(email: string): Promise { +export async function resendEmail(email: string): Promise { const { error } = await supabase.auth.resend({ email: email, type: 'signup', }); if (error) { - console.error('Error resending verification email:', error); + logger.error(`Error resending verification email: ${error}`); throw error; } } -async function sendResetPassword(email: string): Promise { +export async function sendResetPassword(email: string): Promise { const { error } = await supabase.auth.resetPasswordForEmail(email); if (error) { - console.error('Error sending password reset email:', error); + logger.error(`Error sending password reset email: ${error}`); throw error; } } -async function getUserById(id: string): Promise { +export async function getUserById(id: string): Promise { const { data, error } = await supabase.from('users').select('*').eq('id', id); if (error) { - console.error('Error getting user:', error); + logger.error(`Error getting user: ${error}`); throw error; } return data[0]; } -async function getAllUsers(): Promise { +export async function getAllUsers(): Promise { const { data, error } = await supabase.from('users').select('*'); if (error) { - console.error('Error getting all users:', error); + logger.error(`Error getting all users: ${error}`); throw error; } return data; } -async function checkUser(bearer: string): Promise { +export async function checkUser(bearer: string): Promise { const { data, error } = await supabase.auth.getUser(bearer); if (error) { - console.error('Error checking user:', error); + logger.error(`Error checking user: ${error}`); throw error; } return data.user.id; } -async function emailExist(email: string): Promise { +export async function emailExist(email: string): Promise { const { data: { users }, error, } = await supabase.auth.admin.listUsers(); if (error) { - console.error('Error checking user:', error); + logger.error(`Error checking user: ${error}`); throw error; } return users.some((user) => user.email === email); } - -export { - authenticateUser, - refreshUser, - loginUser, - createUser, - resendEmail, - sendResetPassword, - emailExist, - getAllUsers, - getUserById, - checkUser, - createprofilePictureSignedUploadUrl, -}; diff --git a/src/routes/index.ts b/src/routes/index.ts index 23eaf1f..a8525a2 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -1,82 +1,51 @@ import { Elysia, t } from 'elysia'; -import { allUsers, getRecommendedCollocs, userById } from '../services/info_service'; import { register, login, resendVerification, resetPassword, - checkEmailExist, verifyUser, getNewSession, -} from '../services/authentication_service'; -import { HttpError } from 'elysia-http-error'; +} from '../services/authenticationService'; import bearer from '@elysiajs/bearer'; -import { AuthApiError } from '@supabase/supabase-js'; +import { checkEmailExist, getRecommendedCollocs, userById } from '../services/infoService'; +import { handleError, handleMissingBearer } from '../services/responseService'; const userRoutes = new Elysia(); -// This route should not be exposed out of the app -userRoutes.get('/', async () => { - return await allUsers(); -}); - userRoutes.use(bearer()).get( - '/:id', - async ({ bearer, params }) => { + '/', + async ({ bearer, query }) => { try { await verifyUser(bearer); - return await userById(params.id); + return await userById(query.id); } catch (error) { - if (error instanceof HttpError) { - return new Response(`{message: ${error.message}}`, { - status: error.statusCode, - headers: { 'Content-Type': 'application/json' }, - }); - } - throw error; + return handleError(error); } }, { beforeHandle({ bearer, set }) { - if (!bearer) { - set.headers['WWW-Authenticate'] = `Bearer realm='sign', error="invalid_request"`; - return new Response(`{message: \"Bearer not found or invalid"}`, { - status: 401, - headers: { 'Content-Type': 'application/json' }, - }); - } + if (!bearer) handleMissingBearer(set); }, - params: t.Object({ + query: t.Object({ id: t.String(), }), }, ); userRoutes.use(bearer()).get( - '/id', + '/check', async ({ bearer }) => { try { const id: string = await verifyUser(bearer); return await userById(id); } catch (error) { - if (error instanceof HttpError) { - return new Response(`{message: ${error.message}}`, { - status: error.statusCode, - headers: { 'Content-Type': 'application/json' }, - }); - } - throw error; + return handleError(error); } }, { beforeHandle({ bearer, set }) { - if (!bearer) { - set.headers['WWW-Authenticate'] = `Bearer realm='sign', error="invalid_request"`; - return new Response(`{message: \"Bearer not found or invalid"}`, { - status: 401, - headers: { 'Content-Type': 'application/json' }, - }); - } + if (!bearer) handleMissingBearer(set); }, }, ); @@ -87,24 +56,12 @@ userRoutes.use(bearer()).get( try { return await getNewSession(bearer); } catch (error) { - if (error instanceof HttpError) { - return new Response(`{message: ${error.message}}`, { - status: error.statusCode, - headers: { 'Content-Type': 'application/json' }, - }); - } - throw error; + return handleError(error); } }, { beforeHandle({ bearer, set }) { - if (!bearer) { - set.headers['WWW-Authenticate'] = `Bearer realm='sign', error="invalid_request"`; - return new Response(`{message: \"Bearer not found or invalid"}`, { - status: 401, - headers: { 'Content-Type': 'application/json' }, - }); - } + if (!bearer) handleMissingBearer(set); }, }, ); @@ -112,14 +69,11 @@ userRoutes.use(bearer()).get( userRoutes.post( '/register', async ({ body }) => { - var resp = await register(body); - if (resp instanceof HttpError) { - return new Response(`{message: ${resp.message}}`, { - status: resp.statusCode, - headers: { 'Content-Type': 'application/json' }, - }); + try { + return await register(body); + } catch (error) { + return handleError(error); } - return resp; }, { body: t.Object({ @@ -143,17 +97,14 @@ userRoutes.post( userRoutes.post( '/resend', async ({ body }) => { - var resp = await resendVerification(body.email); - if (resp instanceof HttpError) { - return new Response(`{message: ${resp.message}}`, { - status: resp.statusCode, - headers: { 'Content-Type': 'application/json' }, - }); - } else { + try{ + await resendVerification(body.email); return new Response('{"status":"OK"}', { status: 200, headers: { 'Content-Type': 'application/json' }, }); + } catch(error) { + return handleError(error); } }, { @@ -168,19 +119,9 @@ userRoutes.post( '/login', async ({ body }) => { try { - var resp = await login(body.email, body.password); - if (resp instanceof AuthApiError) { - return HttpError.Unauthorized(resp.message); - } - return resp; + return await login(body.email, body.password); } catch (error) { - if (error instanceof HttpError) { - return new Response(`{message: ${error.message}}`, { - status: error.statusCode, - headers: { 'Content-Type': 'application/json' }, - }); - } - throw error; + return handleError(error); } }, { @@ -193,27 +134,22 @@ userRoutes.post( }, ); -userRoutes.get( - '/forgotPassword/:email', - async ({ params }) => { +userRoutes.post( + '/forgotPassword/', + async ({ body }) => { try { - await resetPassword(params.email); + + await resetPassword(body.email); return new Response('{"status":"OK"}', { status: 200, headers: { 'Content-Type': 'application/json' }, }); } catch (error) { - if (error instanceof HttpError) { - return new Response(`{message: ${error.message}}`, { - status: error.statusCode, - headers: { 'Content-Type': 'application/json' }, - }); - } - throw error; + return handleError(error); } }, { - params: t.Object({ + body: t.Object({ email: t.String({ format: 'email', }), @@ -221,21 +157,28 @@ userRoutes.get( }, ); -userRoutes.get('/checkEmail/:email', async ({ params }) => { - const resp = await checkEmailExist(params.email); - return new Response(JSON.stringify({ emailTaken: resp }), { - status: 200, - headers: { 'Content-Type': 'application/json' }, - }); -}); +userRoutes.get('/checkEmail', async ({ query }) => { + const resp = await checkEmailExist(query.email); + return new Response(JSON.stringify({ emailTaken: resp }), { + status: 200, + headers: { 'Content-Type': 'application/json' }, + }); + }, + { + body: t.Object({ + email: t.String({ + format: 'email', + }), + }), + }, +); userRoutes.use(bearer()).get('/recommendedColloc', async ({ bearer }) => { const id: string = await verifyUser(bearer); if (!id) { return new Response("User do not exist", { status: 401, headers: { 'Content-Type': 'application/json' } }); } - var ret = await getRecommendedCollocs(bearer); - return new Response(JSON.stringify(ret), {status: 200, headers: { 'Content-Type': 'application/json' }}); + return await getRecommendedCollocs(bearer); }, { beforeHandle({ bearer, set }) { diff --git a/src/services/authenticationService.ts b/src/services/authenticationService.ts new file mode 100644 index 0000000..cc8bb1d --- /dev/null +++ b/src/services/authenticationService.ts @@ -0,0 +1,86 @@ +import { + authenticateUser, + checkUser, + createprofilePictureSignedUploadUrl, + createUser, + loginUser, + refreshUser, + resendEmail, + sendResetPassword, +} from '../data/user'; +import RegisterRequest from '../routes/requests/register'; +import LoginResponse from '../routes/responses/login'; +import User from '../models/user'; +import { HttpError } from 'elysia-http-error'; +import { Session } from '@supabase/supabase-js'; +import { createUserNode } from '../data/relations'; +import { getLogger } from './logger'; +import { Logger } from 'winston'; +import { handleResponse } from './responseService'; + +const logger: Logger = getLogger('Authentication'); + + +export async function register(request: RegisterRequest): Promise { + passwordCheck(request.password); + logger.info(`Creating user: ${request.email}`); + var id: string = await authenticateUser(request.email, request.password); + logger.info(`Successfully authenticater user: ${id}`); + await createUser(new User(id, request.firstName, request.lastName, request.birthdate)); + const registerResponse = await createprofilePictureSignedUploadUrl(id); + return handleResponse(JSON.stringify(registerResponse), 200); +} + +export async function login(email: string, password: string): Promise { + logger.info(`Login in user: ${email}`); + var session = await loginUser(email, password); + await createUserNode(session.access_token); + var response = new LoginResponse(session); + logger.info(`Response: ${response}`); + return handleResponse(JSON.stringify(response), 200); +} + +export async function resendVerification(email: string): Promise { + logger.info(`Resending verification email to: ${email}`); + await resendEmail(email); + return handleResponse('{"status": "OK"}', 200); +} + +function passwordCheck(password: string): Response { + if (password.length < 8) { + throw HttpError.BadRequest('Password must be at least 8 characters long.', { status: 400 }); + } + var regex = /^(.*[0-9].*)$/; + if (!regex.test(password)) { + throw HttpError.BadRequest('Password must contain at least one number.', { status: 400 }); + } + var regex = /^(.*[-!@#$%_^&*].*)$/; + if (!regex.test(password)) { + throw HttpError.BadRequest('Password must contain at least special character.', { + status: 400, + }); + } + return handleResponse('{"status": "OK"}', 200); +} + +export async function resetPassword(email: string): Promise { + return handleResponse(JSON.stringify(await sendResetPassword(email)), 200); +} + + +export async function verifyUser(bearer: string): Promise { + const id: string = await checkUser(bearer); + if (!id) { + throw HttpError.Unauthorized('Unauthorized', { status: 401 }); + } + return id; +} + +export async function getNewSession(bearer: string): Promise { + const ret: Session | null = await refreshUser(bearer); + if (!ret) { + throw HttpError.Unauthorized('Unauthorized', { status: 401 }); + } + return handleResponse(JSON.stringify(ret),200); +} + diff --git a/src/services/authentication_service.ts b/src/services/authentication_service.ts deleted file mode 100644 index 444a9f1..0000000 --- a/src/services/authentication_service.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { - authenticateUser, - checkUser, - createprofilePictureSignedUploadUrl, - createUser, - emailExist, - loginUser, - refreshUser, - resendEmail, - sendResetPassword, -} from '../data/user'; -import RegisterRequest from '../routes/requests/register'; -import LoginResponse from '../routes/responses/login'; -import User from '../models/user'; -import { HttpError } from 'elysia-http-error'; -import { AuthApiError, Session } from '@supabase/supabase-js'; -import { createUserNode } from '../data/relations'; - -async function register(request: RegisterRequest): Promise { - try { - passwordCheck(request.password); - } catch (error) { - console.log('Password check failed: ', error); - return error; - } - console.log('Creating user:', request.email); - var id: string = await authenticateUser(request.email, request.password); - console.log('Successfully authenticater user: ', id); - await createUser(new User(id, request.firstName, request.lastName, request.birthdate)); - - const registerResponse = await createprofilePictureSignedUploadUrl(id); - return JSON.stringify(registerResponse); -} - -async function login(email: string, password: string): Promise { - try { - console.log('Login in user:', email); - var session = await loginUser(email, password); - await createUserNode(session.access_token); - var response = new LoginResponse(session); - console.log('Response: ' + response); - return JSON.stringify(response); - } catch (error) { - const catchedErrors = ['Invalid login credentials', 'Email not confirmed']; - - if (error instanceof AuthApiError && catchedErrors.includes(error.message)) { - return error; - } - throw error; - } -} - -async function resendVerification(email: string): Promise { - try { - console.log('Resending verification email to: ', email); - await resendEmail(email); - } catch (error) { - console.error('Error resending verification email:', error); - return error; - } -} - -function passwordCheck(password: string): void { - if (password.length < 8) { - throw HttpError.BadRequest('Password must be at least 8 characters long.', { status: 400 }); - } - var regex = /^(.*[0-9].*)$/; - if (!regex.test(password)) { - throw HttpError.BadRequest('Password must contain at least one number.', { status: 400 }); - } - var regex = /^(.*[-!@#$%_^&*].*)$/; - if (!regex.test(password)) { - throw HttpError.BadRequest('Password must contain at least special character.', { - status: 400, - }); - } -} - -async function resetPassword(email: string): Promise { - try { - return await sendResetPassword(email); - } catch (error) { - console.error('Error sending password reset email:', error); - throw error; - } -} - -async function checkEmailExist(email: string): Promise { - return await emailExist(email); -} - -async function verifyUser(bearer: string): Promise { - const id: string = await checkUser(bearer); - if (!id) { - throw HttpError.Unauthorized('Unauthorized', { status: 401 }); - } - return id; -} - -async function getNewSession(bearer: string): Promise { - const ret: Session | null = await refreshUser(bearer); - if (!ret) { - throw HttpError.Unauthorized('Unauthorized', { status: 401 }); - } - return ret; -} - -export { - register, - login, - resendVerification, - resetPassword, - checkEmailExist, - verifyUser, - passwordCheck, - getNewSession, -}; diff --git a/src/services/infoService.ts b/src/services/infoService.ts new file mode 100644 index 0000000..6cb818b --- /dev/null +++ b/src/services/infoService.ts @@ -0,0 +1,31 @@ +import { Logger } from 'winston'; +import { fetchRecommendedCollocs } from '../data/relations'; +import { getUserById, getAllUsers, emailExist } from '../data/user'; +import User from '../models/user'; +import { getLogger } from './logger'; +import { handleResponse } from './responseService'; + +const logger: Logger = getLogger('Information') + +export async function userById(id: string): Promise { + + var user: User = await getUserById(id); + return handleResponse(JSON.stringify(user), 200); +} + +export async function allUsers(): Promise { + return handleResponse(JSON.stringify(await getAllUsers()), 200); +} + +export async function getRecommendedCollocs(bearer: string): Promise { + var userIds : string[] = await fetchRecommendedCollocs(bearer); + var users: User[] = []; + for (const id of userIds) { + users.push(await getUserById(id)); + } + return handleResponse(JSON.stringify(users), 200); +} + +export async function checkEmailExist(email: string): Promise { + return handleResponse(`{"emailExist": ${(await emailExist(email))}}`,200); +} diff --git a/src/services/info_service.ts b/src/services/info_service.ts deleted file mode 100644 index 1a3fb45..0000000 --- a/src/services/info_service.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { fetchRecommendedCollocs } from '../data/relations'; -import { getUserById, getAllUsers } from '../data/user'; -import User from '../models/user'; - -export async function userById(id: string): Promise { - return await getUserById(id); -} - -export async function allUsers(): Promise { - return await getAllUsers(); -} - -export async function getRecommendedCollocs(bearer: string): Promise<{users: User[]}> { - try { - var userIds : string[] = (await fetchRecommendedCollocs(bearer)).userIds; - var users: User[] = []; - for (const id of userIds) { - users.push(await getUserById(id)); - } - return {users: users}; - } catch (error) { - console.error('Error getting recommended Collocs:', error); - throw new Error('Error getting recommended Collocs'); - } -} diff --git a/src/services/logger.ts b/src/services/logger.ts new file mode 100644 index 0000000..53c85d6 --- /dev/null +++ b/src/services/logger.ts @@ -0,0 +1,35 @@ +import winston, { Logger } from "winston"; + +const {combine, timestamp, json, label,printf } = winston.format; + +export function getLogger(name: string) : Logger{ + + const myFormat = winston.format.combine( + winston.format.colorize({ + all:true + }), + winston.format.label({ + label:`[${name}]` + }), + winston.format.timestamp({ + format:"HH:mm:ss" + }), + printf( + info => ` ${info.label} ${info.timestamp} ${info.level} : ${info.message}` + ) + ); + return winston.createLogger({ + level: process.env.LOG_LEVEL || 'info', + format: json(), + defaultMeta: { service: name }, + transports: [ + new winston.transports.File({ filename: 'error.log', level: 'error' }), + new winston.transports.Console({ format: combine( + label({ label: name }), + timestamp(), + myFormat + )}), + new winston.transports.File({ filename: 'combined.log' }), + ], + }); +} diff --git a/src/services/responseService.ts b/src/services/responseService.ts new file mode 100644 index 0000000..ee24496 --- /dev/null +++ b/src/services/responseService.ts @@ -0,0 +1,26 @@ +import { AuthApiError } from "@supabase/supabase-js"; +import { HttpError } from "elysia-http-error"; + +export function handleMissingBearer(set: any) : Response { + set.headers['WWW-Authenticate'] = `Bearer realm='sign', error="invalid_request"`; + return handleResponse(`{message: \"Bearer not found or invalid"}`, 401); +} + +export function handleError(error: any) : Response { + const catchedErrors = ['Invalid login credentials', 'Email not confirmed']; + + if (error instanceof AuthApiError && catchedErrors.includes(error.message)) { + return handleResponse(`{"Error": "${error.message}"}`, 401); + } + else if (error instanceof HttpError ) { + return handleResponse(`{"Error": "${error.message}"}`, error.statusCode); + } + return handleResponse(`{"Server Error": "${error.message}"}`, 500); +} + +export function handleResponse(content: string, status: number) : Response{ + return new Response(content, { + status: status, + headers: { 'Content-Type': 'application/json' }, + }); +}