diff --git a/mockenv b/mockenv index 412622c..55c9ba7 100644 --- a/mockenv +++ b/mockenv @@ -11,3 +11,4 @@ REDIS_PORT=[add your redis port in number ex "16747"] REDIS_PASSWORD=[add your redis password] REDIS_DB=[add your redis db in number ex "0"] OPENAI_API_KEY=[add your openai api key] +LOGTAIL_TOKEN=[add your logtail token / or it defaults to console logging] diff --git a/package.json b/package.json index f0e8457..9365e24 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,8 @@ "@aws-sdk/client-s3": "^3.723.0", "@aws-sdk/s3-request-presigner": "^3.723.0", "@hookform/resolvers": "^3.9.1", + "@logtail/node": "^0.5.2", + "@logtail/winston": "^0.5.2", "@prisma/client": "6.1.0", "@radix-ui/react-accordion": "^1.2.2", "@radix-ui/react-alert-dialog": "^1.1.4", @@ -77,6 +79,7 @@ "tsc-alias": "^1.8.10", "vaul": "^1.1.2", "weaviate-client": "^3.3.1", + "winston": "^3.17.0", "zod": "^3.24.1", "zustand": "^5.0.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eb68757..4d93c88 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,12 @@ importers: '@hookform/resolvers': specifier: ^3.9.1 version: 3.10.0(react-hook-form@7.54.2(react@19.0.0)) + '@logtail/node': + specifier: ^0.5.2 + version: 0.5.2 + '@logtail/winston': + specifier: ^0.5.2 + version: 0.5.2(winston@3.17.0) '@prisma/client': specifier: 6.1.0 version: 6.1.0(prisma@6.2.1) @@ -203,6 +209,9 @@ importers: weaviate-client: specifier: ^3.3.1 version: 3.3.1 + winston: + specifier: ^3.17.0 + version: 3.17.0 zod: specifier: ^3.24.1 version: 3.24.1 @@ -437,10 +446,17 @@ packages: resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} engines: {node: '>=6.9.0'} + '@colors/colors@1.6.0': + resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} + engines: {node: '>=0.1.90'} + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} + '@dabh/diagnostics@2.0.3': + resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==} + '@emnapi/runtime@1.3.1': resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} @@ -668,6 +684,27 @@ packages: '@js-sdsl/ordered-map@4.4.2': resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} + '@logtail/core@0.5.2': + resolution: {integrity: sha512-mkQqGFwtZ06x2xsj6kOiEZeLSlPeTDArNOEeB9Q1VHxduRHJFInG7soix8+P8xeaoJx+7itvbUySB0XBlnmLSA==} + + '@logtail/node@0.5.2': + resolution: {integrity: sha512-pSleAsbq61WdaMzYkmW+kdCfptIWmjhSvNoyAtFFuaIGNXFS2UEmnHPrvzrPxsFgBswePSGl/m1teHTeBxA+qg==} + + '@logtail/tools@0.5.2': + resolution: {integrity: sha512-1Vg0rznoDYXWYDkz8orjKNTjK5f2eUubHN6tfJ2hHKCRRHy7y+TJpIlCQg3BilVcOvMIfiy4RbrcaFTHvDQWTQ==} + + '@logtail/types@0.5.2': + resolution: {integrity: sha512-G3C3XjJPW/LJS0+sanzsNLLqXHAJkhdBR8h4zFUylOtUOevtlneenGNZFjEil+h/GOb3tUySvBuP2wl51gvf0A==} + + '@logtail/winston@0.5.2': + resolution: {integrity: sha512-eKbtw0RB1d0Cxs9qLxQskmcDjlyUolKJJluia0uNXK190SDavIY6VW/193BLSy5S7gn32V6T4kQ9yC0W6g9C9A==} + peerDependencies: + winston: '>=3.2.1' + + '@msgpack/msgpack@2.8.0': + resolution: {integrity: sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==} + engines: {node: '>= 10'} + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==} cpu: [arm64] @@ -1906,6 +1943,12 @@ packages: '@types/react@19.0.1': resolution: {integrity: sha512-YW6614BDhqbpR5KtUYzTA+zlA7nayzJRA9ljz9CQoxthR0sDisYZLuvSMsil36t4EH/uAt8T52Xb4sVw17G+SQ==} + '@types/stack-trace@0.0.33': + resolution: {integrity: sha512-O7in6531Bbvlb2KEsJ0dq0CHZvc3iWSR5ZYMtvGgnHA56VgriAN/AU2LorfmcvAl2xc9N5fbCTRyMRRl8nd74g==} + + '@types/triple-beam@1.3.5': + resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -2069,6 +2112,9 @@ packages: ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -2210,20 +2256,32 @@ packages: react: ^18.0.0 react-dom: ^18.0.0 + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} color-string@1.9.1: resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + color@3.2.1: + resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} + color@4.2.3: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + colorspace@1.1.4: + resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -2252,6 +2310,9 @@ packages: cross-fetch@3.2.0: resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==} + cross-fetch@4.1.0: + resolution: {integrity: sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -2444,6 +2505,9 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + enabled@2.0.0: + resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} + end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} @@ -2651,6 +2715,9 @@ packages: fastq@1.18.0: resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} + fecha@4.2.3: + resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -2670,6 +2737,9 @@ packages: flatted@3.3.2: resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} + fn.name@1.1.0: + resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} + follow-redirects@1.15.9: resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} engines: {node: '>=4.0'} @@ -2977,6 +3047,10 @@ packages: resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + is-string@1.1.1: resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} @@ -3060,6 +3134,9 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + kuler@2.0.0: + resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} + language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -3118,6 +3195,10 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + logform@2.7.0: + resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==} + engines: {node: '>= 12.0.0'} + long@5.2.4: resolution: {integrity: sha512-qtzLbJE8hq7VabR3mISmVGtoXP8KGc2Z/AT8OuqlYD7JTR3oqrgwdjnk07wpj1twXxYmgDXgoKVWUG/fReSzHg==} @@ -3426,6 +3507,9 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + one-time@1.0.0: + resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} + openai@4.78.0: resolution: {integrity: sha512-4rRsKkx++5m1zayxkryVH+K/z91cv1sRbaNJAhSQjZiSCQOR7eaM8KpfIssXrS9Hlpta7+VcuO/fi57pW8xGjA==} hasBin: true @@ -3780,6 +3864,10 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + scheduler@0.25.0: resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} @@ -3792,6 +3880,10 @@ packages: engines: {node: '>=10'} hasBin: true + serialize-error@8.1.0: + resolution: {integrity: sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==} + engines: {node: '>=10'} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -3872,6 +3964,9 @@ packages: stable-hash@0.0.4: resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==} + stack-trace@0.0.10: + resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + standard-as-callback@2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} @@ -3996,6 +4091,9 @@ packages: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} + text-hex@1.0.0: + resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} + thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -4020,6 +4118,10 @@ packages: trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + triple-beam@1.4.1: + resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} + engines: {node: '>= 14.0.0'} + trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} @@ -4070,6 +4172,10 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -4213,6 +4319,14 @@ packages: engines: {node: '>= 8'} hasBin: true + winston-transport@4.9.0: + resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==} + engines: {node: '>= 12.0.0'} + + winston@3.17.0: + resolution: {integrity: sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==} + engines: {node: '>= 12.0.0'} + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -4810,10 +4924,18 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 + '@colors/colors@1.6.0': {} + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 + '@dabh/diagnostics@2.0.3': + dependencies: + colorspace: 1.1.4 + enabled: 2.0.0 + kuler: 2.0.0 + '@emnapi/runtime@1.3.1': dependencies: tslib: 2.8.1 @@ -5020,6 +5142,47 @@ snapshots: '@js-sdsl/ordered-map@4.4.2': {} + '@logtail/core@0.5.2': + dependencies: + '@logtail/tools': 0.5.2 + '@logtail/types': 0.5.2 + serialize-error: 8.1.0 + transitivePeerDependencies: + - encoding + + '@logtail/node@0.5.2': + dependencies: + '@logtail/core': 0.5.2 + '@logtail/types': 0.5.2 + '@msgpack/msgpack': 2.8.0 + '@types/stack-trace': 0.0.33 + cross-fetch: 4.1.0 + minimatch: 9.0.5 + serialize-error: 8.1.0 + stack-trace: 0.0.10 + transitivePeerDependencies: + - encoding + + '@logtail/tools@0.5.2': + dependencies: + '@logtail/types': 0.5.2 + cross-fetch: 4.1.0 + transitivePeerDependencies: + - encoding + + '@logtail/types@0.5.2': {} + + '@logtail/winston@0.5.2(winston@3.17.0)': + dependencies: + '@logtail/node': 0.5.2 + '@logtail/types': 0.5.2 + winston: 3.17.0 + winston-transport: 4.9.0 + transitivePeerDependencies: + - encoding + + '@msgpack/msgpack@2.8.0': {} + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': optional: true @@ -6369,6 +6532,10 @@ snapshots: dependencies: csstype: 3.1.3 + '@types/stack-trace@0.0.33': {} + + '@types/triple-beam@1.3.5': {} + '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} @@ -6576,6 +6743,8 @@ snapshots: ast-types-flow@0.0.8: {} + async@3.2.6: {} + asynckit@0.4.0: {} available-typed-arrays@1.0.7: @@ -6732,10 +6901,16 @@ snapshots: - '@types/react' - '@types/react-dom' + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + color-convert@2.0.1: dependencies: color-name: 1.1.4 + color-name@1.1.3: {} + color-name@1.1.4: {} color-string@1.9.1: @@ -6743,11 +6918,21 @@ snapshots: color-name: 1.1.4 simple-swizzle: 0.2.2 + color@3.2.1: + dependencies: + color-convert: 1.9.3 + color-string: 1.9.1 + color@4.2.3: dependencies: color-convert: 2.0.1 color-string: 1.9.1 + colorspace@1.1.4: + dependencies: + color: 3.2.1 + text-hex: 1.0.0 + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -6772,6 +6957,12 @@ snapshots: transitivePeerDependencies: - encoding + cross-fetch@4.1.0: + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -6943,6 +7134,8 @@ snapshots: emoji-regex@9.2.2: {} + enabled@2.0.0: {} + end-of-stream@1.4.4: dependencies: once: 1.4.0 @@ -7293,6 +7486,8 @@ snapshots: dependencies: reusify: 1.0.4 + fecha@4.2.3: {} + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -7313,6 +7508,8 @@ snapshots: flatted@3.3.2: {} + fn.name@1.1.0: {} + follow-redirects@1.15.9: {} for-each@0.3.3: @@ -7643,6 +7840,8 @@ snapshots: dependencies: call-bound: 1.0.3 + is-stream@2.0.1: {} + is-string@1.1.1: dependencies: call-bound: 1.0.3 @@ -7743,6 +7942,8 @@ snapshots: dependencies: json-buffer: 3.0.1 + kuler@2.0.0: {} + language-subtag-registry@0.3.23: {} language-tags@1.0.9: @@ -7786,6 +7987,15 @@ snapshots: lodash@4.17.21: {} + logform@2.7.0: + dependencies: + '@colors/colors': 1.6.0 + '@types/triple-beam': 1.3.5 + fecha: 4.2.3 + ms: 2.1.3 + safe-stable-stringify: 2.5.0 + triple-beam: 1.4.1 + long@5.2.4: {} longest-streak@3.1.0: {} @@ -8229,6 +8439,10 @@ snapshots: dependencies: wrappy: 1.0.2 + one-time@1.0.0: + dependencies: + fn.name: 1.1.0 + openai@4.78.0(zod@3.24.1): dependencies: '@types/node': 18.19.70 @@ -8643,12 +8857,18 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 + safe-stable-stringify@2.5.0: {} + scheduler@0.25.0: {} semver@6.3.1: {} semver@7.6.3: {} + serialize-error@8.1.0: + dependencies: + type-fest: 0.20.2 + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -8768,6 +8988,8 @@ snapshots: stable-hash@0.0.4: {} + stack-trace@0.0.10: {} + standard-as-callback@2.1.0: {} streamsearch@1.1.0: {} @@ -8938,6 +9160,8 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + text-hex@1.0.0: {} + thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -8958,6 +9182,8 @@ snapshots: trim-lines@3.0.1: {} + triple-beam@1.4.1: {} + trough@2.2.0: {} ts-api-utils@2.0.0(typescript@5.7.3): @@ -9018,6 +9244,8 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-fest@0.20.2: {} + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.3 @@ -9230,6 +9458,26 @@ snapshots: dependencies: isexe: 2.0.0 + winston-transport@4.9.0: + dependencies: + logform: 2.7.0 + readable-stream: 3.6.2 + triple-beam: 1.4.1 + + winston@3.17.0: + dependencies: + '@colors/colors': 1.6.0 + '@dabh/diagnostics': 2.0.3 + async: 3.2.6 + is-stream: 2.0.1 + logform: 2.7.0 + one-time: 1.0.0 + readable-stream: 3.6.2 + safe-stable-stringify: 2.5.0 + stack-trace: 0.0.10 + triple-beam: 1.4.1 + winston-transport: 4.9.0 + word-wrap@1.2.5: {} wrap-ansi@7.0.0: diff --git a/src/app/auth/login/actions.ts b/src/app/auth/login/actions.ts index bb40d72..a6b9086 100644 --- a/src/app/auth/login/actions.ts +++ b/src/app/auth/login/actions.ts @@ -4,6 +4,7 @@ import { prisma } from '@/lib/prisma' import { sendEmail } from '@/lib/email' import { cookies } from 'next/headers' import { sign } from 'jsonwebtoken' +import { logger } from '@/lib/logger' export async function loginUser(email: string) { @@ -24,7 +25,7 @@ export async function loginUser(email: string) { ) if (!emailResult.success) { - console.error('Failed to send email:', emailResult.error) + logger.error('Failed to send email:', emailResult.error) return { success: false, error: 'Failed to send OTP email' } } diff --git a/src/app/auth/signup/actions.ts b/src/app/auth/signup/actions.ts index 1e41ee6..b2baf3b 100644 --- a/src/app/auth/signup/actions.ts +++ b/src/app/auth/signup/actions.ts @@ -1,5 +1,6 @@ 'use server' +import { logger } from '@/lib/logger' import { prisma } from '@/lib/prisma' export async function signupUser(data: { name: string, email: string, organizationName: string }) { @@ -28,7 +29,7 @@ export async function signupUser(data: { name: string, email: string, organizati }) return { success: true } } catch (error) { - console.error('Signup error:', error) + logger.error('Signup error:', error) return { success: false } } } diff --git a/src/app/console/searchDialog.tsx b/src/app/console/searchDialog.tsx index 9447ca7..d413fb6 100644 --- a/src/app/console/searchDialog.tsx +++ b/src/app/console/searchDialog.tsx @@ -40,7 +40,6 @@ export default function SearchDialog({ open }: { open: boolean }) { }) })) } catch (err) { - console.log(err) setMessages(produce((draft) => { draft.push({ role: "assistant", diff --git a/src/app/console/sheets/[slug]/columnDialog.tsx b/src/app/console/sheets/[slug]/columnDialog.tsx index e75462a..839285e 100644 --- a/src/app/console/sheets/[slug]/columnDialog.tsx +++ b/src/app/console/sheets/[slug]/columnDialog.tsx @@ -61,7 +61,6 @@ export default function ColumnDialog({ open, defaultData, sheetId, onSubmit }: { description: "The column has been saved to the sheet", }) } catch (error) { - console.error(error) toast({ title: "Error", description: "An error occurred while saving the column", diff --git a/src/app/console/sheets/[slug]/page.tsx b/src/app/console/sheets/[slug]/page.tsx index 5a80a9d..dbade3e 100644 --- a/src/app/console/sheets/[slug]/page.tsx +++ b/src/app/console/sheets/[slug]/page.tsx @@ -90,7 +90,6 @@ export default function SheetPage() { description: "The column has been deleted from the sheet", }) } catch (error) { - console.error(error) toast({ title: "Error", description: "An error occurred while deleting the column", diff --git a/src/app/console/sheetsDialog.tsx b/src/app/console/sheetsDialog.tsx index 0435ddf..66721b8 100644 --- a/src/app/console/sheetsDialog.tsx +++ b/src/app/console/sheetsDialog.tsx @@ -11,6 +11,7 @@ import { Input } from "@/components/ui/input" import { Button } from "@/components/ui/button" import { PiSpinner } from "react-icons/pi" import { Switch } from "@/components/ui/switch" +import { useToast } from "@/hooks/use-toast" interface AddSheetDialogProps { isOpen: boolean; @@ -29,14 +30,15 @@ const sheetSchema = z.object({ type SheetFormValues = z.infer export function AddSheetDialog({ isOpen, onClose }: AddSheetDialogProps) { - const [isSubmitting, setIsSubmitting] = useState(false); + const [isSubmitting, setIsSubmitting] = useState(false) const form = useForm({ defaultValues: { name: '', singleSource: false }, resolver: zodResolver(sheetSchema) - }); + }) + const { toast } = useToast() const onSubmit = async (data: SheetFormValues) => { setIsSubmitting(true); @@ -45,12 +47,15 @@ export function AddSheetDialog({ isOpen, onClose }: AddSheetDialogProps) { onClose(); form.reset(); } catch (error) { - console.error('Error adding sheet:', error); - // Handle error (e.g., show error message) + toast({ + title: "Error adding sheet", + description: "An error occurred while adding the sheet", + variant: "destructive" + }) } finally { setIsSubmitting(false); } - }; + } return ( !open && onClose()}> diff --git a/src/app/console/sourcesDialog.tsx b/src/app/console/sourcesDialog.tsx index 232223f..6a8dab9 100644 --- a/src/app/console/sourcesDialog.tsx +++ b/src/app/console/sourcesDialog.tsx @@ -56,7 +56,6 @@ export default function SourcesDialog() { await fetchData() setUploadError('') } catch (error) { - console.error('Error uploading file:', error) setUploadError('Error uploading file(s)') } finally { setUploading(false); @@ -74,7 +73,6 @@ export default function SourcesDialog() { variant: 'destructive', }) } catch (error) { - console.error('Error deleting source:', error) toast({ title: 'Error deleting source', description: 'An error occurred while deleting the source', diff --git a/src/cron.ts b/src/cron.ts index 0cd17e6..a83bcd2 100644 --- a/src/cron.ts +++ b/src/cron.ts @@ -2,12 +2,13 @@ import cron from "node-cron" import { indexSource } from "@/core/indexer" import { prisma } from "@/lib/prisma" import { redis } from "@/lib/redis" +import { logger } from "./lib/logger" cron.schedule("*/5 * * * *", async () => { try { const lock = await redis.get("cron-lock") - console.log("CRON Lock Status", lock) + logger.info("CRON Lock Status", lock) if (lock) { return @@ -15,7 +16,7 @@ cron.schedule("*/5 * * * *", async () => { await redis.set("cron-lock", "true") - console.log("Starting CRON") + logger.info("Starting CRON") const sources = await prisma.source.findMany({ where: { @@ -29,7 +30,7 @@ cron.schedule("*/5 * * * *", async () => { for (const source of sources) { - console.log(`Indexing source of ${source.id}`) + logger.info(`Indexing source of ${source.id}`) try { await prisma.source.update({ @@ -56,7 +57,7 @@ cron.schedule("*/5 * * * *", async () => { } }) - console.log(`Indexed source of ${source.id}`) + logger.info(`Indexed source of ${source.id}`) } catch (err) { @@ -73,15 +74,15 @@ cron.schedule("*/5 * * * *", async () => { } }) - console.log(err) - console.log(`Failed to index source of ${source.id}`) + logger.info(err) + logger.info(`Failed to index source of ${source.id}`) } } await redis.del("cron-lock") } catch (err) { - console.error(err) + logger.error(err) await redis.del("cron-lock") } }) diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 2a97b26..7b0a796 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -1,6 +1,7 @@ import { cookies } from "next/headers" import { redirect } from "next/navigation" import jwt from "jsonwebtoken" +import { logger } from "./logger" interface DecodedToken { userId: string @@ -19,7 +20,7 @@ export async function getAuthToken(): Promise { const decoded = jwt.verify(token.value, process.env.JWT_SECRET as string) as DecodedToken return decoded } catch (error) { - console.error("Invalid token:", error) + logger.error("Invalid token:", error) redirect("/auth/login") } } diff --git a/src/lib/email.ts b/src/lib/email.ts index deff556..7e6af64 100644 --- a/src/lib/email.ts +++ b/src/lib/email.ts @@ -1,4 +1,5 @@ import nodemailer from "nodemailer"; +import { logger } from "./logger"; const transporter = nodemailer.createTransport({ host: process.env.SMTP_HOST, @@ -20,10 +21,10 @@ export async function sendEmail(to: string, subject: string, body: string) { html: `

${body}

`, }); - console.log("Message sent: %s", info.messageId); + logger.info("Message sent: %s", info.messageId); return { success: true, messageId: info.messageId }; } catch (error) { - console.error("Error sending email:", error); + logger.error("Error sending email:", error); return { success: false, error }; } } \ No newline at end of file diff --git a/src/lib/logger.ts b/src/lib/logger.ts new file mode 100644 index 0000000..5a1ef37 --- /dev/null +++ b/src/lib/logger.ts @@ -0,0 +1,35 @@ +import winston from "winston"; +import { Logtail } from "@logtail/node"; +import { LogtailTransport } from "@logtail/winston"; + + +export class Logger { + private static _instance: Logger | null = null; + private _logtail: Logtail; + private _logger: winston.Logger; + + constructor() { + this._logtail = new Logtail(process.env.BETTER_STACK_TOKEN || "") + + const transports = process.env.LOGTAIL !== "" ? new LogtailTransport(this._logtail) : new winston.transports.Console({ + format: winston.format.combine( + winston.format.colorize(), + winston.format.simple() + ), + }) + + // process .env is PROD then logtail else commandline + this._logger = winston.createLogger({ + transports: [transports], + }) + } + + public static getInstance(): winston.Logger { + if (!Logger._instance) { + Logger._instance = new Logger() + } + return Logger._instance._logger + } +} + +export const logger = Logger.getInstance() diff --git a/src/worker.ts b/src/worker.ts index 8deb913..e9ed9d4 100644 --- a/src/worker.ts +++ b/src/worker.ts @@ -1,10 +1,11 @@ import { Worker } from "bullmq"; +import { logger } from "./lib/logger"; // Define the worker process new Worker( "queue", async (job) => { - console.log("Worker running") + logger.info("Worker running") }, { connection: {