diff --git a/.env.example b/.env.example index c571d09..d13ac74 100644 --- a/.env.example +++ b/.env.example @@ -5,3 +5,4 @@ GITHUB_CLIENT_ID= GITHUB_CLIENT_SECRET= NEXTAUTH_URL= +DATABASE_URL= \ No newline at end of file diff --git a/.gitignore b/.gitignore index af52675..2c62c23 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,5 @@ next-env.d.ts build.sh -test.ts \ No newline at end of file +test.ts +/generated/prisma diff --git a/package.json b/package.json index bb85593..63fff30 100644 --- a/package.json +++ b/package.json @@ -10,13 +10,13 @@ "lint": "eslint" }, "dependencies": { + "@prisma/client": "^6.19.0", "bcryptjs": "^3.0.3", "edge-tts-universal": "^1.3.2", "lucide-react": "^0.553.0", "next": "15.5.3", "next-auth": "^4.24.13", - "next-intl": "^4.5.1", - "pg": "^8.16.3", + "next-intl": "^4.5.2", "react": "19.1.0", "react-dom": "19.1.0", "unstorage": "^1.17.2", @@ -27,11 +27,11 @@ "@tailwindcss/postcss": "^4.1.17", "@types/bcryptjs": "^2.4.6", "@types/node": "^20.19.25", - "@types/pg": "^8.15.6", - "@types/react": "^19.2.3", + "@types/react": "^19.2.4", "@types/react-dom": "^19.2.3", "eslint": "^9.39.1", "eslint-config-next": "15.5.3", + "prisma": "^6.19.0", "tailwindcss": "^4.1.17", "typescript": "^5.9.3" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1ffa9c5..20e3a7f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,12 +8,15 @@ importers: .: dependencies: + '@prisma/client': + specifier: ^6.19.0 + version: 6.19.0(prisma@6.19.0(typescript@5.9.3))(typescript@5.9.3) bcryptjs: specifier: ^3.0.3 version: 3.0.3 edge-tts-universal: specifier: ^1.3.2 - version: 1.3.2(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0)) + version: 1.3.2(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0)) lucide-react: specifier: ^0.553.0 version: 0.553.0(react@19.1.0) @@ -24,11 +27,8 @@ importers: specifier: ^4.24.13 version: 4.24.13(next@15.5.3(@babel/core@7.28.5)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) next-intl: - specifier: ^4.5.1 - version: 4.5.1(next@15.5.3(@babel/core@7.28.5)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(typescript@5.9.3) - pg: - specifier: ^8.16.3 - version: 8.16.3 + specifier: ^4.5.2 + version: 4.5.2(next@15.5.3(@babel/core@7.28.5)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(typescript@5.9.3) react: specifier: 19.1.0 version: 19.1.0 @@ -54,21 +54,21 @@ importers: '@types/node': specifier: ^20.19.25 version: 20.19.25 - '@types/pg': - specifier: ^8.15.6 - version: 8.15.6 '@types/react': - specifier: ^19.2.3 - version: 19.2.3 + specifier: ^19.2.4 + version: 19.2.4 '@types/react-dom': specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.3) + version: 19.2.3(@types/react@19.2.4) eslint: specifier: ^9.39.1 version: 9.39.1(jiti@2.6.1) eslint-config-next: specifier: 15.5.3 version: 15.5.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + prisma: + specifier: ^6.19.0 + version: 6.19.0(typescript@5.9.3) tailwindcss: specifier: ^4.1.17 version: 4.1.17 @@ -1072,6 +1072,36 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@prisma/client@6.19.0': + resolution: {integrity: sha512-QXFT+N/bva/QI2qoXmjBzL7D6aliPffIwP+81AdTGq0FXDoLxLkWivGMawG8iM5B9BKfxLIXxfWWAF6wbuJU6g==} + engines: {node: '>=18.18'} + peerDependencies: + prisma: '*' + typescript: '>=5.1.0' + peerDependenciesMeta: + prisma: + optional: true + typescript: + optional: true + + '@prisma/config@6.19.0': + resolution: {integrity: sha512-zwCayme+NzI/WfrvFEtkFhhOaZb/hI+X8TTjzjJ252VbPxAl2hWHK5NMczmnG9sXck2lsXrxIZuK524E25UNmg==} + + '@prisma/debug@6.19.0': + resolution: {integrity: sha512-8hAdGG7JmxrzFcTzXZajlQCidX0XNkMJkpqtfbLV54wC6LSSX6Vni25W/G+nAANwLnZ2TmwkfIuWetA7jJxJFA==} + + '@prisma/engines-version@6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773': + resolution: {integrity: sha512-gV7uOBQfAFlWDvPJdQxMT1aSRur3a0EkU/6cfbAC5isV67tKDWUrPauyaHNpB+wN1ebM4A9jn/f4gH+3iHSYSQ==} + + '@prisma/engines@6.19.0': + resolution: {integrity: sha512-pMRJ+1S6NVdXoB8QJAPIGpKZevFjxhKt0paCkRDTZiczKb7F4yTgRP8M4JdVkpQwmaD4EoJf6qA+p61godDokw==} + + '@prisma/fetch-engine@6.19.0': + resolution: {integrity: sha512-OOx2Lda0DGrZ1rodADT06ZGqHzr7HY7LNMaFE2Vp8dp146uJld58sRuasdX0OiwpHgl8SqDTUKHNUyzEq7pDdQ==} + + '@prisma/get-platform@6.19.0': + resolution: {integrity: sha512-ym85WDO2yDhC3fIXHWYpG3kVMBA49cL1XD2GCsCF8xbwoy2OkDQY44gEbAt2X46IQ4Apq9H6g0Ex1iFfPqEkHA==} + '@react-native/assets-registry@0.82.1': resolution: {integrity: sha512-B1SRwpntaAcckiatxbjzylvNK562Ayza05gdJCjDQHTiDafa1OABmyB5LHt7qWDOpNkaluD+w11vHF7pBmTpzQ==} engines: {node: '>= 20.19.4'} @@ -1173,6 +1203,9 @@ packages: '@sinonjs/fake-timers@10.3.0': resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + '@swc/core-darwin-arm64@1.15.1': resolution: {integrity: sha512-vEPrVxegWIjKEz+1VCVuKRY89jhokhSmQ/YXBWLnmLj9cI08G61RTZJvdsIcjYUjjTu7NgZlYVK+b2y0fbh11g==} engines: {node: '>=10'} @@ -1381,16 +1414,13 @@ packages: '@types/node@20.19.25': resolution: {integrity: sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==} - '@types/pg@8.15.6': - resolution: {integrity: sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ==} - '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: '@types/react': ^19.2.0 - '@types/react@19.2.3': - resolution: {integrity: sha512-k5dJVszUiNr1DSe8Cs+knKR6IrqhqdhpUwzqhkS8ecQTSf3THNtbfIp/umqHMpX2bv+9dkx3fwDv/86LcSfvSg==} + '@types/react@19.2.4': + resolution: {integrity: sha512-tBFxBp9Nfyy5rsmefN+WXc1JeW/j2BpBHFdLZbEVfs9wn3E3NRFxwV0pJg8M1qQAexFpvz73hJXFofV0ZAu92A==} '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -1814,8 +1844,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.8.26: - resolution: {integrity: sha512-73lC1ugzwoaWCLJ1LvOgrR5xsMLTqSKIEoMHVtL9E/HNk0PXtTM76ZIm84856/SF7Nv8mPZxKoBsgpm0tR1u1Q==} + baseline-browser-mapping@2.8.27: + resolution: {integrity: sha512-2CXFpkjVnY2FT+B6GrSYxzYf65BJWEqz5tIRHCvNsZZ2F3CmsCB37h8SpYgKG7y9C4YAeTipIPWG7EmFmhAeXA==} hasBin: true bcryptjs@3.0.3: @@ -1869,6 +1899,14 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.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: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -1927,6 +1965,9 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + cli-cursor@2.1.0: resolution: {integrity: sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==} engines: {node: '>=4'} @@ -1992,10 +2033,17 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + confbox@0.2.2: + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + connect@3.7.0: resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} engines: {node: '>= 0.10.0'} + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -2076,6 +2124,10 @@ packages: deep-is@0.1.4: 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'} + deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -2129,6 +2181,10 @@ packages: resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} engines: {node: '>=12'} + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -2143,6 +2199,9 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + effect@3.18.4: + resolution: {integrity: sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==} + electron-to-chromium@1.5.250: resolution: {integrity: sha512-/5UMj9IiGDMOFBnN4i7/Ry5onJrAGSbOGo3s9FEKmwobGq6xw832ccET0CE3CkkMBZ8GJSlUIesZofpyurqDXw==} @@ -2152,6 +2211,10 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + empathic@2.0.0: + resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} + engines: {node: '>=14'} + encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} @@ -2430,6 +2493,13 @@ packages: exponential-backoff@3.1.3: resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + + fast-check@3.23.2: + resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} + engines: {node: '>=8.0.0'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -2586,6 +2656,10 @@ packages: resolution: {integrity: sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==} engines: {node: '>=6'} + giget@2.0.0: + resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} + hasBin: true + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -2930,8 +3004,8 @@ packages: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true jsc-safe-url@0.2.4: @@ -3350,8 +3424,8 @@ packages: nodemailer: optional: true - next-intl@4.5.1: - resolution: {integrity: sha512-irtCL71cYJrnleHFpELhlYqb7LIqNiXBssijNVjxUU7hShUFuLYDvYFMbQA0Ocy1WTwSasgmysUHo/bWuKXpRA==} + next-intl@4.5.2: + resolution: {integrity: sha512-njv6ZPzBmnn33fjQDcMCqYhb4zw9HANruDYB8zNLHTG+bhBfLIjvzdL/XbUBlg8ByK0QI/Qqmpmet0b1eSTL8A==} peerDependencies: next: ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0 @@ -3417,6 +3491,11 @@ packages: nullthrows@1.1.1: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} + nypm@0.6.2: + resolution: {integrity: sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==} + engines: {node: ^14.16.0 || >=16.10.0} + hasBin: true + oauth@0.9.15: resolution: {integrity: sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==} @@ -3467,6 +3546,9 @@ packages: ofetch@1.5.1: resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + oidc-token-hash@5.2.0: resolution: {integrity: sha512-6gj2m8cJZ+iSW8bm0FXdGF0YhIQbKrfP4yWTNzxc31U6MOjfEmB1rHvlYvxI1B7t7BCi1F2vYTT6YhtQRG4hxw==} engines: {node: ^10.13.0 || >=12.0.0} @@ -3567,39 +3649,11 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - pg-cloudflare@1.2.7: - resolution: {integrity: sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - pg-connection-string@2.9.1: - resolution: {integrity: sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==} - - pg-int8@1.0.1: - resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} - engines: {node: '>=4.0.0'} - - pg-pool@3.10.1: - resolution: {integrity: sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==} - peerDependencies: - pg: '>=8.0' - - pg-protocol@1.10.3: - resolution: {integrity: sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==} - - pg-types@2.2.0: - resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} - engines: {node: '>=4'} - - pg@8.16.3: - resolution: {integrity: sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==} - engines: {node: '>= 16.0.0'} - peerDependencies: - pg-native: '>=3.0.1' - peerDependenciesMeta: - pg-native: - optional: true - - pgpass@1.0.5: - resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -3620,6 +3674,9 @@ packages: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} + pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + plist@3.1.0: resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} engines: {node: '>=10.4.0'} @@ -3644,22 +3701,6 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} - postgres-array@2.0.0: - resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} - engines: {node: '>=4'} - - postgres-bytea@1.0.0: - resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} - engines: {node: '>=0.10.0'} - - postgres-date@1.0.7: - resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} - engines: {node: '>=0.10.0'} - - postgres-interval@1.2.0: - resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} - engines: {node: '>=0.10.0'} - preact-render-to-string@5.2.6: resolution: {integrity: sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==} peerDependencies: @@ -3683,6 +3724,16 @@ packages: pretty-format@3.8.0: resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==} + prisma@6.19.0: + resolution: {integrity: sha512-F3eX7K+tWpkbhl3l4+VkFtrwJlLXbAM+f9jolgoUZbFcm1DgHZ4cq9AgVEgUym2au5Ad/TDLN8lg83D+M10ycw==} + engines: {node: '>=18.18'} + hasBin: true + peerDependencies: + typescript: '>=5.1.0' + peerDependenciesMeta: + typescript: + optional: true + proc-log@4.2.0: resolution: {integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -3708,6 +3759,9 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + pvtsutils@1.3.6: resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} @@ -3732,6 +3786,9 @@ packages: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} + rc9@2.1.2: + resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true @@ -3998,10 +4055,6 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} - sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} @@ -4172,6 +4225,10 @@ packages: throat@5.0.0: resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} @@ -4361,8 +4418,8 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - use-intl@4.5.1: - resolution: {integrity: sha512-a9wVAuIofJuoD3wQazNuCr2B04rStdgUzILHNXHuogyOx2h0RabnfrRfFlGJnmrZDwN6JtPqD2aHLh4Naa8M0Q==} + use-intl@4.5.2: + resolution: {integrity: sha512-f9erBQDCk7uuu4vqqrUNffnvRv0a00cnWNEm1EtLnTleoM/cdNnFmXu3hcBXpUVwBdCoX07WD90dLeg7lzfhlw==} peerDependencies: react: ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0 @@ -4519,10 +4576,6 @@ packages: resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} engines: {node: '>=8.0'} - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -5313,7 +5366,7 @@ snapshots: globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 - js-yaml: 4.1.0 + js-yaml: 4.1.1 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: @@ -5328,7 +5381,7 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 - '@expo/cli@54.0.16(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))': + '@expo/cli@54.0.16(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))': dependencies: '@0no-co/graphql.web': 1.2.0 '@expo/code-signing-certificates': 0.0.5 @@ -5340,11 +5393,11 @@ snapshots: '@expo/json-file': 10.0.7 '@expo/mcp-tunnel': 0.1.0 '@expo/metro': 54.1.0 - '@expo/metro-config': 54.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0)) + '@expo/metro-config': 54.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0)) '@expo/osascript': 2.3.7 '@expo/package-manager': 1.9.8 '@expo/plist': 0.4.7 - '@expo/prebuild-config': 54.0.6(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0)) + '@expo/prebuild-config': 54.0.6(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0)) '@expo/schema-utils': 0.1.7 '@expo/spawn-async': 1.7.2 '@expo/ws-tunnel': 1.0.6 @@ -5363,7 +5416,7 @@ snapshots: connect: 3.7.0 debug: 4.4.3 env-editor: 0.4.2 - expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) + expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) expo-server: 1.0.4 freeport-async: 2.0.0 getenv: 2.0.0 @@ -5396,7 +5449,7 @@ snapshots: wrap-ansi: 7.0.0 ws: 8.18.3 optionalDependencies: - react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0) + react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0) transitivePeerDependencies: - '@modelcontextprotocol/sdk' - bufferutil @@ -5462,12 +5515,12 @@ snapshots: - supports-color optional: true - '@expo/devtools@0.1.7(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0)': + '@expo/devtools@0.1.7(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0)': dependencies: chalk: 4.1.2 optionalDependencies: react: 19.1.0 - react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0) + react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0) optional: true '@expo/env@2.0.7': @@ -5528,7 +5581,7 @@ snapshots: - utf-8-validate optional: true - '@expo/metro-config@54.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))': + '@expo/metro-config@54.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))': dependencies: '@babel/code-frame': 7.27.1 '@babel/core': 7.28.5 @@ -5552,7 +5605,7 @@ snapshots: postcss: 8.4.49 resolve-from: 5.0.0 optionalDependencies: - expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) + expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) transitivePeerDependencies: - bufferutil - supports-color @@ -5602,7 +5655,7 @@ snapshots: xmlbuilder: 15.1.1 optional: true - '@expo/prebuild-config@54.0.6(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))': + '@expo/prebuild-config@54.0.6(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))': dependencies: '@expo/config': 12.0.10 '@expo/config-plugins': 54.0.2 @@ -5611,7 +5664,7 @@ snapshots: '@expo/json-file': 10.0.7 '@react-native/normalize-colors': 0.81.5 debug: 4.4.3 - expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) + expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) resolve-from: 5.0.0 semver: 7.7.3 xml2js: 0.6.0 @@ -5633,11 +5686,11 @@ snapshots: '@expo/sudo-prompt@9.3.2': optional: true - '@expo/vector-icons@15.0.3(expo-font@14.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0)': + '@expo/vector-icons@15.0.3(expo-font@14.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0)': dependencies: - expo-font: 14.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) + expo-font: 14.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) react: 19.1.0 - react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0) + react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0) optional: true '@expo/ws-tunnel@1.0.6': @@ -5648,7 +5701,7 @@ snapshots: '@babel/code-frame': 7.10.4 chalk: 4.1.2 find-up: 5.0.0 - js-yaml: 4.1.0 + js-yaml: 4.1.1 optional: true '@formatjs/ecma402-abstract@2.3.6': @@ -5977,6 +6030,41 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@prisma/client@6.19.0(prisma@6.19.0(typescript@5.9.3))(typescript@5.9.3)': + optionalDependencies: + prisma: 6.19.0(typescript@5.9.3) + typescript: 5.9.3 + + '@prisma/config@6.19.0': + dependencies: + c12: 3.1.0 + deepmerge-ts: 7.1.5 + effect: 3.18.4 + empathic: 2.0.0 + transitivePeerDependencies: + - magicast + + '@prisma/debug@6.19.0': {} + + '@prisma/engines-version@6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773': {} + + '@prisma/engines@6.19.0': + dependencies: + '@prisma/debug': 6.19.0 + '@prisma/engines-version': 6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773 + '@prisma/fetch-engine': 6.19.0 + '@prisma/get-platform': 6.19.0 + + '@prisma/fetch-engine@6.19.0': + dependencies: + '@prisma/debug': 6.19.0 + '@prisma/engines-version': 6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773 + '@prisma/get-platform': 6.19.0 + + '@prisma/get-platform@6.19.0': + dependencies: + '@prisma/debug': 6.19.0 + '@react-native/assets-registry@0.82.1': optional: true @@ -6140,14 +6228,14 @@ snapshots: '@react-native/normalize-colors@0.82.1': optional: true - '@react-native/virtualized-lists@0.82.1(@types/react@19.2.3)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0)': + '@react-native/virtualized-lists@0.82.1(@types/react@19.2.4)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 19.1.0 - react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0) + react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0) optionalDependencies: - '@types/react': 19.2.3 + '@types/react': 19.2.4 optional: true '@rtsao/scc@1.1.0': {} @@ -6169,6 +6257,8 @@ snapshots: '@sinonjs/commons': 3.0.1 optional: true + '@standard-schema/spec@1.0.0': {} + '@swc/core-darwin-arm64@1.15.1': optional: true @@ -6354,17 +6444,11 @@ snapshots: dependencies: undici-types: 6.21.0 - '@types/pg@8.15.6': + '@types/react-dom@19.2.3(@types/react@19.2.4)': dependencies: - '@types/node': 20.19.25 - pg-protocol: 1.10.3 - pg-types: 2.2.0 + '@types/react': 19.2.4 - '@types/react-dom@19.2.3(@types/react@19.2.3)': - dependencies: - '@types/react': 19.2.3 - - '@types/react@19.2.3': + '@types/react@19.2.4': dependencies: csstype: 3.1.3 @@ -6859,7 +6943,7 @@ snapshots: '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.5) optional: true - babel-preset-expo@54.0.7(@babel/core@7.28.5)(@babel/runtime@7.28.4)(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-refresh@0.14.2): + babel-preset-expo@54.0.7(@babel/core@7.28.5)(@babel/runtime@7.28.4)(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-refresh@0.14.2): dependencies: '@babel/helper-module-imports': 7.27.1 '@babel/plugin-proposal-decorators': 7.28.0(@babel/core@7.28.5) @@ -6886,7 +6970,7 @@ snapshots: resolve-from: 5.0.0 optionalDependencies: '@babel/runtime': 7.28.4 - expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) + expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) transitivePeerDependencies: - '@babel/core' - supports-color @@ -6906,7 +6990,7 @@ snapshots: base64-js@1.5.1: optional: true - baseline-browser-mapping@2.8.26: + baseline-browser-mapping@2.8.27: optional: true bcryptjs@3.0.3: {} @@ -6949,7 +7033,7 @@ snapshots: browserslist@4.28.0: dependencies: - baseline-browser-mapping: 2.8.26 + baseline-browser-mapping: 2.8.27 caniuse-lite: 1.0.30001754 electron-to-chromium: 1.5.250 node-releases: 2.0.27 @@ -6973,6 +7057,21 @@ snapshots: bytes@3.1.2: optional: true + c12@3.1.0: + dependencies: + chokidar: 4.0.3 + confbox: 0.2.2 + defu: 6.1.4 + dotenv: 16.6.1 + exsolve: 1.0.8 + giget: 2.0.0 + jiti: 2.6.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: dependencies: es-errors: 1.3.0 @@ -7047,6 +7146,10 @@ snapshots: ci-info@3.9.0: optional: true + citty@0.1.6: + dependencies: + consola: 3.4.2 + cli-cursor@2.1.0: dependencies: restore-cursor: 2.0.0 @@ -7120,6 +7223,8 @@ snapshots: concat-map@0.0.1: {} + confbox@0.2.2: {} + connect@3.7.0: dependencies: debug: 2.6.9 @@ -7130,6 +7235,8 @@ snapshots: - supports-color optional: true + consola@3.4.2: {} + convert-source-map@2.0.0: optional: true @@ -7203,6 +7310,8 @@ snapshots: deep-is@0.1.4: {} + deepmerge-ts@7.1.5: {} + deepmerge@4.3.1: optional: true @@ -7252,6 +7361,8 @@ snapshots: dotenv@16.4.7: optional: true + dotenv@16.6.1: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -7261,12 +7372,12 @@ snapshots: eastasianwidth@0.2.0: optional: true - edge-tts-universal@1.3.2(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0)): + edge-tts-universal@1.3.2(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0)): dependencies: axios: 1.13.2 cross-fetch: 4.1.0 https-proxy-agent: 7.0.6 - isomorphic-webcrypto: 2.3.8(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0)) + isomorphic-webcrypto: 2.3.8(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0)) isomorphic-ws: 5.0.0(ws@8.18.3) uuid: 11.1.0 ws: 8.18.3 @@ -7283,6 +7394,11 @@ snapshots: ee-first@1.1.1: optional: true + effect@3.18.4: + dependencies: + '@standard-schema/spec': 1.0.0 + fast-check: 3.23.2 + electron-to-chromium@1.5.250: optional: true @@ -7291,6 +7407,8 @@ snapshots: emoji-regex@9.2.2: {} + empathic@2.0.0: {} + encodeurl@1.0.2: optional: true @@ -7633,44 +7751,44 @@ snapshots: exec-async@2.2.0: optional: true - expo-asset@12.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0): + expo-asset@12.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0): dependencies: '@expo/image-utils': 0.8.7 - expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) - expo-constants: 18.0.10(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0)) + expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) + expo-constants: 18.0.10(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0)) react: 19.1.0 - react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0) + react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0) transitivePeerDependencies: - supports-color optional: true - expo-constants@18.0.10(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0)): + expo-constants@18.0.10(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0)): dependencies: '@expo/config': 12.0.10 '@expo/env': 2.0.7 - expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) - react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0) + expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) + react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0) transitivePeerDependencies: - supports-color optional: true - expo-file-system@19.0.17(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0)): + expo-file-system@19.0.17(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0)): dependencies: - expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) - react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0) + expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) + react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0) optional: true - expo-font@14.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0): + expo-font@14.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0): dependencies: - expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) + expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) fontfaceobserver: 2.3.0 react: 19.1.0 - react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0) + react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0) optional: true - expo-keep-awake@15.0.7(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react@19.1.0): + expo-keep-awake@15.0.7(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react@19.1.0): dependencies: - expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) + expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) react: 19.1.0 optional: true @@ -7692,45 +7810,45 @@ snapshots: resolve-from: 5.0.0 optional: true - expo-modules-core@3.0.25(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0): + expo-modules-core@3.0.25(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0): dependencies: invariant: 2.2.4 react: 19.1.0 - react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0) + react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0) optional: true - expo-random@14.0.1(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0)): + expo-random@14.0.1(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0)): dependencies: base64-js: 1.5.1 - expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) + expo: 54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) optional: true expo-server@1.0.4: optional: true - expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0): + expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0): dependencies: '@babel/runtime': 7.28.4 - '@expo/cli': 54.0.16(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0)) + '@expo/cli': 54.0.16(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0)) '@expo/config': 12.0.10 '@expo/config-plugins': 54.0.2 - '@expo/devtools': 0.1.7(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) + '@expo/devtools': 0.1.7(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) '@expo/fingerprint': 0.15.3 '@expo/metro': 54.1.0 - '@expo/metro-config': 54.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0)) - '@expo/vector-icons': 15.0.3(expo-font@14.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) + '@expo/metro-config': 54.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0)) + '@expo/vector-icons': 15.0.3(expo-font@14.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) '@ungap/structured-clone': 1.3.0 - babel-preset-expo: 54.0.7(@babel/core@7.28.5)(@babel/runtime@7.28.4)(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-refresh@0.14.2) - expo-asset: 12.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) - expo-constants: 18.0.10(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0)) - expo-file-system: 19.0.17(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0)) - expo-font: 14.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) - expo-keep-awake: 15.0.7(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react@19.1.0) + babel-preset-expo: 54.0.7(@babel/core@7.28.5)(@babel/runtime@7.28.4)(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-refresh@0.14.2) + expo-asset: 12.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) + expo-constants: 18.0.10(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0)) + expo-file-system: 19.0.17(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0)) + expo-font: 14.0.9(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) + expo-keep-awake: 15.0.7(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react@19.1.0) expo-modules-autolinking: 3.0.21 - expo-modules-core: 3.0.25(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) + expo-modules-core: 3.0.25(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) pretty-format: 29.7.0 react: 19.1.0 - react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0) + react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0) react-refresh: 0.14.2 whatwg-url-without-unicode: 8.0.0-3 transitivePeerDependencies: @@ -7746,6 +7864,12 @@ snapshots: exponential-backoff@3.1.3: optional: true + exsolve@1.0.8: {} + + fast-check@3.23.2: + dependencies: + pure-rand: 6.1.0 + fast-deep-equal@3.1.3: {} fast-glob@3.3.1: @@ -7924,6 +8048,15 @@ snapshots: getenv@2.0.0: optional: true + 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.2 + pathe: 2.0.3 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -8225,7 +8358,7 @@ snapshots: isexe@2.0.0: {} - isomorphic-webcrypto@2.3.8(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0)): + isomorphic-webcrypto@2.3.8(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0))(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0)): dependencies: '@peculiar/webcrypto': 1.5.0 asmcrypto.js: 0.22.0 @@ -8237,8 +8370,8 @@ snapshots: optionalDependencies: '@unimodules/core': 7.1.2 '@unimodules/react-native-adapter': 6.3.9 - expo-random: 14.0.1(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0)) - react-native-securerandom: 0.1.1(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0)) + expo-random: 14.0.1(expo@54.0.23(@babel/core@7.28.5)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0)) + react-native-securerandom: 0.1.1(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0)) transitivePeerDependencies: - expo - react-native @@ -8373,7 +8506,7 @@ snapshots: esprima: 4.0.1 optional: true - js-yaml@4.1.0: + js-yaml@4.1.1: dependencies: argparse: 2.0.1 @@ -9022,14 +9155,14 @@ snapshots: react-dom: 19.1.0(react@19.1.0) uuid: 8.3.2 - next-intl@4.5.1(next@15.5.3(@babel/core@7.28.5)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(typescript@5.9.3): + next-intl@4.5.2(next@15.5.3(@babel/core@7.28.5)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(typescript@5.9.3): dependencies: '@formatjs/intl-localematcher': 0.5.10 '@swc/core': 1.15.1 negotiator: 1.0.0 next: 15.5.3(@babel/core@7.28.5)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: 19.1.0 - use-intl: 4.5.1(react@19.1.0) + use-intl: 4.5.2(react@19.1.0) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -9089,6 +9222,14 @@ snapshots: nullthrows@1.1.1: optional: true + nypm@0.6.2: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + pathe: 2.0.3 + pkg-types: 2.3.0 + tinyexec: 1.0.2 + oauth@0.9.15: {} ob1@0.83.2: @@ -9151,6 +9292,8 @@ snapshots: node-fetch-native: 1.6.7 ufo: 1.6.1 + ohash@2.0.11: {} + oidc-token-hash@5.2.0: {} on-finished@2.3.0: @@ -9272,40 +9415,9 @@ snapshots: minipass: 7.1.2 optional: true - pg-cloudflare@1.2.7: - optional: true + pathe@2.0.3: {} - pg-connection-string@2.9.1: {} - - pg-int8@1.0.1: {} - - pg-pool@3.10.1(pg@8.16.3): - dependencies: - pg: 8.16.3 - - pg-protocol@1.10.3: {} - - pg-types@2.2.0: - dependencies: - pg-int8: 1.0.1 - postgres-array: 2.0.0 - postgres-bytea: 1.0.0 - postgres-date: 1.0.7 - postgres-interval: 1.2.0 - - pg@8.16.3: - dependencies: - pg-connection-string: 2.9.1 - pg-pool: 3.10.1(pg@8.16.3) - pg-protocol: 1.10.3 - pg-types: 2.2.0 - pgpass: 1.0.5 - optionalDependencies: - pg-cloudflare: 1.2.7 - - pgpass@1.0.5: - dependencies: - split2: 4.2.0 + perfect-debounce@1.0.0: {} picocolors@1.1.1: {} @@ -9319,6 +9431,12 @@ snapshots: pirates@4.0.7: optional: true + pkg-types@2.3.0: + dependencies: + confbox: 0.2.2 + exsolve: 1.0.8 + pathe: 2.0.3 + plist@3.1.0: dependencies: '@xmldom/xmldom': 0.8.11 @@ -9350,16 +9468,6 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postgres-array@2.0.0: {} - - postgres-bytea@1.0.0: {} - - postgres-date@1.0.7: {} - - postgres-interval@1.2.0: - dependencies: - xtend: 4.0.2 - preact-render-to-string@5.2.6(preact@10.27.2): dependencies: preact: 10.27.2 @@ -9381,6 +9489,15 @@ snapshots: pretty-format@3.8.0: {} + prisma@6.19.0(typescript@5.9.3): + dependencies: + '@prisma/config': 6.19.0 + '@prisma/engines': 6.19.0 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - magicast + proc-log@4.2.0: optional: true @@ -9408,6 +9525,8 @@ snapshots: punycode@2.3.1: {} + pure-rand@6.1.0: {} + pvtsutils@1.3.6: dependencies: tslib: 2.8.1 @@ -9429,6 +9548,11 @@ snapshots: range-parser@1.2.1: optional: true + rc9@2.1.2: + dependencies: + defu: 6.1.4 + destr: 2.0.5 + rc@1.2.8: dependencies: deep-extend: 0.6.0 @@ -9456,13 +9580,13 @@ snapshots: react-is@18.3.1: optional: true - react-native-securerandom@0.1.1(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0)): + react-native-securerandom@0.1.1(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0)): dependencies: base64-js: 1.5.1 - react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0) + react-native: 0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0) optional: true - react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0): + react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0): dependencies: '@jest/create-cache-key-function': 29.7.0 '@react-native/assets-registry': 0.82.1 @@ -9471,7 +9595,7 @@ snapshots: '@react-native/gradle-plugin': 0.82.1 '@react-native/js-polyfills': 0.82.1 '@react-native/normalize-colors': 0.82.1 - '@react-native/virtualized-lists': 0.82.1(@types/react@19.2.3)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.3)(react@19.1.0))(react@19.1.0) + '@react-native/virtualized-lists': 0.82.1(@types/react@19.2.4)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@19.2.4)(react@19.1.0))(react@19.1.0) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -9501,7 +9625,7 @@ snapshots: ws: 6.2.3 yargs: 17.7.2 optionalDependencies: - '@types/react': 19.2.3 + '@types/react': 19.2.4 transitivePeerDependencies: - '@babel/core' - '@react-native-community/cli' @@ -9844,8 +9968,6 @@ snapshots: source-map@0.6.1: optional: true - split2@4.2.0: {} - sprintf-js@1.0.3: optional: true @@ -10059,6 +10181,8 @@ snapshots: throat@5.0.0: optional: true + tinyexec@1.0.2: {} + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) @@ -10228,7 +10352,7 @@ snapshots: dependencies: punycode: 2.3.1 - use-intl@4.5.1(react@19.1.0): + use-intl@4.5.2(react@19.1.0): dependencies: '@formatjs/fast-memoize': 2.2.7 '@schummar/icu-type-parser': 1.21.5 @@ -10397,8 +10521,6 @@ snapshots: xmlbuilder@15.1.1: optional: true - xtend@4.0.2: {} - y18n@5.0.8: optional: true diff --git a/prisma.config.ts b/prisma.config.ts new file mode 100644 index 0000000..6b6d3b6 --- /dev/null +++ b/prisma.config.ts @@ -0,0 +1,12 @@ +import { defineConfig, env } from "prisma/config"; + +export default defineConfig({ + schema: "prisma/schema.prisma", + migrations: { + path: "prisma/migrations", + }, + engine: "classic", + datasource: { + url: env("DATABASE_URL"), + }, +}); diff --git a/prisma/migrations/0_init/migration.sql b/prisma/migrations/0_init/migration.sql new file mode 100644 index 0000000..89f5366 --- /dev/null +++ b/prisma/migrations/0_init/migration.sql @@ -0,0 +1,28 @@ +-- CreateTable +CREATE TABLE "text_pair" ( + "id" SERIAL NOT NULL, + "locale1" VARCHAR(10) NOT NULL, + "locale2" VARCHAR(10) NOT NULL, + "text1" TEXT NOT NULL, + "text2" TEXT NOT NULL, + "folder_id" INTEGER NOT NULL, + "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "text_pairs_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "folder" ( + "id" SERIAL NOT NULL, + "name" TEXT NOT NULL, + "owner" TEXT NOT NULL, + "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "folders_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "text_pair" ADD CONSTRAINT "fk_text_pairs_folder" FOREIGN KEY ("folder_id") REFERENCES "folder"("id") ON DELETE CASCADE ON UPDATE CASCADE; + diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..e58db59 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,31 @@ +generator client { + provider = "prisma-client" + output = "../generated/prisma" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +/// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info. +model text_pair { + id Int @id(map: "text_pairs_pkey") @default(autoincrement()) + locale1 String @db.VarChar(10) + locale2 String @db.VarChar(10) + text1 String + text2 String + folder_id Int + created_at DateTime? @default(now()) @db.Timestamptz(6) + updated_at DateTime? @default(now()) @db.Timestamptz(6) + folders folder @relation(fields: [folder_id], references: [id], onDelete: Cascade, map: "fk_text_pairs_folder") +} + +model folder { + id Int @id(map: "folders_pkey") @default(autoincrement()) + name String + owner String + created_at DateTime? @default(now()) @db.Timestamptz(6) + updated_at DateTime? @default(now()) @db.Timestamptz(6) + text_pair text_pair[] +} diff --git a/src/app/alphabet/MemoryCard.tsx b/src/app/alphabet/MemoryCard.tsx index 990f15a..49dc9b2 100644 --- a/src/app/alphabet/MemoryCard.tsx +++ b/src/app/alphabet/MemoryCard.tsx @@ -1,7 +1,7 @@ import LightButton from "@/components/buttons/LightButton"; import IconClick from "@/components/IconClick"; import IMAGES from "@/config/images"; -import { Letter, SupportedAlphabets } from "@/interfaces"; +import { Letter, SupportedAlphabets } from "@/lib/interfaces"; import { Dispatch, KeyboardEvent, diff --git a/src/app/alphabet/page.tsx b/src/app/alphabet/page.tsx index b39439a..b3f9361 100644 --- a/src/app/alphabet/page.tsx +++ b/src/app/alphabet/page.tsx @@ -1,7 +1,7 @@ "use client"; import LightButton from "@/components/buttons/LightButton"; -import { Letter, SupportedAlphabets } from "@/interfaces"; +import { Letter, SupportedAlphabets } from "@/lib/interfaces"; import { useEffect, useState } from "react"; import MemoryCard from "./MemoryCard"; diff --git a/src/app/api/folder/[id]/route.ts b/src/app/api/folder/[id]/route.ts deleted file mode 100644 index 906af0d..0000000 --- a/src/app/api/folder/[id]/route.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { getServerSession } from "next-auth"; -import { NextResponse } from "next/server"; -import { authOptions } from "../../auth/[...nextauth]/route"; -import { WordPairController } from "@/lib/db"; - -export async function GET({ params }: { params: { slug: number } }) { - const session = await getServerSession(authOptions); - if (session) { - const id = params.slug; - return new NextResponse( - JSON.stringify( - await WordPairController.getWordPairsByFolderId(id), - ), - ); - } else { - return new NextResponse("Unauthorized"); - } -} diff --git a/src/app/api/folders/route.ts b/src/app/api/folders/route.ts deleted file mode 100644 index 4cc893c..0000000 --- a/src/app/api/folders/route.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { getServerSession } from "next-auth"; -import { NextRequest, NextResponse } from "next/server"; -import { authOptions } from "../auth/[...nextauth]/route"; -import { FolderController } from "@/lib/db"; - -export async function GET() { - const session = await getServerSession(authOptions); - if (session) { - return new NextResponse( - JSON.stringify( - await FolderController.getFoldersByOwner(session.user!.name as string), - ), - ); - } else { - return new NextResponse("Unauthorized"); - } -} - -export async function POST(req: NextRequest) { - const session = await getServerSession(authOptions); - if (session) { - const body = await req.json(); - - return new NextResponse( - JSON.stringify( - await FolderController.createFolder( - body.name, - session.user!.name as string, - ), - ), - ); - } else { - return new NextResponse("Unauthorized"); - } -} diff --git a/src/app/api/ipa/route.ts b/src/app/api/ipa/route.ts index 2a05712..4506748 100644 --- a/src/app/api/ipa/route.ts +++ b/src/app/api/ipa/route.ts @@ -1,4 +1,4 @@ -import { callZhipuAPI, handleAPIError } from "@/utils"; +import { callZhipuAPI, handleAPIError } from "@/lib/utils"; import { NextRequest, NextResponse } from "next/server"; async function getIPA(text: string) { diff --git a/src/app/api/locale/route.ts b/src/app/api/locale/route.ts index 810836c..8aba5b2 100644 --- a/src/app/api/locale/route.ts +++ b/src/app/api/locale/route.ts @@ -1,4 +1,4 @@ -import { callZhipuAPI } from "@/utils"; +import { callZhipuAPI } from "@/lib/utils"; import { NextRequest, NextResponse } from "next/server"; async function getLocale(text: string) { diff --git a/src/app/api/translate/route.ts b/src/app/api/translate/route.ts index 170194c..17175f1 100644 --- a/src/app/api/translate/route.ts +++ b/src/app/api/translate/route.ts @@ -1,4 +1,4 @@ -import { callZhipuAPI } from "@/utils"; +import { callZhipuAPI } from "@/lib/utils"; import { NextRequest, NextResponse } from "next/server"; async function translate(text: string, target_lang: string) { diff --git a/src/app/folders/FoldersClient.tsx b/src/app/folders/FoldersClient.tsx index 6906529..a342594 100644 --- a/src/app/folders/FoldersClient.tsx +++ b/src/app/folders/FoldersClient.tsx @@ -1,24 +1,18 @@ "use client"; import { ChevronRight, Folder, FolderPlus, Trash2 } from "lucide-react"; +import { useEffect, useState } from "react"; +import { Center } from "@/components/Center"; +import { useRouter } from "next/navigation"; +import { folder } from "../../../generated/prisma/browser"; import { createFolder, deleteFolderById, - getFoldersWithTextPairsCountByOwner, -} from "@/lib/controllers/FolderController"; -import { useEffect, useState } from "react"; -import InFolder from "./[folder_id]/InFolder"; -import { Center } from "@/components/Center"; -import { useRouter } from "next/navigation"; - -interface Folder { - id: number; - name: string; - text_pairs_count: number; -} + getFoldersByOwner, +} from "@/lib/services/folderService"; interface FolderProps { - folder: Folder; + folder: folder; deleteCallback: () => void; openCallback: () => void; } @@ -36,9 +30,7 @@ const FolderCard = ({ folder, deleteCallback, openCallback }: FolderProps) => {

{folder.name}

-

- {folder.text_pairs_count} items -

+ {/*

{} items

*/}
#{folder.id}
@@ -61,88 +53,84 @@ const FolderCard = ({ folder, deleteCallback, openCallback }: FolderProps) => { }; export default function FoldersClient({ username }: { username: string }) { - const [folders, setFolders] = useState([]); - const [folderId, setFolderId] = useState(0); + const [folders, setFolders] = useState([]); const [loading, setLoading] = useState(false); const router = useRouter(); useEffect(() => { - getFoldersWithTextPairsCountByOwner(username).then((folders) => { - setFolders(folders as Folder[]); + getFoldersByOwner(username).then((folders) => { + setFolders(folders); }); }, [username]); const updateFolders = async () => { setLoading(true); try { - const updatedFolders = - await getFoldersWithTextPairsCountByOwner(username); - setFolders(updatedFolders as Folder[]); + const updatedFolders = await getFoldersByOwner(username); + setFolders(updatedFolders); } finally { setLoading(false); } }; - return ( -
-
-
-

Folders

-

- Manage your collections -

-
- - - -
- {folders.length === 0 ? ( -
-
- -
-

No folders yet

-
- ) : ( -
- {folders.map((folder) => ( - { - const confirm = prompt( - `Type "${folder.name}" to delete:`, - ); - if (confirm === folder.name) { - deleteFolderById(folder.id).then(updateFolders); - } - }} - openCallback={() => { - setFolderId(folder.id); - router.push(`/folders/${folder.id}`); - }} - /> - ))} -
- )} -
+ return ( +
+
+
+

Folders

+

Manage your collections

-
- ); + + + +
+ {folders.length === 0 ? ( +
+
+ +
+

No folders yet

+
+ ) : ( +
+ {folders.map((folder) => ( + { + const confirm = prompt(`Type "${folder.name}" to delete:`); + if (confirm === folder.name) { + deleteFolderById(folder.id).then(updateFolders); + } + }} + openCallback={() => { + router.push(`/folders/${folder.id}`); + }} + /> + ))} +
+ )} +
+
+
+ ); } diff --git a/src/app/folders/[folder_id]/AddTextPairModal.tsx b/src/app/folders/[folder_id]/AddTextPairModal.tsx new file mode 100644 index 0000000..36549d3 --- /dev/null +++ b/src/app/folders/[folder_id]/AddTextPairModal.tsx @@ -0,0 +1,91 @@ +import LightButton from "@/components/buttons/LightButton"; +import Input from "@/components/Input"; +import { X } from "lucide-react"; +import { useRef } from "react"; + +interface AddTextPairModalProps { + isOpen: boolean; + onClose: () => void; + onAdd: ( + text1: string, + text2: string, + locale1: string, + locale2: string, + ) => void; +} + +export default function AddTextPairModal({ + isOpen, + onClose, + onAdd, +}: AddTextPairModalProps) { + const input1Ref = useRef(null); + const input2Ref = useRef(null); + const input3Ref = useRef(null); + const input4Ref = useRef(null); + if (!isOpen) return null; + + const handleAdd = () => { + if ( + !input1Ref.current?.value || + !input2Ref.current?.value || + !input3Ref.current?.value || + !input4Ref.current?.value + ) + return; + + const text1 = input1Ref.current.value; + const text2 = input2Ref.current.value; + const locale1 = input3Ref.current.value; + const locale2 = input4Ref.current.value; + if ( + typeof text1 === "string" && + typeof text2 === "string" && + typeof locale1 === "string" && + typeof locale2 === "string" && + text1.trim() !== "" && + text2.trim() !== "" && + locale1.trim() !== "" && + locale2.trim() !== "" + ) { + onAdd(text1, text2, locale1, locale2); + input1Ref.current.value = ""; + input2Ref.current.value = ""; + } + }; + return ( +
{ + if (e.key === "Enter") { + e.preventDefault(); + handleAdd(); + } + }} + > +
+
+

+ Add New Text Pair +

+ +
+
+
+ text1 +
+
+ text2 +
+
+ locale1 +
+
+ locale2 +
+
+ Add +
+
+ ); +} diff --git a/src/app/folders/[folder_id]/InFolder.tsx b/src/app/folders/[folder_id]/InFolder.tsx index b8e9f0d..cf3eb53 100644 --- a/src/app/folders/[folder_id]/InFolder.tsx +++ b/src/app/folders/[folder_id]/InFolder.tsx @@ -1,36 +1,22 @@ "use client"; -import { ArrowLeft, Plus, Volume2, Edit, Trash2 } from "lucide-react"; +import { ArrowLeft, Edit, Plus, Trash2, X } from "lucide-react"; import { Center } from "@/components/Center"; -import { createTextPair, getTextPairsByFolderId } from "@/lib/controllers/TextPairController"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import Container from "@/components/cards/Container"; +import { + createTextPair, + deleteTextPairById, + getTextPairsByFolderId, + updateTextPairById, +} from "@/lib/services/textPairService"; +import AddTextPairModal from "./AddTextPairModal"; +import TextPairCard from "./TextPairCard"; +import UpdateTextPairModal from "./UpdateTextPairModal"; +import { text_pairUpdateInput } from "../../../../generated/prisma/models"; -interface AddTextPairModalProps { - isOpen: boolean; - onClose: () => void; - onAdd: (textPair: TextPair) => void; -} - -const AddTextPairModal = ({ - isOpen, - onClose, - onAdd, -}: AddTextPairModalProps) => { - if (!isOpen) return null; - - return ( -
-
-

Add New Vocabulary

- {/* 表单内容 */} -
-
- ); -}; - -interface TextPair { +export interface TextPair { id: number; text1: string; text2: string; @@ -38,58 +24,10 @@ interface TextPair { locale2: string; } -interface TextPairCardProps { - textPair: TextPair; -} - -const TextPairCard = ({ textPair }: TextPairCardProps) => { - return ( -
-
-
-
- - {textPair.locale1.toUpperCase()} - - - - {textPair.locale2.toUpperCase()} - -
- -
- - - -
-
- -
-
-
{textPair.locale1}
-
{textPair.text1}
-
- -
-
{textPair.locale2}
-
{textPair.text2}
-
-
-
-
- ); -}; - export default function InFolder({ folderId }: { folderId: number }) { const [textPairs, setTextPairs] = useState([]); const [loading, setLoading] = useState(true); - const [open, setOpen] = useState(false); + const [openAddModal, setAddModal] = useState(false); const router = useRouter(); useEffect(() => { @@ -104,10 +42,21 @@ export default function InFolder({ folderId }: { folderId: number }) { setLoading(false); } }; - fetchTextPairs(); }, [folderId]); + const refreshTextPairs = async () => { + setLoading(true); + try { + const data = await getTextPairsByFolderId(folderId); + setTextPairs(data as TextPair[]); + } catch (error) { + console.error("Failed to fetch text pairs:", error); + } finally { + setLoading(false); + } + }; + return (
@@ -122,7 +71,7 @@ export default function InFolder({ folderId }: { folderId: number }) {
-

Vocabulary

+

Text Pairs

{textPairs.length} items

@@ -131,42 +80,64 @@ export default function InFolder({ folderId }: { folderId: number }) {
-
+
{loading ? (
-

Loading vocabulary...

+

Loading text pairs...

) : textPairs.length === 0 ? (
-

No vocabulary items

+

No text pair items

) : (
{textPairs.map((textPair) => ( - + { + deleteTextPairById(textPair.id); + refreshTextPairs(); + }} + refreshTextPairs={refreshTextPairs} + /> ))}
)}
setAddModal(false)} + onAdd={async ( + text1: string, + text2: string, + locale1: string, + locale2: string, + ) => { + await createTextPair({ + text1: text1, + text2: text2, + locale1: locale1, + locale2: locale2, + folders: { + connect: { + id: folderId, + }, + }, + }); + refreshTextPairs(); }} - onAdd={function (textPair: TextPair): void { - throw new Error("Function not implemented."); - }} - > + />
); } diff --git a/src/app/folders/[folder_id]/TextPairCard.tsx b/src/app/folders/[folder_id]/TextPairCard.tsx new file mode 100644 index 0000000..848fec8 --- /dev/null +++ b/src/app/folders/[folder_id]/TextPairCard.tsx @@ -0,0 +1,63 @@ +import { Edit, Trash2 } from "lucide-react"; +import { TextPair } from "./InFolder"; +import { updateTextPairById } from "@/lib/services/textPairService"; +import { useState } from "react"; +import { text_pairUpdateInput } from "../../../../generated/prisma/models"; +import UpdateTextPairModal from "./UpdateTextPairModal"; + +interface TextPairCardProps { + textPair: TextPair; + onDel: () => void; + refreshTextPairs: () => void; +} + +export default function TextPairCard({ + textPair, + onDel, + refreshTextPairs, +}: TextPairCardProps) { + const [openUpdateModal, setOpenUpdateModal] = useState(false); + return ( +
+
+
+
+ + {textPair.locale1.toUpperCase()} + + + + {textPair.locale2.toUpperCase()} + +
+ +
+ + +
+
+
+
{textPair.text1}
+
{textPair.text2}
+
+
+ setOpenUpdateModal(false)} + onUpdate={async (id: number, data: text_pairUpdateInput) => { + await updateTextPairById(id, data); + setOpenUpdateModal(false); + refreshTextPairs(); + }} + textPair={textPair} + /> +
+ ); +} diff --git a/src/app/folders/[folder_id]/UpdateTextPairModal.tsx b/src/app/folders/[folder_id]/UpdateTextPairModal.tsx new file mode 100644 index 0000000..bd6636b --- /dev/null +++ b/src/app/folders/[folder_id]/UpdateTextPairModal.tsx @@ -0,0 +1,90 @@ +import LightButton from "@/components/buttons/LightButton"; +import Input from "@/components/Input"; +import { X } from "lucide-react"; +import { useRef } from "react"; +import { text_pairUpdateInput } from "../../../../generated/prisma/models"; +import { TextPair } from "./InFolder"; + +interface UpdateTextPairModalProps { + isOpen: boolean; + onClose: () => void; + textPair: TextPair; + onUpdate: (id: number, tp: text_pairUpdateInput) => void; +} + +export default function UpdateTextPairModal({ + isOpen, + onClose, + onUpdate, + textPair, +}: UpdateTextPairModalProps) { + const input1Ref = useRef(null); + const input2Ref = useRef(null); + const input3Ref = useRef(null); + const input4Ref = useRef(null); + if (!isOpen) return null; + + const handleUpdate = () => { + if ( + !input1Ref.current?.value || + !input2Ref.current?.value || + !input3Ref.current?.value || + !input4Ref.current?.value + ) + return; + + const text1 = input1Ref.current.value; + const text2 = input2Ref.current.value; + const locale1 = input3Ref.current.value; + const locale2 = input4Ref.current.value; + if ( + typeof text1 === "string" && + typeof text2 === "string" && + typeof locale1 === "string" && + typeof locale2 === "string" && + text1.trim() !== "" && + text2.trim() !== "" && + locale1.trim() !== "" && + locale2.trim() !== "" + ) { + onUpdate(textPair.id, { text1, text2, locale1, locale2 }); + input1Ref.current.value = ""; + input2Ref.current.value = ""; + } + }; + return ( +
{ + if (e.key === "Enter") { + e.preventDefault(); + handleUpdate(); + } + }} + > +
+
+

+ Update Text Pair +

+ +
+
+
+ text1 +
+
+ text2 +
+
+ locale1 +
+
+ locale2 +
+
+ Update +
+
+ ); +} diff --git a/src/app/folders/[folder_id]/page.tsx b/src/app/folders/[folder_id]/page.tsx index 6f8c252..2089ccd 100644 --- a/src/app/folders/[folder_id]/page.tsx +++ b/src/app/folders/[folder_id]/page.tsx @@ -1,7 +1,7 @@ import { redirect } from "next/navigation"; import { getServerSession } from "next-auth"; import InFolder from "./InFolder"; -import { getOwnerByFolderId } from "@/lib/controllers/FolderController"; +import { getOwnerByFolderId } from "@/lib/services/folderService"; export default async function FoldersPage({ params, }: { @@ -9,9 +9,13 @@ export default async function FoldersPage({ }) { const session = await getServerSession(); const { folder_id } = await params; + const id = Number(folder_id); + if (!id) { + redirect("/folders"); + } if (!session?.user?.name) redirect(`/login`); - if ((await getOwnerByFolderId(folder_id)) !== session.user.name) { + if ((await getOwnerByFolderId(id)) !== session.user.name) { return "you are not the owner of this folder"; } - return ; + return ; } diff --git a/src/app/memorize/Choose.tsx b/src/app/memorize/Choose.tsx index 3fd2e20..8148aba 100644 --- a/src/app/memorize/Choose.tsx +++ b/src/app/memorize/Choose.tsx @@ -3,7 +3,7 @@ import ACard from "@/components/cards/ACard"; import BCard from "@/components/cards/BCard"; import { LOCALES } from "@/config/locales"; import { Dispatch, SetStateAction, useState } from "react"; -import { WordData } from "@/interfaces"; +import { WordData } from "@/lib/interfaces"; import { useTranslations } from "next-intl"; diff --git a/src/app/memorize/Edit.tsx b/src/app/memorize/Edit.tsx index 5ea30d5..b1a1a06 100644 --- a/src/app/memorize/Edit.tsx +++ b/src/app/memorize/Edit.tsx @@ -3,7 +3,7 @@ import ACard from "@/components/cards/ACard"; import BCard from "@/components/cards/BCard"; import { ChangeEvent, Dispatch, SetStateAction, useRef, useState } from "react"; import DarkButton from "@/components/buttons/DarkButton"; -import { WordData } from "@/interfaces"; +import { WordData } from "@/lib/interfaces"; import Choose from "./Choose"; import { useTranslations } from "next-intl"; diff --git a/src/app/memorize/Main.tsx b/src/app/memorize/Main.tsx index 2a5a1f0..0a7aeee 100644 --- a/src/app/memorize/Main.tsx +++ b/src/app/memorize/Main.tsx @@ -1,7 +1,7 @@ import LightButton from "@/components/buttons/LightButton"; import ACard from "@/components/cards/ACard"; import BCard from "@/components/cards/BCard"; -import { WordData, WordDataSchema } from "@/interfaces"; +import { WordData, WordDataSchema } from "@/lib/interfaces"; import { Dispatch, SetStateAction } from "react"; import useFileUpload from "@/hooks/useFileUpload"; import { useTranslations } from "next-intl"; diff --git a/src/app/memorize/Start.tsx b/src/app/memorize/Start.tsx index 37143b4..5353988 100644 --- a/src/app/memorize/Start.tsx +++ b/src/app/memorize/Start.tsx @@ -1,8 +1,8 @@ import LightButton from "@/components/buttons/LightButton"; -import { WordData } from "@/interfaces"; +import { WordData } from "@/lib/interfaces"; import { Dispatch, SetStateAction, useState } from "react"; import { useAudioPlayer } from "@/hooks/useAudioPlayer"; -import { getTTSAudioUrl } from "@/utils"; +import { getTTSAudioUrl } from "@/lib/utils"; import { VOICES } from "@/config/locales"; import { useTranslations } from "next-intl"; diff --git a/src/app/memorize/page.tsx b/src/app/memorize/page.tsx index e1b37df..b131915 100644 --- a/src/app/memorize/page.tsx +++ b/src/app/memorize/page.tsx @@ -4,7 +4,7 @@ import { useState } from "react"; import Main from "./Main"; import Edit from "./Edit"; import Start from "./Start"; -import { WordData, WordDataSchema } from "@/interfaces"; +import { WordData, WordDataSchema } from "@/lib/interfaces"; const getLocalWordData = (): WordData => { const data = localStorage.getItem("wordData"); diff --git a/src/app/srt-player/VideoPlayer/SubtitleDisplay.tsx b/src/app/srt-player/VideoPlayer/SubtitleDisplay.tsx index 5138bc8..1aa7b7f 100644 --- a/src/app/srt-player/VideoPlayer/SubtitleDisplay.tsx +++ b/src/app/srt-player/VideoPlayer/SubtitleDisplay.tsx @@ -1,4 +1,4 @@ -import { inspect } from "@/utils"; +import { inspect } from "@/lib/utils"; export default function SubtitleDisplay({ subtitle }: { subtitle: string }) { const words = subtitle.match(/\b[\w']+(?:-[\w']+)*\b/g) || []; diff --git a/src/app/text-speaker/SaveList.tsx b/src/app/text-speaker/SaveList.tsx index 18d8ee3..2e38bc7 100644 --- a/src/app/text-speaker/SaveList.tsx +++ b/src/app/text-speaker/SaveList.tsx @@ -1,9 +1,12 @@ "use client"; -import { getLocalStorageOperator } from "@/utils"; +import { getLocalStorageOperator } from "@/lib/utils"; import { useState } from "react"; import z from "zod"; -import { TextSpeakerArraySchema, TextSpeakerItemSchema } from "@/interfaces"; +import { + TextSpeakerArraySchema, + TextSpeakerItemSchema, +} from "@/lib/interfaces"; import IconClick from "@/components/IconClick"; import IMAGES from "@/config/images"; import { useTranslations } from "next-intl"; @@ -49,9 +52,11 @@ interface SaveListProps { } export default function SaveList({ show = false, handleUse }: SaveListProps) { const t = useTranslations("text-speaker"); - const { get: getFromLocalStorage, set: setIntoLocalStorage } = getLocalStorageOperator< - typeof TextSpeakerArraySchema - >("text-speaker", TextSpeakerArraySchema); + const { get: getFromLocalStorage, set: setIntoLocalStorage } = + getLocalStorageOperator( + "text-speaker", + TextSpeakerArraySchema, + ); const [data, setData] = useState(getFromLocalStorage()); const handleDel = (item: z.infer) => { const current_data = getFromLocalStorage(); diff --git a/src/app/text-speaker/page.tsx b/src/app/text-speaker/page.tsx index 243ef1d..b62b834 100644 --- a/src/app/text-speaker/page.tsx +++ b/src/app/text-speaker/page.tsx @@ -4,8 +4,8 @@ import LightButton from "@/components/buttons/LightButton"; import IconClick from "@/components/IconClick"; import IMAGES from "@/config/images"; import { useAudioPlayer } from "@/hooks/useAudioPlayer"; -import { TextSpeakerArraySchema, TextSpeakerItemSchema } from "@/interfaces"; -import { getLocalStorageOperator, getTTSAudioUrl } from "@/utils"; +import { TextSpeakerArraySchema, TextSpeakerItemSchema } from "@/lib/interfaces"; +import { getLocalStorageOperator, getTTSAudioUrl } from "@/lib/utils"; import { ChangeEvent, useEffect, useRef, useState } from "react"; import z from "zod"; import SaveList from "./SaveList"; diff --git a/src/app/translator/page.tsx b/src/app/translator/page.tsx index 5ffc098..031f497 100644 --- a/src/app/translator/page.tsx +++ b/src/app/translator/page.tsx @@ -5,10 +5,10 @@ import IconClick from "@/components/IconClick"; import IMAGES from "@/config/images"; import { VOICES } from "@/config/locales"; import { useAudioPlayer } from "@/hooks/useAudioPlayer"; -import { TranslationHistorySchema } from "@/interfaces"; +import { TranslationHistorySchema } from "@/lib/interfaces"; import { tlsoPush, tlso } from "@/lib/localStorageOperators"; import { getTTSAudioUrl } from "@/lib/tts"; -import { letsFetch } from "@/utils"; +import { letsFetch } from "@/lib/utils"; import { useTranslations } from "next-intl"; import { useRef, useState } from "react"; import z from "zod"; diff --git a/src/app/word-board/TheBoard.tsx b/src/app/word-board/TheBoard.tsx index 22d39da..1840363 100644 --- a/src/app/word-board/TheBoard.tsx +++ b/src/app/word-board/TheBoard.tsx @@ -6,7 +6,7 @@ import { BOARD_HEIGHT, TEXT_SIZE, } from "@/config/word-board-config"; -import { Word } from "@/interfaces"; +import { Word } from "@/lib/interfaces"; import { Dispatch, SetStateAction } from "react"; export default function TheBoard({ diff --git a/src/app/word-board/page.tsx b/src/app/word-board/page.tsx index 5319f5e..4dd1851 100644 --- a/src/app/word-board/page.tsx +++ b/src/app/word-board/page.tsx @@ -2,14 +2,14 @@ import TheBoard from "@/app/word-board/TheBoard"; import LightButton from "../../components/buttons/LightButton"; import { KeyboardEvent, useRef, useState } from "react"; -import { Word } from "@/interfaces"; +import { Word } from "@/lib/interfaces"; import { BOARD_WIDTH, TEXT_WIDTH, BOARD_HEIGHT, TEXT_SIZE, } from "@/config/word-board-config"; -import { inspect } from "@/utils"; +import { inspect } from "@/lib/utils"; export default function WordBoardPage() { const inputRef = useRef(null); diff --git a/src/components/Input.tsx b/src/components/Input.tsx index 3bda581..4c56f03 100644 --- a/src/components/Input.tsx +++ b/src/components/Input.tsx @@ -4,6 +4,7 @@ interface Props { type?: string; className?: string; name?: string; + defaultValue?: string; } export default function Input({ @@ -12,6 +13,7 @@ export default function Input({ type = "text", className = "", name = "", + defaultValue = "", }: Props) { return ( ); } diff --git a/src/components/buttons/DarkButton.tsx b/src/components/buttons/DarkButton.tsx index fa261a7..5a80be2 100644 --- a/src/components/buttons/DarkButton.tsx +++ b/src/components/buttons/DarkButton.tsx @@ -1,4 +1,4 @@ -import PlainButton from "./PlainButton"; +import PlainButton, { ButtonType } from "./PlainButton"; export default function DarkButton({ onClick, @@ -11,7 +11,7 @@ export default function DarkButton({ className?: string; selected?: boolean; children?: React.ReactNode; - type?: string; + type?: ButtonType; }) { return ( void; className?: string; selected?: boolean; children?: React.ReactNode; - type?: string; + type?: ButtonType; }) { return ( void; className?: string; children?: React.ReactNode; - type?: "button" | "submit" | "reset" | undefined; + type?: ButtonType; }) { return (