Commit 496f7668 authored by 何 广一's avatar 何 广一
Browse files

prisma & auth api

parent 35afac8f
...@@ -39,3 +39,5 @@ yarn-error.log* ...@@ -39,3 +39,5 @@ yarn-error.log*
# typescript # typescript
*.tsbuildinfo *.tsbuildinfo
next-env.d.ts next-env.d.ts
/src/generated/prisma
...@@ -3,25 +3,32 @@ ...@@ -3,25 +3,32 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev --turbopack", "dev": "pnpm run redis & next dev --turbopack",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint" "lint": "next lint",
"redis": "start redis-server --port 6379"
}, },
"dependencies": { "dependencies": {
"@prisma/client": "6.14.0",
"next": "15.4.6",
"rate-limiter-flexible": "^7.2.0",
"react": "19.1.0", "react": "19.1.0",
"react-dom": "19.1.0", "react-dom": "19.1.0",
"next": "15.4.6" "redis": "^5.8.2",
"zod": "^4.1.1"
}, },
"devDependencies": { "devDependencies": {
"typescript": "^5", "@eslint/eslintrc": "^3",
"@tailwindcss/postcss": "^4",
"@types/node": "^20", "@types/node": "^20",
"@types/react": "^19", "@types/react": "^19",
"@types/react-dom": "^19", "@types/react-dom": "^19",
"@tailwindcss/postcss": "^4", "concurrently": "^9.2.0",
"tailwindcss": "^4",
"eslint": "^9", "eslint": "^9",
"eslint-config-next": "15.4.6", "eslint-config-next": "15.4.6",
"@eslint/eslintrc": "^3" "prisma": "6.14.0",
"tailwindcss": "^4",
"typescript": "^5"
} }
} }
...@@ -8,15 +8,27 @@ importers: ...@@ -8,15 +8,27 @@ importers:
.: .:
dependencies: dependencies:
'@prisma/client':
specifier: 6.14.0
version: 6.14.0(prisma@6.14.0(typescript@5.9.2))(typescript@5.9.2)
next: next:
specifier: 15.4.6 specifier: 15.4.6
version: 15.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0) version: 15.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
rate-limiter-flexible:
specifier: ^7.2.0
version: 7.2.0
react: react:
specifier: 19.1.0 specifier: 19.1.0
version: 19.1.0 version: 19.1.0
react-dom: react-dom:
specifier: 19.1.0 specifier: 19.1.0
version: 19.1.0(react@19.1.0) version: 19.1.0(react@19.1.0)
redis:
specifier: ^5.8.2
version: 5.8.2
zod:
specifier: ^4.1.1
version: 4.1.1
devDependencies: devDependencies:
'@eslint/eslintrc': '@eslint/eslintrc':
specifier: ^3 specifier: ^3
...@@ -33,12 +45,18 @@ importers: ...@@ -33,12 +45,18 @@ importers:
'@types/react-dom': '@types/react-dom':
specifier: ^19 specifier: ^19
version: 19.1.7(@types/react@19.1.9) version: 19.1.7(@types/react@19.1.9)
concurrently:
specifier: ^9.2.0
version: 9.2.0
eslint: eslint:
specifier: ^9 specifier: ^9
version: 9.33.0(jiti@2.5.1) version: 9.33.0(jiti@2.5.1)
eslint-config-next: eslint-config-next:
specifier: 15.4.6 specifier: 15.4.6
version: 15.4.6(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) version: 15.4.6(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
prisma:
specifier: 6.14.0
version: 6.14.0(typescript@5.9.2)
tailwindcss: tailwindcss:
specifier: ^4 specifier: ^4
version: 4.1.11 version: 4.1.11
...@@ -335,12 +353,73 @@ packages: ...@@ -335,12 +353,73 @@ packages:
resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==}
engines: {node: '>=12.4.0'} engines: {node: '>=12.4.0'}
'@prisma/client@6.14.0':
resolution: {integrity: sha512-8E/Nk3eL5g7RQIg/LUj1ICyDmhD053STjxrPxUtCRybs2s/2sOEcx9NpITuAOPn07HEpWBfhAVe1T/HYWXUPOw==}
engines: {node: '>=18.18'}
peerDependencies:
prisma: '*'
typescript: '>=5.1.0'
peerDependenciesMeta:
prisma:
optional: true
typescript:
optional: true
'@prisma/config@6.14.0':
resolution: {integrity: sha512-IwC7o5KNNGhmblLs23swnfBjADkacBb7wvyDXUWLwuvUQciKJZqyecU0jw0d7JRkswrj+XTL8fdr0y2/VerKQQ==}
'@prisma/debug@6.14.0':
resolution: {integrity: sha512-j4Lf+y+5QIJgQD4sJWSbkOD7geKx9CakaLp/TyTy/UDu9Wo0awvWCBH/BAxTHUaCpIl9USA5VS/KJhDqKJSwug==}
'@prisma/engines-version@6.14.0-25.717184b7b35ea05dfa71a3236b7af656013e1e49':
resolution: {integrity: sha512-EgN9ODJpiX45yvwcngoStp3uQPJ3l+AEVoQ6dMMO2QvmwIlnxfApzKmJQExzdo7/hqQANrz5txHJdGYHzOnGHA==}
'@prisma/engines@6.14.0':
resolution: {integrity: sha512-LhJjqsALFEcoAtF07nSaOkVguaxw/ZsgfROIYZ8bAZDobe7y8Wy+PkYQaPOK1iLSsFgV2MhCO/eNrI1gdSOj6w==}
'@prisma/fetch-engine@6.14.0':
resolution: {integrity: sha512-MPzYPOKMENYOaY3AcAbaKrfvXVlvTc6iHmTXsp9RiwCX+bPyfDMqMFVUSVXPYrXnrvEzhGHfyiFy0PRLHPysNg==}
'@prisma/get-platform@6.14.0':
resolution: {integrity: sha512-7VjuxKNwjnBhKfqPpMeWiHEa2sVjYzmHdl1slW6STuUCe9QnOY0OY1ljGSvz6wpG4U8DfbDqkG1yofd/1GINww==}
'@redis/bloom@5.8.2':
resolution: {integrity: sha512-855DR0ChetZLarblio5eM0yLwxA9Dqq50t8StXKp5bAtLT0G+rZ+eRzzqxl37sPqQKjUudSYypz55o6nNhbz0A==}
engines: {node: '>= 18'}
peerDependencies:
'@redis/client': ^5.8.2
'@redis/client@5.8.2':
resolution: {integrity: sha512-WtMScno3+eBpTac1Uav2zugXEoXqaU23YznwvFgkPwBQVwEHTDgOG7uEAObtZ/Nyn8SmAMbqkEubJaMOvnqdsQ==}
engines: {node: '>= 18'}
'@redis/json@5.8.2':
resolution: {integrity: sha512-uxpVfas3I0LccBX9rIfDgJ0dBrUa3+0Gc8sEwmQQH0vHi7C1Rx1Qn8Nv1QWz5bohoeIXMICFZRcyDONvum2l/w==}
engines: {node: '>= 18'}
peerDependencies:
'@redis/client': ^5.8.2
'@redis/search@5.8.2':
resolution: {integrity: sha512-cNv7HlgayavCBXqPXgaS97DRPVWFznuzsAmmuemi2TMCx5scwLiP50TeZvUS06h/MG96YNPe6A0Zt57yayfxwA==}
engines: {node: '>= 18'}
peerDependencies:
'@redis/client': ^5.8.2
'@redis/time-series@5.8.2':
resolution: {integrity: sha512-g2NlHM07fK8H4k+613NBsk3y70R2JIM2dPMSkhIjl2Z17SYvaYKdusz85d7VYOrZBWtDrHV/WD2E3vGu+zni8A==}
engines: {node: '>= 18'}
peerDependencies:
'@redis/client': ^5.8.2
'@rtsao/scc@1.1.0': '@rtsao/scc@1.1.0':
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
'@rushstack/eslint-patch@1.12.0': '@rushstack/eslint-patch@1.12.0':
resolution: {integrity: sha512-5EwMtOqvJMMa3HbmxLlF74e+3/HhwBTMcvt3nqVJgGCozO6hzIPOBlwm8mGVNR9SN2IJpxSnlxczyDjcn7qIyw==} resolution: {integrity: sha512-5EwMtOqvJMMa3HbmxLlF74e+3/HhwBTMcvt3nqVJgGCozO6hzIPOBlwm8mGVNR9SN2IJpxSnlxczyDjcn7qIyw==}
'@standard-schema/spec@1.0.0':
resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==}
'@swc/helpers@0.5.15': '@swc/helpers@0.5.15':
resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
...@@ -622,6 +701,10 @@ packages: ...@@ -622,6 +701,10 @@ packages:
ajv@6.12.6: ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
ansi-styles@4.3.0: ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'} engines: {node: '>=8'}
...@@ -697,6 +780,14 @@ packages: ...@@ -697,6 +780,14 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'} engines: {node: '>=8'}
c12@3.1.0:
resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==}
peerDependencies:
magicast: ^0.3.5
peerDependenciesMeta:
magicast:
optional: true
call-bind-apply-helpers@1.0.2: call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
...@@ -720,13 +811,28 @@ packages: ...@@ -720,13 +811,28 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'} engines: {node: '>=10'}
chokidar@4.0.3:
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
engines: {node: '>= 14.16.0'}
chownr@3.0.0: chownr@3.0.0:
resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
engines: {node: '>=18'} engines: {node: '>=18'}
citty@0.1.6:
resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==}
client-only@0.0.1: client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
cliui@8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'}
cluster-key-slot@1.1.2:
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
engines: {node: '>=0.10.0'}
color-convert@2.0.1: color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'} engines: {node: '>=7.0.0'}
...@@ -744,6 +850,18 @@ packages: ...@@ -744,6 +850,18 @@ packages:
concat-map@0.0.1: concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
concurrently@9.2.0:
resolution: {integrity: sha512-IsB/fiXTupmagMW4MNp2lx2cdSN2FfZq78vF90LBB+zZHArbIQZjQtzXCiXnvTxCZSvXanTqFLWBjw2UkLx1SQ==}
engines: {node: '>=18'}
hasBin: true
confbox@0.2.2:
resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==}
consola@3.4.2:
resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==}
engines: {node: ^14.18.0 || >=16.10.0}
cross-spawn@7.0.6: cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
...@@ -786,6 +904,10 @@ packages: ...@@ -786,6 +904,10 @@ packages:
deep-is@0.1.4: deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
deepmerge-ts@7.1.5:
resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==}
engines: {node: '>=16.0.0'}
define-data-property@1.1.4: define-data-property@1.1.4:
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
...@@ -794,6 +916,12 @@ packages: ...@@ -794,6 +916,12 @@ packages:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
defu@6.1.4:
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
destr@2.0.5:
resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
detect-libc@2.0.4: detect-libc@2.0.4:
resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
engines: {node: '>=8'} engines: {node: '>=8'}
...@@ -802,13 +930,27 @@ packages: ...@@ -802,13 +930,27 @@ packages:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
dotenv@16.6.1:
resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==}
engines: {node: '>=12'}
dunder-proto@1.0.1: dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
effect@3.16.12:
resolution: {integrity: sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
emoji-regex@9.2.2: emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
empathic@2.0.0:
resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==}
engines: {node: '>=14'}
enhanced-resolve@5.18.3: enhanced-resolve@5.18.3:
resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}
...@@ -845,6 +987,10 @@ packages: ...@@ -845,6 +987,10 @@ packages:
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
escape-string-regexp@4.0.0: escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'} engines: {node: '>=10'}
...@@ -965,6 +1111,13 @@ packages: ...@@ -965,6 +1111,13 @@ packages:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
exsolve@1.0.7:
resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==}
fast-check@3.23.2:
resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==}
engines: {node: '>=8.0.0'}
fast-deep-equal@3.1.3: fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
...@@ -1026,6 +1179,10 @@ packages: ...@@ -1026,6 +1179,10 @@ packages:
functions-have-names@1.2.3: functions-have-names@1.2.3:
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
get-intrinsic@1.3.0: get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
...@@ -1041,6 +1198,10 @@ packages: ...@@ -1041,6 +1198,10 @@ packages:
get-tsconfig@4.10.1: get-tsconfig@4.10.1:
resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==}
giget@2.0.0:
resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==}
hasBin: true
glob-parent@5.1.2: glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
...@@ -1160,6 +1321,10 @@ packages: ...@@ -1160,6 +1321,10 @@ packages:
resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
is-generator-function@1.1.0: is-generator-function@1.1.0:
resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
...@@ -1343,6 +1508,9 @@ packages: ...@@ -1343,6 +1508,9 @@ packages:
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@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
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
...@@ -1422,6 +1590,14 @@ packages: ...@@ -1422,6 +1590,14 @@ packages:
sass: sass:
optional: true optional: true
node-fetch-native@1.6.7:
resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==}
nypm@0.6.1:
resolution: {integrity: sha512-hlacBiRiv1k9hZFiphPUkfSQ/ZfQzZDzC+8z0wL3lvDAOUu/2NnChkKuMoMjNur/9OpKuz2QsIeiPVN0xM5Q0w==}
engines: {node: ^14.16.0 || >=16.10.0}
hasBin: true
object-assign@4.1.1: object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
...@@ -1454,6 +1630,9 @@ packages: ...@@ -1454,6 +1630,9 @@ packages:
resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
ohash@2.0.11:
resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
optionator@0.9.4: optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
...@@ -1485,6 +1664,12 @@ packages: ...@@ -1485,6 +1664,12 @@ packages:
path-parse@1.0.7: path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
perfect-debounce@1.0.0:
resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
picocolors@1.1.1: picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
...@@ -1496,6 +1681,9 @@ packages: ...@@ -1496,6 +1681,9 @@ packages:
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
engines: {node: '>=12'} engines: {node: '>=12'}
pkg-types@2.3.0:
resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==}
possible-typed-array-names@1.1.0: possible-typed-array-names@1.1.0:
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
...@@ -1512,6 +1700,16 @@ packages: ...@@ -1512,6 +1700,16 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
prisma@6.14.0:
resolution: {integrity: sha512-QEuCwxu+Uq9BffFw7in8In+WfbSUN0ewnaSUKloLkbJd42w6EyFckux4M0f7VwwHlM3A8ssaz4OyniCXlsn0WA==}
engines: {node: '>=18.18'}
hasBin: true
peerDependencies:
typescript: '>=5.1.0'
peerDependenciesMeta:
typescript:
optional: true
prop-types@15.8.1: prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
...@@ -1519,9 +1717,18 @@ packages: ...@@ -1519,9 +1717,18 @@ packages:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'} engines: {node: '>=6'}
pure-rand@6.1.0:
resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
queue-microtask@1.2.3: queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
rate-limiter-flexible@7.2.0:
resolution: {integrity: sha512-hrf0vIS/WOBegnHg+uPXxsXhuQYlNGfZiCmK5Wgudb12xlZUhpv9yD23yp/EW6BKQosshqnIQRQV+r3jyfIGQg==}
rc9@2.1.2:
resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==}
react-dom@19.1.0: react-dom@19.1.0:
resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==}
peerDependencies: peerDependencies:
...@@ -1534,6 +1741,14 @@ packages: ...@@ -1534,6 +1741,14 @@ packages:
resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
readdirp@4.1.2:
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
engines: {node: '>= 14.18.0'}
redis@5.8.2:
resolution: {integrity: sha512-31vunZj07++Y1vcFGcnNWEf5jPoTkGARgfWI4+Tk55vdwHxhAvug8VEtW7Cx+/h47NuJTEg/JL77zAwC6E0OeA==}
engines: {node: '>= 18'}
reflect.getprototypeof@1.0.10: reflect.getprototypeof@1.0.10:
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
...@@ -1542,6 +1757,10 @@ packages: ...@@ -1542,6 +1757,10 @@ packages:
resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
resolve-from@4.0.0: resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'} engines: {node: '>=4'}
...@@ -1565,6 +1784,9 @@ packages: ...@@ -1565,6 +1784,9 @@ packages:
run-parallel@1.2.0: run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
rxjs@7.8.2:
resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==}
safe-array-concat@1.1.3: safe-array-concat@1.1.3:
resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
engines: {node: '>=0.4'} engines: {node: '>=0.4'}
...@@ -1613,6 +1835,10 @@ packages: ...@@ -1613,6 +1835,10 @@ packages:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'} engines: {node: '>=8'}
shell-quote@1.8.3:
resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==}
engines: {node: '>= 0.4'}
side-channel-list@1.0.0: side-channel-list@1.0.0:
resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
...@@ -1643,6 +1869,10 @@ packages: ...@@ -1643,6 +1869,10 @@ packages:
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
string.prototype.includes@2.0.1: string.prototype.includes@2.0.1:
resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
...@@ -1666,6 +1896,10 @@ packages: ...@@ -1666,6 +1896,10 @@ packages:
resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
strip-bom@3.0.0: strip-bom@3.0.0:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'} engines: {node: '>=4'}
...@@ -1691,6 +1925,10 @@ packages: ...@@ -1691,6 +1925,10 @@ packages:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'} engines: {node: '>=8'}
supports-color@8.1.1:
resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
engines: {node: '>=10'}
supports-preserve-symlinks-flag@1.0.0: supports-preserve-symlinks-flag@1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
...@@ -1706,6 +1944,9 @@ packages: ...@@ -1706,6 +1944,9 @@ packages:
resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==}
engines: {node: '>=18'} engines: {node: '>=18'}
tinyexec@1.0.1:
resolution: {integrity: sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==}
tinyglobby@0.2.14: tinyglobby@0.2.14:
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
engines: {node: '>=12.0.0'} engines: {node: '>=12.0.0'}
...@@ -1714,6 +1955,10 @@ packages: ...@@ -1714,6 +1955,10 @@ packages:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'} engines: {node: '>=8.0'}
tree-kill@1.2.2:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
ts-api-utils@2.1.0: ts-api-utils@2.1.0:
resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==}
engines: {node: '>=18.12'} engines: {node: '>=18.12'}
...@@ -1789,14 +2034,33 @@ packages: ...@@ -1789,14 +2034,33 @@ packages:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
yallist@5.0.0: yallist@5.0.0:
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
engines: {node: '>=18'} engines: {node: '>=18'}
yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
yargs@17.7.2:
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
engines: {node: '>=12'}
yocto-queue@0.1.0: yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'} engines: {node: '>=10'}
zod@4.1.1:
resolution: {integrity: sha512-SgMZK/h8Tigt9nnKkfJMvB/mKjiJXaX26xegP4sa+0wHIFVFWVlsQGdhklDmuargBD3Hsi3rsQRIzwJIhTPJHA==}
snapshots: snapshots:
'@alloc/quick-lru@5.2.0': {} '@alloc/quick-lru@5.2.0': {}
...@@ -2034,10 +2298,67 @@ snapshots: ...@@ -2034,10 +2298,67 @@ snapshots:
'@nolyfill/is-core-module@1.0.39': {} '@nolyfill/is-core-module@1.0.39': {}
'@prisma/client@6.14.0(prisma@6.14.0(typescript@5.9.2))(typescript@5.9.2)':
optionalDependencies:
prisma: 6.14.0(typescript@5.9.2)
typescript: 5.9.2
'@prisma/config@6.14.0':
dependencies:
c12: 3.1.0
deepmerge-ts: 7.1.5
effect: 3.16.12
empathic: 2.0.0
transitivePeerDependencies:
- magicast
'@prisma/debug@6.14.0': {}
'@prisma/engines-version@6.14.0-25.717184b7b35ea05dfa71a3236b7af656013e1e49': {}
'@prisma/engines@6.14.0':
dependencies:
'@prisma/debug': 6.14.0
'@prisma/engines-version': 6.14.0-25.717184b7b35ea05dfa71a3236b7af656013e1e49
'@prisma/fetch-engine': 6.14.0
'@prisma/get-platform': 6.14.0
'@prisma/fetch-engine@6.14.0':
dependencies:
'@prisma/debug': 6.14.0
'@prisma/engines-version': 6.14.0-25.717184b7b35ea05dfa71a3236b7af656013e1e49
'@prisma/get-platform': 6.14.0
'@prisma/get-platform@6.14.0':
dependencies:
'@prisma/debug': 6.14.0
'@redis/bloom@5.8.2(@redis/client@5.8.2)':
dependencies:
'@redis/client': 5.8.2
'@redis/client@5.8.2':
dependencies:
cluster-key-slot: 1.1.2
'@redis/json@5.8.2(@redis/client@5.8.2)':
dependencies:
'@redis/client': 5.8.2
'@redis/search@5.8.2(@redis/client@5.8.2)':
dependencies:
'@redis/client': 5.8.2
'@redis/time-series@5.8.2(@redis/client@5.8.2)':
dependencies:
'@redis/client': 5.8.2
'@rtsao/scc@1.1.0': {} '@rtsao/scc@1.1.0': {}
'@rushstack/eslint-patch@1.12.0': {} '@rushstack/eslint-patch@1.12.0': {}
'@standard-schema/spec@1.0.0': {}
'@swc/helpers@0.5.15': '@swc/helpers@0.5.15':
dependencies: dependencies:
tslib: 2.8.1 tslib: 2.8.1
...@@ -2302,6 +2623,8 @@ snapshots: ...@@ -2302,6 +2623,8 @@ snapshots:
json-schema-traverse: 0.4.1 json-schema-traverse: 0.4.1
uri-js: 4.4.1 uri-js: 4.4.1
ansi-regex@5.0.1: {}
ansi-styles@4.3.0: ansi-styles@4.3.0:
dependencies: dependencies:
color-convert: 2.0.1 color-convert: 2.0.1
...@@ -2404,6 +2727,21 @@ snapshots: ...@@ -2404,6 +2727,21 @@ snapshots:
dependencies: dependencies:
fill-range: 7.1.1 fill-range: 7.1.1
c12@3.1.0:
dependencies:
chokidar: 4.0.3
confbox: 0.2.2
defu: 6.1.4
dotenv: 16.6.1
exsolve: 1.0.7
giget: 2.0.0
jiti: 2.5.1
ohash: 2.0.11
pathe: 2.0.3
perfect-debounce: 1.0.0
pkg-types: 2.3.0
rc9: 2.1.2
call-bind-apply-helpers@1.0.2: call-bind-apply-helpers@1.0.2:
dependencies: dependencies:
es-errors: 1.3.0 es-errors: 1.3.0
...@@ -2430,10 +2768,26 @@ snapshots: ...@@ -2430,10 +2768,26 @@ snapshots:
ansi-styles: 4.3.0 ansi-styles: 4.3.0
supports-color: 7.2.0 supports-color: 7.2.0
chokidar@4.0.3:
dependencies:
readdirp: 4.1.2
chownr@3.0.0: {} chownr@3.0.0: {}
citty@0.1.6:
dependencies:
consola: 3.4.2
client-only@0.0.1: {} client-only@0.0.1: {}
cliui@8.0.1:
dependencies:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
cluster-key-slot@1.1.2: {}
color-convert@2.0.1: color-convert@2.0.1:
dependencies: dependencies:
color-name: 1.1.4 color-name: 1.1.4
...@@ -2454,6 +2808,20 @@ snapshots: ...@@ -2454,6 +2808,20 @@ snapshots:
concat-map@0.0.1: {} concat-map@0.0.1: {}
concurrently@9.2.0:
dependencies:
chalk: 4.1.2
lodash: 4.17.21
rxjs: 7.8.2
shell-quote: 1.8.3
supports-color: 8.1.1
tree-kill: 1.2.2
yargs: 17.7.2
confbox@0.2.2: {}
consola@3.4.2: {}
cross-spawn@7.0.6: cross-spawn@7.0.6:
dependencies: dependencies:
path-key: 3.1.1 path-key: 3.1.1
...@@ -2492,6 +2860,8 @@ snapshots: ...@@ -2492,6 +2860,8 @@ snapshots:
deep-is@0.1.4: {} deep-is@0.1.4: {}
deepmerge-ts@7.1.5: {}
define-data-property@1.1.4: define-data-property@1.1.4:
dependencies: dependencies:
es-define-property: 1.0.1 es-define-property: 1.0.1
...@@ -2504,20 +2874,35 @@ snapshots: ...@@ -2504,20 +2874,35 @@ snapshots:
has-property-descriptors: 1.0.2 has-property-descriptors: 1.0.2
object-keys: 1.1.1 object-keys: 1.1.1
defu@6.1.4: {}
destr@2.0.5: {}
detect-libc@2.0.4: {} detect-libc@2.0.4: {}
doctrine@2.1.0: doctrine@2.1.0:
dependencies: dependencies:
esutils: 2.0.3 esutils: 2.0.3
dotenv@16.6.1: {}
dunder-proto@1.0.1: dunder-proto@1.0.1:
dependencies: dependencies:
call-bind-apply-helpers: 1.0.2 call-bind-apply-helpers: 1.0.2
es-errors: 1.3.0 es-errors: 1.3.0
gopd: 1.2.0 gopd: 1.2.0
effect@3.16.12:
dependencies:
'@standard-schema/spec': 1.0.0
fast-check: 3.23.2
emoji-regex@8.0.0: {}
emoji-regex@9.2.2: {} emoji-regex@9.2.2: {}
empathic@2.0.0: {}
enhanced-resolve@5.18.3: enhanced-resolve@5.18.3:
dependencies: dependencies:
graceful-fs: 4.2.11 graceful-fs: 4.2.11
...@@ -2624,6 +3009,8 @@ snapshots: ...@@ -2624,6 +3009,8 @@ snapshots:
is-date-object: 1.1.0 is-date-object: 1.1.0
is-symbol: 1.1.1 is-symbol: 1.1.1
escalade@3.2.0: {}
escape-string-regexp@4.0.0: {} escape-string-regexp@4.0.0: {}
eslint-config-next@15.4.6(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2): eslint-config-next@15.4.6(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2):
...@@ -2823,6 +3210,12 @@ snapshots: ...@@ -2823,6 +3210,12 @@ snapshots:
esutils@2.0.3: {} esutils@2.0.3: {}
exsolve@1.0.7: {}
fast-check@3.23.2:
dependencies:
pure-rand: 6.1.0
fast-deep-equal@3.1.3: {} fast-deep-equal@3.1.3: {}
fast-glob@3.3.1: fast-glob@3.3.1:
...@@ -2890,6 +3283,8 @@ snapshots: ...@@ -2890,6 +3283,8 @@ snapshots:
functions-have-names@1.2.3: {} functions-have-names@1.2.3: {}
get-caller-file@2.0.5: {}
get-intrinsic@1.3.0: get-intrinsic@1.3.0:
dependencies: dependencies:
call-bind-apply-helpers: 1.0.2 call-bind-apply-helpers: 1.0.2
...@@ -2918,6 +3313,15 @@ snapshots: ...@@ -2918,6 +3313,15 @@ snapshots:
dependencies: dependencies:
resolve-pkg-maps: 1.0.0 resolve-pkg-maps: 1.0.0
giget@2.0.0:
dependencies:
citty: 0.1.6
consola: 3.4.2
defu: 6.1.4
node-fetch-native: 1.6.7
nypm: 0.6.1
pathe: 2.0.3
glob-parent@5.1.2: glob-parent@5.1.2:
dependencies: dependencies:
is-glob: 4.0.3 is-glob: 4.0.3
...@@ -3031,6 +3435,8 @@ snapshots: ...@@ -3031,6 +3435,8 @@ snapshots:
dependencies: dependencies:
call-bound: 1.0.4 call-bound: 1.0.4
is-fullwidth-code-point@3.0.0: {}
is-generator-function@1.1.0: is-generator-function@1.1.0:
dependencies: dependencies:
call-bound: 1.0.4 call-bound: 1.0.4
...@@ -3196,6 +3602,8 @@ snapshots: ...@@ -3196,6 +3602,8 @@ snapshots:
lodash.merge@4.6.2: {} lodash.merge@4.6.2: {}
lodash@4.17.21: {}
loose-envify@1.4.0: loose-envify@1.4.0:
dependencies: dependencies:
js-tokens: 4.0.0 js-tokens: 4.0.0
...@@ -3262,6 +3670,16 @@ snapshots: ...@@ -3262,6 +3670,16 @@ snapshots:
- '@babel/core' - '@babel/core'
- babel-plugin-macros - babel-plugin-macros
node-fetch-native@1.6.7: {}
nypm@0.6.1:
dependencies:
citty: 0.1.6
consola: 3.4.2
pathe: 2.0.3
pkg-types: 2.3.0
tinyexec: 1.0.1
object-assign@4.1.1: {} object-assign@4.1.1: {}
object-inspect@1.13.4: {} object-inspect@1.13.4: {}
...@@ -3304,6 +3722,8 @@ snapshots: ...@@ -3304,6 +3722,8 @@ snapshots:
define-properties: 1.2.1 define-properties: 1.2.1
es-object-atoms: 1.1.1 es-object-atoms: 1.1.1
ohash@2.0.11: {}
optionator@0.9.4: optionator@0.9.4:
dependencies: dependencies:
deep-is: 0.1.4 deep-is: 0.1.4
...@@ -3337,12 +3757,22 @@ snapshots: ...@@ -3337,12 +3757,22 @@ snapshots:
path-parse@1.0.7: {} path-parse@1.0.7: {}
pathe@2.0.3: {}
perfect-debounce@1.0.0: {}
picocolors@1.1.1: {} picocolors@1.1.1: {}
picomatch@2.3.1: {} picomatch@2.3.1: {}
picomatch@4.0.3: {} picomatch@4.0.3: {}
pkg-types@2.3.0:
dependencies:
confbox: 0.2.2
exsolve: 1.0.7
pathe: 2.0.3
possible-typed-array-names@1.1.0: {} possible-typed-array-names@1.1.0: {}
postcss@8.4.31: postcss@8.4.31:
...@@ -3359,6 +3789,15 @@ snapshots: ...@@ -3359,6 +3789,15 @@ snapshots:
prelude-ls@1.2.1: {} prelude-ls@1.2.1: {}
prisma@6.14.0(typescript@5.9.2):
dependencies:
'@prisma/config': 6.14.0
'@prisma/engines': 6.14.0
optionalDependencies:
typescript: 5.9.2
transitivePeerDependencies:
- magicast
prop-types@15.8.1: prop-types@15.8.1:
dependencies: dependencies:
loose-envify: 1.4.0 loose-envify: 1.4.0
...@@ -3367,8 +3806,17 @@ snapshots: ...@@ -3367,8 +3806,17 @@ snapshots:
punycode@2.3.1: {} punycode@2.3.1: {}
pure-rand@6.1.0: {}
queue-microtask@1.2.3: {} queue-microtask@1.2.3: {}
rate-limiter-flexible@7.2.0: {}
rc9@2.1.2:
dependencies:
defu: 6.1.4
destr: 2.0.5
react-dom@19.1.0(react@19.1.0): react-dom@19.1.0(react@19.1.0):
dependencies: dependencies:
react: 19.1.0 react: 19.1.0
...@@ -3378,6 +3826,16 @@ snapshots: ...@@ -3378,6 +3826,16 @@ snapshots:
react@19.1.0: {} react@19.1.0: {}
readdirp@4.1.2: {}
redis@5.8.2:
dependencies:
'@redis/bloom': 5.8.2(@redis/client@5.8.2)
'@redis/client': 5.8.2
'@redis/json': 5.8.2(@redis/client@5.8.2)
'@redis/search': 5.8.2(@redis/client@5.8.2)
'@redis/time-series': 5.8.2(@redis/client@5.8.2)
reflect.getprototypeof@1.0.10: reflect.getprototypeof@1.0.10:
dependencies: dependencies:
call-bind: 1.0.8 call-bind: 1.0.8
...@@ -3398,6 +3856,8 @@ snapshots: ...@@ -3398,6 +3856,8 @@ snapshots:
gopd: 1.2.0 gopd: 1.2.0
set-function-name: 2.0.2 set-function-name: 2.0.2
require-directory@2.1.1: {}
resolve-from@4.0.0: {} resolve-from@4.0.0: {}
resolve-pkg-maps@1.0.0: {} resolve-pkg-maps@1.0.0: {}
...@@ -3420,6 +3880,10 @@ snapshots: ...@@ -3420,6 +3880,10 @@ snapshots:
dependencies: dependencies:
queue-microtask: 1.2.3 queue-microtask: 1.2.3
rxjs@7.8.2:
dependencies:
tslib: 2.8.1
safe-array-concat@1.1.3: safe-array-concat@1.1.3:
dependencies: dependencies:
call-bind: 1.0.8 call-bind: 1.0.8
...@@ -3503,6 +3967,8 @@ snapshots: ...@@ -3503,6 +3967,8 @@ snapshots:
shebang-regex@3.0.0: {} shebang-regex@3.0.0: {}
shell-quote@1.8.3: {}
side-channel-list@1.0.0: side-channel-list@1.0.0:
dependencies: dependencies:
es-errors: 1.3.0 es-errors: 1.3.0
...@@ -3545,6 +4011,12 @@ snapshots: ...@@ -3545,6 +4011,12 @@ snapshots:
es-errors: 1.3.0 es-errors: 1.3.0
internal-slot: 1.1.0 internal-slot: 1.1.0
string-width@4.2.3:
dependencies:
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
string.prototype.includes@2.0.1: string.prototype.includes@2.0.1:
dependencies: dependencies:
call-bind: 1.0.8 call-bind: 1.0.8
...@@ -3595,6 +4067,10 @@ snapshots: ...@@ -3595,6 +4067,10 @@ snapshots:
define-properties: 1.2.1 define-properties: 1.2.1
es-object-atoms: 1.1.1 es-object-atoms: 1.1.1
strip-ansi@6.0.1:
dependencies:
ansi-regex: 5.0.1
strip-bom@3.0.0: {} strip-bom@3.0.0: {}
strip-json-comments@3.1.1: {} strip-json-comments@3.1.1: {}
...@@ -3608,6 +4084,10 @@ snapshots: ...@@ -3608,6 +4084,10 @@ snapshots:
dependencies: dependencies:
has-flag: 4.0.0 has-flag: 4.0.0
supports-color@8.1.1:
dependencies:
has-flag: 4.0.0
supports-preserve-symlinks-flag@1.0.0: {} supports-preserve-symlinks-flag@1.0.0: {}
tailwindcss@4.1.11: {} tailwindcss@4.1.11: {}
...@@ -3623,6 +4103,8 @@ snapshots: ...@@ -3623,6 +4103,8 @@ snapshots:
mkdirp: 3.0.1 mkdirp: 3.0.1
yallist: 5.0.0 yallist: 5.0.0
tinyexec@1.0.1: {}
tinyglobby@0.2.14: tinyglobby@0.2.14:
dependencies: dependencies:
fdir: 6.4.6(picomatch@4.0.3) fdir: 6.4.6(picomatch@4.0.3)
...@@ -3632,6 +4114,8 @@ snapshots: ...@@ -3632,6 +4114,8 @@ snapshots:
dependencies: dependencies:
is-number: 7.0.0 is-number: 7.0.0
tree-kill@1.2.2: {}
ts-api-utils@2.1.0(typescript@5.9.2): ts-api-utils@2.1.0(typescript@5.9.2):
dependencies: dependencies:
typescript: 5.9.2 typescript: 5.9.2
...@@ -3768,6 +4252,28 @@ snapshots: ...@@ -3768,6 +4252,28 @@ snapshots:
word-wrap@1.2.5: {} word-wrap@1.2.5: {}
wrap-ansi@7.0.0:
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
y18n@5.0.8: {}
yallist@5.0.0: {} yallist@5.0.0: {}
yargs-parser@21.1.1: {}
yargs@17.7.2:
dependencies:
cliui: 8.0.1
escalade: 3.2.0
get-caller-file: 2.0.5
require-directory: 2.1.1
string-width: 4.2.3
y18n: 5.0.8
yargs-parser: 21.1.1
yocto-queue@0.1.0: {} yocto-queue@0.1.0: {}
zod@4.1.1: {}
-- CreateTable
CREATE TABLE "User" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL,
"password" TEXT NOT NULL,
"salt" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "Room" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"roomName" TEXT NOT NULL,
"creatorId" INTEGER NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Room_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "Message" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"content" TEXT NOT NULL,
"roomId" INTEGER NOT NULL,
"senderId" INTEGER NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "Message_roomId_fkey" FOREIGN KEY ("roomId") REFERENCES "Room" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "Message_senderId_fkey" FOREIGN KEY ("senderId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "User_name_key" ON "User"("name");
-- CreateIndex
CREATE INDEX "Room_creatorId_idx" ON "Room"("creatorId");
-- CreateIndex
CREATE INDEX "Message_roomId_idx" ON "Message"("roomId");
-- CreateIndex
CREATE INDEX "Message_senderId_idx" ON "Message"("senderId");
/*
Warnings:
- You are about to drop the column `senderId` on the `Message` table. All the data in the column will be lost.
- You are about to drop the column `creatorId` on the `Room` table. All the data in the column will be lost.
- The primary key for the `User` table will be changed. If it partially fails, the table could be left without primary key constraint.
- You are about to drop the column `id` on the `User` table. All the data in the column will be lost.
- Added the required column `senderName` to the `Message` table without a default value. This is not possible if the table is not empty.
- Added the required column `creatorToken` to the `Room` table without a default value. This is not possible if the table is not empty.
- Added the required column `userToken` to the `User` table without a default value. This is not possible if the table is not empty.
*/
-- CreateTable
CREATE TABLE "AuthToken" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"token" TEXT NOT NULL,
"userName" TEXT NOT NULL,
"expiresAt" DATETIME NOT NULL,
"ua" TEXT,
"ip" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "AuthToken_userName_fkey" FOREIGN KEY ("userName") REFERENCES "User" ("name") ON DELETE CASCADE ON UPDATE CASCADE
);
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Message" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"content" TEXT NOT NULL,
"roomId" INTEGER NOT NULL,
"senderName" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "Message_roomId_fkey" FOREIGN KEY ("roomId") REFERENCES "Room" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "Message_senderName_fkey" FOREIGN KEY ("senderName") REFERENCES "User" ("name") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_Message" ("content", "createdAt", "id", "roomId") SELECT "content", "createdAt", "id", "roomId" FROM "Message";
DROP TABLE "Message";
ALTER TABLE "new_Message" RENAME TO "Message";
CREATE INDEX "Message_roomId_idx" ON "Message"("roomId");
CREATE INDEX "Message_senderName_idx" ON "Message"("senderName");
CREATE TABLE "new_Room" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"roomName" TEXT NOT NULL,
"creatorToken" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Room_creatorToken_fkey" FOREIGN KEY ("creatorToken") REFERENCES "User" ("userToken") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_Room" ("createdAt", "id", "roomName", "updatedAt") SELECT "createdAt", "id", "roomName", "updatedAt" FROM "Room";
DROP TABLE "Room";
ALTER TABLE "new_Room" RENAME TO "Room";
CREATE INDEX "Room_creatorToken_idx" ON "Room"("creatorToken");
CREATE TABLE "new_User" (
"name" TEXT NOT NULL PRIMARY KEY,
"password" TEXT NOT NULL,
"salt" TEXT NOT NULL,
"userToken" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_User" ("createdAt", "name", "password", "salt", "updatedAt") SELECT "createdAt", "name", "password", "salt", "updatedAt" FROM "User";
DROP TABLE "User";
ALTER TABLE "new_User" RENAME TO "User";
CREATE UNIQUE INDEX "User_name_key" ON "User"("name");
CREATE UNIQUE INDEX "User_userToken_key" ON "User"("userToken");
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;
-- CreateIndex
CREATE UNIQUE INDEX "AuthToken_token_key" ON "AuthToken"("token");
-- CreateIndex
CREATE INDEX "AuthToken_userName_idx" ON "AuthToken"("userName");
-- CreateIndex
CREATE INDEX "AuthToken_token_idx" ON "AuthToken"("token");
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "sqlite"
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
generator client {
provider = "prisma-client-js"
output = "../src/generated/prisma"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model User {
name String @id @unique
password String
salt String
userToken String @unique
createdRooms Room[] @relation("RoomCreator")
messages Message[]
authTokens AuthToken[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model AuthToken {
id Int @id @default(autoincrement())
token String @unique
userName String
user User @relation(fields: [userName], references: [name], onDelete: Cascade)
expiresAt DateTime // 过期时间
ua String?
ip String?
createdAt DateTime @default(now())
@@index([userName])
@@index([token])
}
model Room {
id Int @id @default(autoincrement())
roomName String
creatorToken String
creator User @relation("RoomCreator", fields: [creatorToken], references: [userToken], onDelete: Cascade)
messages Message[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([creatorToken])
}
model Message {
id Int @id @default(autoincrement())
content String
roomId Int
room Room @relation(fields: [roomId], references: [id], onDelete: Cascade)
senderName String
sender User @relation(fields: [senderName], references: [name], onDelete: Cascade)
createdAt DateTime @default(now())
@@index([roomId])
@@index([senderName])
}
\ No newline at end of file
import { NextRequest, NextResponse } from 'next/server';
import * as Ty from '../../../interface'
import * as Db from '../../room-api';
import * as Auth from '../../login-interface';
/*
- url: /api/auth/autoLogin
- method: POST
- Read & Check Cookie
*/
export async function POST(req: NextRequest): Promise<NextResponse<Ty.BackendResponse<Auth.LoginResult | null>>> {
const cookieData = await Db.VerifyCookie(req.cookies)
if('code' in cookieData) return NextResponse.json(cookieData);
const Args: Auth.AutoLoginArgs = {
cookie: cookieData
};
const loginResult = await Db.AutoLogin(Args)
return NextResponse.json(loginResult)
}
\ No newline at end of file
import { NextRequest, NextResponse } from 'next/server';
import * as Ty from '../../../interface'
import * as Db from '../../room-api';
import * as Auth from '../../login-interface';
/*
- url: /api/auth/login
- method: POST
- Set Cookie
*/
export async function POST(req: NextRequest): Promise<NextResponse<Ty.BackendResponse<Auth.LoginResult | null>>> {
const result = Auth.authArgsSchema.safeParse(await req.json());
if (!result.success) {
return Db.MakeError('无效的请求参数', 114514, 400);
}
const Args: Auth.AuthArgs = result.data;
Args.userIP = req.headers.get('x-forwarded-for') || null;
const loginResult = await Db.Login(Args);
const res = NextResponse.json(loginResult);
if(loginResult.data)
{
res.cookies.set('userToken', loginResult.data.cookie.userToken, { path: '/' });
res.cookies.set('authToken', loginResult.data.cookie.authToken, { path: '/' });
}
return res;
}
\ No newline at end of file
import { NextRequest, NextResponse } from 'next/server';
import * as Ty from '../../../interface'
import * as Db from '../../room-api';
import * as Auth from '../../login-interface';
/*
- url: /api/auth/logout
- method: POST
- Read & Check Cookie
*/
export async function POST(req: NextRequest): Promise<NextResponse<Ty.BackendResponse<null>>> {
const cookieData = await Db.VerifyCookie(req.cookies)
if('code' in cookieData)return NextResponse.json(cookieData);
const logoutResult = await Db.Logout(cookieData);
const res = NextResponse.json(logoutResult);
res.cookies.set('userToken', '', { maxAge: 0, path: '/' });
res.cookies.set('authToken', '', { maxAge: 0, path: '/' });
return res;
}
\ No newline at end of file
import { NextRequest, NextResponse } from 'next/server';
import * as Ty from '../../../interface'
import * as Db from '../../room-api';
import * as Auth from '../../login-interface';
/*
- url: /api/auth/register
- method: POST
*/
export async function POST(req: NextRequest): Promise<NextResponse<Ty.BackendResponse<Auth.RegisterResult | null>>> {
const result = Auth.authArgsSchema.safeParse(await req.json());
if (!result.success) {
return Db.MakeError('无效的请求参数', 114514, 400);
}
const Args: Auth.AuthArgs = result.data;
Args.userIP = req.headers.get('x-forwarded-for') || null;
const registerResult = await Db.Register(Args);
return NextResponse.json(registerResult);
}
\ No newline at end of file
import { NextRequest, NextResponse } from 'next/server';
import * as Ty from '../../../interface'
import * as Db from '../../room-api';
import * as Auth from '../../login-interface';
/*
- url: /api/auth/startSession
- method: GET
*/
export async function GET(req: NextRequest): Promise<NextResponse<Ty.BackendResponse<Auth.Session | null>>> {
const result = await Db.StartAuthSession();
return NextResponse.json(result);
}
\ No newline at end of file
import {z} from 'zod';
export interface Session {
sessionId: string;
}
export interface AuthArgs {
sessionId: string;
username: string;
password: string;
userAgent: string | null;
userIP: string | null;
}
export interface LoginCookieData {
userToken: string;
authToken: string;
}
export interface LoginResult {
user: string;
cookie: LoginCookieData;
}
export interface RegisterResult {
user: string;
}
export interface AutoLoginArgs {
cookie: LoginCookieData;
}
export const cookieSchema = z.object({
userToken: z.string().nullable(),
authToken: z.string().nullable()
});
export const minPasswordLength = 8;
export const maxPasswordLength = 100;
export const authArgsSchema = z.object({
sessionId: z.string(),
username: z.string().min(2).max(100),
password: z.string().min(minPasswordLength).max(maxPasswordLength),
userAgent: z.string().max(200).nullable(),
userIP: z.string().max(100).nullable()
});
export const reloginErrorCode = 1919810;
export const invalidUserErrorCode = 8848;
export const notAuthorizedToDeleteRoomErrorCode = 2;
...@@ -14,6 +14,10 @@ interface MessageAddArgs { ...@@ -14,6 +14,10 @@ interface MessageAddArgs {
- response: null (只要code为0即为成功) - response: null (只要code为0即为成功)
*/ */
export async function POST(req: NextRequest): Promise<NextResponse<Ty.BackendResponse<null>>> { export async function POST(req: NextRequest): Promise<NextResponse<Ty.BackendResponse<null>>> {
const cookieData = await Db.VerifyCookie(req.cookies);
if('code' in cookieData)return NextResponse.json(cookieData);
const { roomId, content, sender } = await req.json() as Ty.MessageAddArgs; const { roomId, content, sender } = await req.json() as Ty.MessageAddArgs;
const response = await Db.AddMessage({ roomId, content, sender }); const response = await Db.AddMessage({ roomId, content, sender });
return NextResponse.json(response); return NextResponse.json(response);
......
import { NextRequest, NextResponse } from 'next/server'; import { NextRequest, NextResponse } from 'next/server';
import { RequestCookies } from 'next/dist/compiled/@edge-runtime/cookies';
import { createHash, randomBytes } from 'crypto';
import * as Ty from '../interface' import * as Ty from '../interface'
import {RoomInfo, State} from './tmp-state' import {prisma, redis} from "@/lib/db";
import * as Auth from './login-interface';
export async function MakeError(message: string, code: number = 1): Promise<NextResponse<Ty.BackendResponse<null>>> { export async function MakeError(message: string, code: number = 1, status: number = 500): Promise<NextResponse<Ty.BackendResponse<null>>> {
return NextResponse.json({ return NextResponse.json({
code, code,
message, message,
data: null data: null
}); }, { status });
} }
export async function GetRoomList(): Promise<Ty.BackendResponse<Ty.RoomListRes>> { const UserExists = async (name: string): Promise<boolean> => {
console.log('获取到的房间列表:', State.fakeRooms as Ty.RoomPreviewInfo[]); const user = await prisma.user.findUnique({
where: { name },
select: { name: true }
});
return user !== null;
};
const toFrontMsg = async (m: any) : Promise<Ty.Message | null> => {
if(!m.senderName.length) return null;
if(!await UserExists(m.senderName)) return null;
return { return {
code: 0, messageId: m.id,
message: '房间获取成功', roomId: m.roomId,
data: { sender: m.senderName,
rooms: State.fakeRooms as Ty.RoomPreviewInfo[] content: m.content,
} time: m.createdAt.getTime(),
}; };
};
const getUserToken = async (name: string) => {
const user = await prisma.user.findUnique({
where: { name },
select: { userToken: true }
});
return user ? user.userToken : null;
};
const getRandomToken = (): string => {
return [...crypto.getRandomValues(new Uint8Array(16))]
.map(b => b.toString(36))
.join('');
};
const getRandomStr = () => (randomBytes(32).toString('hex'));
export async function GetRoomList(): Promise<Ty.BackendResponse<Ty.RoomListRes | null>> {
const rooms = await prisma.room.findMany({
select: {
id: true,
roomName: true,
messages: {
orderBy: { createdAt: 'desc' },
take: 1
},
},
});
const preview: Ty.RoomPreviewInfo[] = await Promise.all(rooms.map(async (r) => {
const lastMessage = r.messages[0] ? await toFrontMsg(r.messages[0]) : null;
return {
roomId: r.id,
roomName: r.roomName,
lastMessage
};
}));
return {
code: 0,
message: '房间获取成功',
data: {
rooms: preview
}
};
} }
export async function AddRoom(data: Ty.RoomAddArgs): Promise<Ty.BackendResponse<Ty.RoomAddResult>> { export async function AddRoom(data: Ty.RoomAddArgs): Promise<Ty.BackendResponse<Ty.RoomAddResult>> {
const newRoom: RoomInfo = {
roomId: State.maxRoomId + 1, const userName = data.user;
roomName: data.roomName, const creatorToken = await getUserToken(userName);
lastMessage: null,
creator: data.user if(!creatorToken)
}; {
State.fakeRooms = [...State.fakeRooms, newRoom]; return {
console.log('当前房间列表:', State.fakeRooms); code: 1,
State.maxRoomId++; message: '用户不存在',
data: {
roomId: -1
}
};
}
const newRoom = await prisma.room.create({
data: {
roomName: data.roomName,
creatorToken
}
});
return { return {
code: 0, code: 0,
message: '房间创建成功', message: '房间创建成功',
data: { data: {
roomId: newRoom.roomId roomId: newRoom.id
} }
}; };
} }
export async function GetMessageList(data : Ty.RoomMessageListArgs): Promise<Ty.BackendResponse<Ty.RoomMessageListRes>> { export async function GetMessageList(data : Ty.RoomMessageListArgs): Promise<Ty.BackendResponse<Ty.RoomMessageListRes>> {
const { roomId } = data; const { roomId } = data;
const messages = State.fakeMsg.filter(msg => msg.roomId === roomId); const messages = await prisma.message.findMany({
where: { roomId },
orderBy: { createdAt: 'asc' }
});
const messageList: Ty.Message[] =
await Promise.all(messages.map(toFrontMsg))
.then(msgs => msgs.filter((m): m is Ty.Message => m !== null));
return { return {
code: 0, code: 0,
message: '消息获取成功', message: '消息获取成功',
data: { data: {
messages messages: messageList
} }
}; };
} }
export async function UpdateMessageList(data: Ty.RoomMessageGetUpdateArgs): Promise<Ty.BackendResponse<Ty.RoomMessageGetUpdateRes>> { export async function UpdateMessageList(data: Ty.RoomMessageGetUpdateArgs): Promise<Ty.BackendResponse<Ty.RoomMessageGetUpdateRes>> {
const { roomId, sinceMessageId } = data; const { roomId, sinceMessageId } = data;
const messages = State.fakeMsg.filter(msg => msg.roomId === roomId && msg.messageId > sinceMessageId); const messages = await prisma.message.findMany({
where: {
roomId,
id: { gt: sinceMessageId }
},
orderBy: { createdAt: 'asc' }
});
const messageList: Ty.Message[] =
await Promise.all(messages.map(toFrontMsg))
.then(msgs => msgs.filter((m): m is Ty.Message => m !== null));
return { return {
code: 0, code: 0,
message: '消息更新成功', message: '消息更新成功',
data: { data: {
messages messages: messageList
} }
}; };
} }
//后续需要补上房间建立者和删除者不同的无权限错误
export async function DeleteRoom(data: Ty.RoomDeleteArgs): Promise<Ty.BackendResponse<null>> { export async function DeleteRoom(data: Ty.RoomDeleteArgs, operatorToken: String ): Promise<Ty.BackendResponse<null>> {
const { user, roomId } = data; const { user, roomId } = data;
State.fakeRooms = State.fakeRooms.filter(room => room.roomId !== roomId);
State.fakeMsg = State.fakeMsg.filter(msg => msg.roomId !== roomId); const room = await prisma.room.findUnique({
where: { id: roomId },
select: { creator: { select: { name: true, userToken: true } } }
});
if (!room || room.creator.name !== user || room.creator.userToken !== operatorToken) {
return {
code: Auth.notAuthorizedToDeleteRoomErrorCode,
message: '无权限',
data: null
};
}
await prisma.room.delete({
where: { id: roomId }
});
return { return {
code: 0, code: 0,
message: '房间删除成功', message: '房间删除成功',
...@@ -78,18 +185,235 @@ export async function DeleteRoom(data: Ty.RoomDeleteArgs): Promise<Ty.BackendRes ...@@ -78,18 +185,235 @@ export async function DeleteRoom(data: Ty.RoomDeleteArgs): Promise<Ty.BackendRes
export async function AddMessage(data: Ty.MessageAddArgs): Promise<Ty.BackendResponse<null>> { export async function AddMessage(data: Ty.MessageAddArgs): Promise<Ty.BackendResponse<null>> {
const { roomId, sender, content } = data; const { roomId, sender, content } = data;
const newMessage: Ty.Message = {
messageId: State.maxMessageId + 1, console.log(`Adding message to room ${roomId} from user ${sender}: ${content}`);
roomId,
sender, if (!await UserExists(sender)) {
content, return {
time: Date.now() code: 1,
}; message: '用户不存在',
State.fakeMsg = [...State.fakeMsg, newMessage]; data: null
State.maxMessageId++; };
}
await prisma.message.create({
data: {
roomId,
senderName: sender,
content
}
});
return { return {
code: 0, code: 0,
message: '消息发送成功', message: '消息发送成功',
data: null data: null
}; };
}
export async function StartAuthSession() : Promise<Ty.BackendResponse<Auth.Session>> {
const sessionId = getRandomToken();
redis.set(`Session:${sessionId}`, "{}");
redis.expire(`Session:${sessionId}`, 60 * 5); // 5分钟内登录/注册有效
return {
code: 0,
message: '获取成功',
data: {
sessionId,
}
};
}
export async function Login(args: Auth.AuthArgs) : Promise<Ty.BackendResponse<Auth.LoginResult | null>> {
const { sessionId, username, password, userAgent, userIP } = args;
const sessionStr = await redis.get(`Session:${sessionId}`);
if(!sessionStr)
{
return {
code: 1,
message: '会话过期,请刷新页面后重试',
data: null
};
}
const user = await prisma.user.findUnique({
where: { name: username },
select: { password: true, salt: true, userToken: true }
});
if(!user || user.password !== createHash('sha256').update(password + user.salt).digest('hex'))
{
return {
code: 3,
message: '用户名或密码错误',
data: null
};
}
const authToken = getRandomToken();
await prisma.authToken.create({
data: {
token: authToken,
userName: username,
expiresAt: new Date(Date.now() + 60 * 60 * 1000 * 24 * 7), // 7 days
ua: userAgent,
ip: userIP
}
});
await redis.del(`Session:${sessionId}`);
return {
code: 0,
message: '登录成功',
data: {
user: username,
cookie: {
userToken: user.userToken,
authToken
}
}
};
}
export async function AutoLogin(args: Auth.AutoLoginArgs) : Promise<Ty.BackendResponse<Auth.LoginResult | null>> {
const { cookie } = args;
const { authToken } = cookie;
const user = await prisma.authToken.findUnique({
where: { token: authToken },
select: { user: true, expiresAt: true }
});
if (!user) {
return {
code: 101,
message: '无效的用户信息',
data: null
};
}
return {
code: 0,
message: '自动登录成功',
data: {
user: user.user.name,
cookie: {
userToken: cookie.userToken,
authToken: cookie.authToken
}
}
};
}
export async function Register(args: Auth.AuthArgs) : Promise<Ty.BackendResponse<Auth.RegisterResult | null>> {
const { sessionId, username, password } = args;
const sessionStr = await redis.get(`Session:${sessionId}`);
if(!sessionStr)
{
return {
code: 1,
message: '会话过期,请刷新页面后重试',
data: null
};
}
const user = await prisma.user.findUnique({
where: { name: username },
select: { name: true }
});
if(user)
{
return {
code: 3,
message: '用户名已存在',
data: null
};
}
const salt = getRandomStr();
const hashedPassword = createHash('sha256').update(password + salt).digest('hex');
await prisma.user.create({
data: {
name: username,
password: hashedPassword,
salt,
userToken: getRandomToken()
}
});
await redis.del(`Session:${sessionId}`);
return {
code: 0,
message: '注册成功',
data: {
user: username,
}
};
}
export async function Logout(args: Auth.LoginCookieData) : Promise<Ty.BackendResponse<null>> {
const { authToken } = args;
await prisma.authToken.delete({
where: { token: authToken }
});
return {
code: 0,
message: '登出成功',
data: null
};
}
export async function VerifyCookie(cookie : RequestCookies) : Promise<Ty.BackendResponse<null> | Auth.LoginCookieData> {
const result = Auth.cookieSchema.safeParse({
userToken: cookie.get('userToken')?.value || null,
authToken: cookie.get('authToken')?.value || null
});
if(!result.success || !result.data.authToken || !result.data.userToken) {
return {
code: 1,
message: '无效的Cookie',
data: null
};
}
const user = await prisma.authToken.findUnique({
where: { token: result.data.authToken },
select: { user: true, expiresAt: true }
});
if (!user || user.user.userToken !== result.data.userToken) {
return {
code: Auth.invalidUserErrorCode,
message: '无效的用户信息',
data: null
};
}
if (user.expiresAt < new Date()) {
await prisma.authToken.delete({
where: { token: result.data.authToken }
});
return {
code: Auth.reloginErrorCode,
message: '登录过期,请重新登录。',
data: null
};
}
const cookieData: Auth.LoginCookieData = {
userToken: result.data.userToken,
authToken: result.data.authToken
};
return cookieData;
} }
\ No newline at end of file
...@@ -14,7 +14,11 @@ interface RoomDeleteArgs { ...@@ -14,7 +14,11 @@ interface RoomDeleteArgs {
*/ */
export async function POST(req: NextRequest): Promise<NextResponse<Ty.BackendResponse<null>>> { export async function POST(req: NextRequest): Promise<NextResponse<Ty.BackendResponse<null>>> {
const cookieData = await Db.VerifyCookie(req.cookies);
if('code' in cookieData) return NextResponse.json(cookieData);
const { user, roomId } = await req.json() as Ty.RoomDeleteArgs; const { user, roomId } = await req.json() as Ty.RoomDeleteArgs;
const response = await Db.DeleteRoom({ user, roomId }); const response = await Db.DeleteRoom({ user, roomId }, cookieData.userToken);
return NextResponse.json(response); return NextResponse.json(response);
} }
\ No newline at end of file
...@@ -11,8 +11,10 @@ interface RoomListRes { ...@@ -11,8 +11,10 @@ interface RoomListRes {
rooms: RoomPreviewInfo[]; rooms: RoomPreviewInfo[];
} }
*/ */
export async function GET(req: NextRequest) : export async function GET(req: NextRequest) : Promise<NextResponse<Ty.BackendResponse<Ty.RoomListRes | null>>> {
Promise<NextResponse<Ty.BackendResponse<Ty.RoomListRes>>> { const cookieData = await Db.VerifyCookie(req.cookies);
if('code' in cookieData) return NextResponse.json(cookieData);
const response = await Db.GetRoomList(); const response = await Db.GetRoomList();
return NextResponse.json(response); return NextResponse.json(response);
} }
\ No newline at end of file
...@@ -16,7 +16,11 @@ interface RoomMessageGetUpdateRes { ...@@ -16,7 +16,11 @@ interface RoomMessageGetUpdateRes {
} }
*/ */
export async function GET(req: NextRequest): Promise<NextResponse<Ty.BackendResponse<Ty.RoomMessageGetUpdateRes>>> { export async function GET(req: NextRequest): Promise<NextResponse<Ty.BackendResponse<Ty.RoomMessageGetUpdateRes | null>>> {
const cookieData = await Db.VerifyCookie(req.cookies);
if('code' in cookieData) return NextResponse.json(cookieData);
const Params = req.nextUrl.searchParams; const Params = req.nextUrl.searchParams;
const result = await Db.UpdateMessageList({ const result = await Db.UpdateMessageList({
roomId: Number(Params.get('roomId')), roomId: Number(Params.get('roomId')),
......
...@@ -14,7 +14,10 @@ interface RoomMessageListRes { ...@@ -14,7 +14,10 @@ interface RoomMessageListRes {
messages: Message[]; messages: Message[];
} }
*/ */
export async function GET(req: NextRequest): Promise<NextResponse<Ty.BackendResponse<Ty.RoomMessageListRes>>> { export async function GET(req: NextRequest): Promise<NextResponse<Ty.BackendResponse<Ty.RoomMessageListRes | null>>> {
const cookieData = await Db.VerifyCookie(req.cookies);
if('code' in cookieData) return NextResponse.json(cookieData);
const Params = req.nextUrl.searchParams; const Params = req.nextUrl.searchParams;
const response = await Db.GetMessageList({ roomId: Number(Params.get('roomId')) }); const response = await Db.GetMessageList({ roomId: Number(Params.get('roomId')) });
return NextResponse.json(response); return NextResponse.json(response);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment