More stuff
This commit is contained in:
parent
edffe130a5
commit
7371cc8851
@ -18,6 +18,7 @@
|
|||||||
"@t3-oss/env-nextjs": "^0.10.1",
|
"@t3-oss/env-nextjs": "^0.10.1",
|
||||||
"drizzle-orm": "^0.33.0",
|
"drizzle-orm": "^0.33.0",
|
||||||
"geist": "^1.3.0",
|
"geist": "^1.3.0",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
"next": "^14.2.4",
|
"next": "^14.2.4",
|
||||||
"postgres": "^3.4.4",
|
"postgres": "^3.4.4",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
@ -26,6 +27,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/eslint": "^8.56.10",
|
"@types/eslint": "^8.56.10",
|
||||||
|
"@types/jsonwebtoken": "^9.0.7",
|
||||||
"@types/node": "^20.14.10",
|
"@types/node": "^20.14.10",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.3",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
|
103
pnpm-lock.yaml
generated
103
pnpm-lock.yaml
generated
@ -17,6 +17,9 @@ importers:
|
|||||||
geist:
|
geist:
|
||||||
specifier: ^1.3.0
|
specifier: ^1.3.0
|
||||||
version: 1.3.1(next@14.2.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
version: 1.3.1(next@14.2.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||||
|
jsonwebtoken:
|
||||||
|
specifier: ^9.0.2
|
||||||
|
version: 9.0.2
|
||||||
next:
|
next:
|
||||||
specifier: ^14.2.4
|
specifier: ^14.2.4
|
||||||
version: 14.2.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 14.2.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
@ -36,6 +39,9 @@ importers:
|
|||||||
'@types/eslint':
|
'@types/eslint':
|
||||||
specifier: ^8.56.10
|
specifier: ^8.56.10
|
||||||
version: 8.56.12
|
version: 8.56.12
|
||||||
|
'@types/jsonwebtoken':
|
||||||
|
specifier: ^9.0.7
|
||||||
|
version: 9.0.7
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^20.14.10
|
specifier: ^20.14.10
|
||||||
version: 20.16.5
|
version: 20.16.5
|
||||||
@ -539,6 +545,9 @@ packages:
|
|||||||
'@types/json5@0.0.29':
|
'@types/json5@0.0.29':
|
||||||
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
||||||
|
|
||||||
|
'@types/jsonwebtoken@9.0.7':
|
||||||
|
resolution: {integrity: sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg==}
|
||||||
|
|
||||||
'@types/node@20.16.5':
|
'@types/node@20.16.5':
|
||||||
resolution: {integrity: sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==}
|
resolution: {integrity: sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==}
|
||||||
|
|
||||||
@ -785,6 +794,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
buffer-equal-constant-time@1.0.1:
|
||||||
|
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
||||||
|
|
||||||
buffer-from@1.1.2:
|
buffer-from@1.1.2:
|
||||||
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||||
|
|
||||||
@ -1005,6 +1017,9 @@ packages:
|
|||||||
eastasianwidth@0.2.0:
|
eastasianwidth@0.2.0:
|
||||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||||
|
|
||||||
|
ecdsa-sig-formatter@1.0.11:
|
||||||
|
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
|
||||||
|
|
||||||
emoji-regex@8.0.0:
|
emoji-regex@8.0.0:
|
||||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||||
|
|
||||||
@ -1503,10 +1518,20 @@ packages:
|
|||||||
resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
|
resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
jsonwebtoken@9.0.2:
|
||||||
|
resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
|
||||||
|
engines: {node: '>=12', npm: '>=6'}
|
||||||
|
|
||||||
jsx-ast-utils@3.3.5:
|
jsx-ast-utils@3.3.5:
|
||||||
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
|
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
|
||||||
engines: {node: '>=4.0'}
|
engines: {node: '>=4.0'}
|
||||||
|
|
||||||
|
jwa@1.4.1:
|
||||||
|
resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==}
|
||||||
|
|
||||||
|
jws@3.2.2:
|
||||||
|
resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==}
|
||||||
|
|
||||||
keyv@4.5.4:
|
keyv@4.5.4:
|
||||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||||
|
|
||||||
@ -1536,9 +1561,30 @@ packages:
|
|||||||
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
lodash.includes@4.3.0:
|
||||||
|
resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
|
||||||
|
|
||||||
|
lodash.isboolean@3.0.3:
|
||||||
|
resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
|
||||||
|
|
||||||
|
lodash.isinteger@4.0.4:
|
||||||
|
resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==}
|
||||||
|
|
||||||
|
lodash.isnumber@3.0.3:
|
||||||
|
resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==}
|
||||||
|
|
||||||
|
lodash.isplainobject@4.0.6:
|
||||||
|
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
|
||||||
|
|
||||||
|
lodash.isstring@4.0.1:
|
||||||
|
resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
|
||||||
|
|
||||||
lodash.merge@4.6.2:
|
lodash.merge@4.6.2:
|
||||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||||
|
|
||||||
|
lodash.once@4.1.1:
|
||||||
|
resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
|
||||||
|
|
||||||
loose-envify@1.4.0:
|
loose-envify@1.4.0:
|
||||||
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
|
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@ -1893,6 +1939,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==}
|
resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==}
|
||||||
engines: {node: '>=0.4'}
|
engines: {node: '>=0.4'}
|
||||||
|
|
||||||
|
safe-buffer@5.2.1:
|
||||||
|
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||||
|
|
||||||
safe-regex-test@1.0.3:
|
safe-regex-test@1.0.3:
|
||||||
resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==}
|
resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -2450,6 +2499,10 @@ snapshots:
|
|||||||
|
|
||||||
'@types/json5@0.0.29': {}
|
'@types/json5@0.0.29': {}
|
||||||
|
|
||||||
|
'@types/jsonwebtoken@9.0.7':
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 20.16.5
|
||||||
|
|
||||||
'@types/node@20.16.5':
|
'@types/node@20.16.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.19.8
|
undici-types: 6.19.8
|
||||||
@ -2768,6 +2821,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fill-range: 7.1.1
|
fill-range: 7.1.1
|
||||||
|
|
||||||
|
buffer-equal-constant-time@1.0.1: {}
|
||||||
|
|
||||||
buffer-from@1.1.2: {}
|
buffer-from@1.1.2: {}
|
||||||
|
|
||||||
busboy@1.6.0:
|
busboy@1.6.0:
|
||||||
@ -2923,6 +2978,10 @@ snapshots:
|
|||||||
|
|
||||||
eastasianwidth@0.2.0: {}
|
eastasianwidth@0.2.0: {}
|
||||||
|
|
||||||
|
ecdsa-sig-formatter@1.0.11:
|
||||||
|
dependencies:
|
||||||
|
safe-buffer: 5.2.1
|
||||||
|
|
||||||
emoji-regex@8.0.0: {}
|
emoji-regex@8.0.0: {}
|
||||||
|
|
||||||
emoji-regex@9.2.2: {}
|
emoji-regex@9.2.2: {}
|
||||||
@ -3130,7 +3189,7 @@ snapshots:
|
|||||||
debug: 4.3.7
|
debug: 4.3.7
|
||||||
enhanced-resolve: 5.17.1
|
enhanced-resolve: 5.17.1
|
||||||
eslint: 8.57.0
|
eslint: 8.57.0
|
||||||
eslint-module-utils: 2.11.0(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.0))(eslint@8.57.0)
|
eslint-module-utils: 2.11.0(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0)
|
||||||
fast-glob: 3.3.2
|
fast-glob: 3.3.2
|
||||||
get-tsconfig: 4.8.0
|
get-tsconfig: 4.8.0
|
||||||
is-bun-module: 1.2.1
|
is-bun-module: 1.2.1
|
||||||
@ -3143,7 +3202,7 @@ snapshots:
|
|||||||
- eslint-import-resolver-webpack
|
- eslint-import-resolver-webpack
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-module-utils@2.11.0(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.0))(eslint@8.57.0):
|
eslint-module-utils@2.11.0(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 3.2.7
|
debug: 3.2.7
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
@ -3647,6 +3706,19 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
minimist: 1.2.8
|
minimist: 1.2.8
|
||||||
|
|
||||||
|
jsonwebtoken@9.0.2:
|
||||||
|
dependencies:
|
||||||
|
jws: 3.2.2
|
||||||
|
lodash.includes: 4.3.0
|
||||||
|
lodash.isboolean: 3.0.3
|
||||||
|
lodash.isinteger: 4.0.4
|
||||||
|
lodash.isnumber: 3.0.3
|
||||||
|
lodash.isplainobject: 4.0.6
|
||||||
|
lodash.isstring: 4.0.1
|
||||||
|
lodash.once: 4.1.1
|
||||||
|
ms: 2.1.3
|
||||||
|
semver: 7.6.3
|
||||||
|
|
||||||
jsx-ast-utils@3.3.5:
|
jsx-ast-utils@3.3.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
array-includes: 3.1.8
|
array-includes: 3.1.8
|
||||||
@ -3654,6 +3726,17 @@ snapshots:
|
|||||||
object.assign: 4.1.5
|
object.assign: 4.1.5
|
||||||
object.values: 1.2.0
|
object.values: 1.2.0
|
||||||
|
|
||||||
|
jwa@1.4.1:
|
||||||
|
dependencies:
|
||||||
|
buffer-equal-constant-time: 1.0.1
|
||||||
|
ecdsa-sig-formatter: 1.0.11
|
||||||
|
safe-buffer: 5.2.1
|
||||||
|
|
||||||
|
jws@3.2.2:
|
||||||
|
dependencies:
|
||||||
|
jwa: 1.4.1
|
||||||
|
safe-buffer: 5.2.1
|
||||||
|
|
||||||
keyv@4.5.4:
|
keyv@4.5.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
json-buffer: 3.0.1
|
json-buffer: 3.0.1
|
||||||
@ -3679,8 +3762,22 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
p-locate: 5.0.0
|
p-locate: 5.0.0
|
||||||
|
|
||||||
|
lodash.includes@4.3.0: {}
|
||||||
|
|
||||||
|
lodash.isboolean@3.0.3: {}
|
||||||
|
|
||||||
|
lodash.isinteger@4.0.4: {}
|
||||||
|
|
||||||
|
lodash.isnumber@3.0.3: {}
|
||||||
|
|
||||||
|
lodash.isplainobject@4.0.6: {}
|
||||||
|
|
||||||
|
lodash.isstring@4.0.1: {}
|
||||||
|
|
||||||
lodash.merge@4.6.2: {}
|
lodash.merge@4.6.2: {}
|
||||||
|
|
||||||
|
lodash.once@4.1.1: {}
|
||||||
|
|
||||||
loose-envify@1.4.0:
|
loose-envify@1.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
js-tokens: 4.0.0
|
js-tokens: 4.0.0
|
||||||
@ -3979,6 +4076,8 @@ snapshots:
|
|||||||
has-symbols: 1.0.3
|
has-symbols: 1.0.3
|
||||||
isarray: 2.0.5
|
isarray: 2.0.5
|
||||||
|
|
||||||
|
safe-buffer@5.2.1: {}
|
||||||
|
|
||||||
safe-regex-test@1.0.3:
|
safe-regex-test@1.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
|
22
src/app/api/countdown/createOrUpdateCountdown/route.ts
Normal file
22
src/app/api/countdown/createOrUpdateCountdown/route.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
"use server";
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import type { NextRequest } from "next/server";
|
||||||
|
import { createOrUpdateCountdown } from "~/server/functions";
|
||||||
|
import { middleware } from "~/middleware";
|
||||||
|
|
||||||
|
export const POST = async (request: NextRequest) => {
|
||||||
|
const middlewareResponse = middleware(request);
|
||||||
|
if (middlewareResponse) return middlewareResponse;
|
||||||
|
try {
|
||||||
|
const { relationshipId, title, date } = await request.json() as {
|
||||||
|
relationshipId: string;
|
||||||
|
title: string;
|
||||||
|
date: string;
|
||||||
|
};
|
||||||
|
await createOrUpdateCountdown(Number.parseInt(relationshipId), title, new Date(date));
|
||||||
|
return NextResponse.json({ message: "Countdown created or updated successfully" });
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
return NextResponse.json({ message: "Error" }, { status: 500 });
|
||||||
|
}
|
||||||
|
};
|
23
src/app/api/countdown/getCountdownByRelationship/route.ts
Normal file
23
src/app/api/countdown/getCountdownByRelationship/route.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
"use server";
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import { getCountdownByRelationship } from "~/server/functions";
|
||||||
|
|
||||||
|
export const GET = async (request: Request) => {
|
||||||
|
try {
|
||||||
|
const url = new URL(request.url);
|
||||||
|
const apiKey = url.searchParams.get("apiKey");
|
||||||
|
if (apiKey !== process.env.API_KEY) {
|
||||||
|
console.log("Invalid API Key");
|
||||||
|
return NextResponse.json({ message: "Invalid API Key" }, { status: 401 });
|
||||||
|
} else {
|
||||||
|
const relationshipId = url.searchParams.get("relationshipId");
|
||||||
|
if (!relationshipId)
|
||||||
|
return NextResponse.json({ message: "Invalid relationshipId" }, { status: 400 });
|
||||||
|
const countdown = await getCountdownByRelationship(parseInt(relationshipId));
|
||||||
|
return NextResponse.json(countdown);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
return NextResponse.json({ message: "Error" }, { status: 500 });
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,26 @@
|
|||||||
|
"use server";
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import { fetchMessages } from "~/server/functions";
|
||||||
|
|
||||||
|
export const GET = async (request: Request) => {
|
||||||
|
try {
|
||||||
|
const url = new URL(request.url);
|
||||||
|
const apiKey = url.searchParams.get("apiKey");
|
||||||
|
if (apiKey !== process.env.API_KEY) {
|
||||||
|
console.log("Invalid API Key");
|
||||||
|
return NextResponse.json({ message: "Invalid API Key" }, { status: 401 });
|
||||||
|
} else {
|
||||||
|
const userId = url.searchParams.get("userId");
|
||||||
|
if (!userId)
|
||||||
|
return NextResponse.json({ message: "Invalid userId" }, { status: 400 });
|
||||||
|
const partnerId = url.searchParams.get("partnerId");
|
||||||
|
if (!partnerId)
|
||||||
|
return NextResponse.json({ message: "Invalid partnerId" }, { status: 400 });
|
||||||
|
const messages = await fetchMessages(parseInt(userId), parseInt(partnerId));
|
||||||
|
return NextResponse.json(messages);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
return NextResponse.json({ message: "Error" }, { status: 500 });
|
||||||
|
}
|
||||||
|
};
|
@ -2,7 +2,7 @@
|
|||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { createRelationshipRequest } from "~/server/functions";
|
import { createRelationshipRequest } from "~/server/functions";
|
||||||
|
|
||||||
interface CreateRequestRequest {
|
type CreateRequestRequest = {
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
userId: number;
|
userId: number;
|
||||||
targetUserId: number;
|
targetUserId: number;
|
||||||
|
@ -21,8 +21,6 @@ export const POST = async (request: Request) => {
|
|||||||
|
|
||||||
console.log("Changing password for user:", userId);
|
console.log("Changing password for user:", userId);
|
||||||
await changePassword(userId, oldPassword, newPassword);
|
await changePassword(userId, oldPassword, newPassword);
|
||||||
|
|
||||||
console.log("Password changed successfully");
|
|
||||||
return NextResponse.json({ message: "Password changed successfully" });
|
return NextResponse.json({ message: "Password changed successfully" });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error in changePassword:", error);
|
console.error("Error in changePassword:", error);
|
||||||
|
@ -10,7 +10,10 @@ export const GET = async (request: Request) => {
|
|||||||
console.log("Invalid API Key");
|
console.log("Invalid API Key");
|
||||||
return NextResponse.json({ message: "Invalid API Key" }, { status: 401 });
|
return NextResponse.json({ message: "Invalid API Key" }, { status: 401 });
|
||||||
} else {
|
} else {
|
||||||
const userId = url.searchParams.get("userId") ?? "2";
|
const userId = url.searchParams.get("userId");
|
||||||
|
if (!userId) {
|
||||||
|
return NextResponse.json({ message: "Invalid userId" }, { status: 400 });
|
||||||
|
}
|
||||||
const user = await getUserById(parseInt(userId));
|
const user = await getUserById(parseInt(userId));
|
||||||
return NextResponse.json(user);
|
return NextResponse.json(user);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"use server";
|
"use server";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { userLogin } from "~/server/functions";
|
import { login } from "~/server/functions";
|
||||||
|
|
||||||
interface LoginRequest {
|
interface LoginRequest {
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
@ -23,7 +23,7 @@ export async function POST(request: Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log("Logging in user:", username);
|
console.log("Logging in user:", username);
|
||||||
const result = await userLogin(username, password);
|
const result = await login(username, password);
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
console.log("User logged in successfully");
|
console.log("User logged in successfully");
|
||||||
|
32
src/app/api/users/logout/route.ts
Normal file
32
src/app/api/users/logout/route.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
"use server";
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import type { NextRequest } from "next/server";
|
||||||
|
import { logout } from "~/server/functions";
|
||||||
|
import { middleware } from "~/middleware";
|
||||||
|
import jwt from "jsonwebtoken";
|
||||||
|
|
||||||
|
export const POST = async (request: NextRequest) => {
|
||||||
|
const middlewareResponse = middleware(request);
|
||||||
|
if (middlewareResponse) return middlewareResponse;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { token } = await request.json() as { token: string };
|
||||||
|
if (!token)
|
||||||
|
return NextResponse.json({ message: "Token is required" },{ status: 400 });
|
||||||
|
|
||||||
|
try {
|
||||||
|
const decoded = jwt.verify(token, process.env.JWT_SECRET!) as { userId: number };
|
||||||
|
if (!decoded.userId)
|
||||||
|
throw new Error("Invalid token");
|
||||||
|
await logout(decoded.userId);
|
||||||
|
return NextResponse.json({ message: "Logged out successfully" });
|
||||||
|
} catch (jwtError) {
|
||||||
|
return NextResponse.json({ message: "Invalid token", error: jwtError }, { status: 400 });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error)
|
||||||
|
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||||
|
else
|
||||||
|
return NextResponse.json({ message: "Unknown error occurred" }, { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
22
src/app/api/users/refreshToken/route.ts
Normal file
22
src/app/api/users/refreshToken/route.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
"use server";
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import type { NextRequest } from "next/server";
|
||||||
|
import { refreshToken } from "~/server/functions";
|
||||||
|
import { middleware } from "~/middleware";
|
||||||
|
|
||||||
|
export async function POST(request: NextRequest) {
|
||||||
|
const middlewareResponse = middleware(request);
|
||||||
|
if (middlewareResponse) return middlewareResponse;
|
||||||
|
try {
|
||||||
|
const { refreshToken: token } = await request.json() as { refreshToken: string };
|
||||||
|
if (!token)
|
||||||
|
return NextResponse.json({ message: "Refresh token is required" },{ status: 400 });
|
||||||
|
const tokens = await refreshToken(token);
|
||||||
|
return NextResponse.json(tokens);
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error)
|
||||||
|
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||||
|
else
|
||||||
|
return NextResponse.json({ message: "Unknown error occurred" }, { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
13
src/middleware.ts
Normal file
13
src/middleware.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import type { NextRequest } from 'next/server';
|
||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
|
||||||
|
export function middleware(request: NextRequest) {
|
||||||
|
const apiKey = request.headers.get('x-api-key');
|
||||||
|
|
||||||
|
if (!apiKey || apiKey !== process.env.API_KEY)
|
||||||
|
return NextResponse.json({ message: 'Invalid API key' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
matcher: '/api/:path*',
|
||||||
|
};
|
@ -24,7 +24,8 @@ export const users = createTable(
|
|||||||
passwordHash: varchar("password_hash", {length: 255}).notNull(),
|
passwordHash: varchar("password_hash", {length: 255}).notNull(),
|
||||||
name: varchar("name", { length: 100 }),
|
name: varchar("name", { length: 100 }),
|
||||||
pfpURL: varchar("pfp_url", { length: 255 }),
|
pfpURL: varchar("pfp_url", { length: 255 }),
|
||||||
pushToken: varchar("pushToken", { length: 256 }),
|
pushToken: varchar("pushToken", { length: 255 }),
|
||||||
|
refreshToken: varchar("refreshToken", { length: 255 }),
|
||||||
lastLogin: timestamp("last_login", { withTimezone: true }),
|
lastLogin: timestamp("last_login", { withTimezone: true }),
|
||||||
createdAt: timestamp("created_at", { withTimezone: true })
|
createdAt: timestamp("created_at", { withTimezone: true })
|
||||||
.default(sql`CURRENT_TIMESTAMP`)
|
.default(sql`CURRENT_TIMESTAMP`)
|
||||||
|
@ -3,6 +3,7 @@ import { db } from '~/server/db';
|
|||||||
import * as schema from '~/server/db/schema';
|
import * as schema from '~/server/db/schema';
|
||||||
import { eq, and, or } from 'drizzle-orm';
|
import { eq, and, or } from 'drizzle-orm';
|
||||||
import { pgEnum } from 'drizzle-orm/pg-core';
|
import { pgEnum } from 'drizzle-orm/pg-core';
|
||||||
|
import jwt from 'jsonwebtoken';
|
||||||
|
|
||||||
// --- Helper Functions --- //
|
// --- Helper Functions --- //
|
||||||
|
|
||||||
@ -198,19 +199,24 @@ export const updateUserPushToken = async (userId: number, pushToken: string) =>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const userLogin = async (username: string, passwordHash: string) => {
|
export const login = async (username: string, passwordHash: string) => {
|
||||||
try {
|
try {
|
||||||
const user = await getUserByUsername(username);
|
const user = await getUserByUsername(username);
|
||||||
if (user?.passwordHash !== passwordHash) {
|
if (user?.passwordHash !== passwordHash) {
|
||||||
throw new Error("Invalid password");
|
throw new Error("Invalid password");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const accessToken = jwt.sign({ userId: user.id }, process.env.JWT_SECRET!,
|
||||||
|
{expiresIn: '15m' });
|
||||||
|
const refreshToken = jwt.sign({ userId: user.id }, process.env.JWT_REFRESH_SECRET!,
|
||||||
|
{expiresIn: '7d' });
|
||||||
|
|
||||||
// Update last login timestamp
|
// Update last login timestamp
|
||||||
await db.update(schema.users)
|
await db.update(schema.users)
|
||||||
.set({ lastLogin: new Date() })
|
.set({ lastLogin: new Date() })
|
||||||
.where(eq(schema.users.id, user.id));
|
.where(eq(schema.users.id, user.id));
|
||||||
|
|
||||||
return user;
|
return { user, accessToken, refreshToken };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
throw new Error(`Failed to Log in: ${error.message}`);
|
throw new Error(`Failed to Log in: ${error.message}`);
|
||||||
@ -220,6 +226,47 @@ export const userLogin = async (username: string, passwordHash: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const refreshToken = async (refreshToken: string) => {
|
||||||
|
try {
|
||||||
|
const decoded = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET!) as { userId: number };
|
||||||
|
if (!decoded.userId)
|
||||||
|
throw new Error("Invalid refresh token");
|
||||||
|
const user = await getUserById(decoded.userId);
|
||||||
|
if (!user || user.refreshToken !== refreshToken)
|
||||||
|
throw new Error("Invalid refresh token");
|
||||||
|
const newAccessToken = jwt.sign({ userId: user.id }, process.env.JWT_SECRET!,
|
||||||
|
{expiresIn: '15m' });
|
||||||
|
const newRefreshToken = jwt.sign({ userId: user.id }, process.env.JWT_REFRESH_SECRET!,
|
||||||
|
{expiresIn: '7d' });
|
||||||
|
await db.update(schema.users)
|
||||||
|
.set({ refreshToken: newRefreshToken })
|
||||||
|
.where(eq(schema.users.id, user.id));
|
||||||
|
|
||||||
|
return { accessToken: newAccessToken, refreshToken: newRefreshToken };
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(`Failed to refresh token: ${error.message}`);
|
||||||
|
} else {
|
||||||
|
throw new Error("Unknown error occurred while refreshing token");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const logout = async (userId: number) => {
|
||||||
|
try {
|
||||||
|
await db.update(schema.users)
|
||||||
|
.set({ lastLogin: null })
|
||||||
|
.where(eq(schema.users.id, userId));
|
||||||
|
return { success: true };
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(`Failed to logout: ${error.message}`);
|
||||||
|
} else {
|
||||||
|
throw new Error("Unknown error occurred while logging out");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// --- Relationship Management Functions --- //
|
// --- Relationship Management Functions --- //
|
||||||
|
|
||||||
export const createRelationshipRequest = async (requestorId: number, requestedId: number) => {
|
export const createRelationshipRequest = async (requestorId: number, requestedId: number) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user