wip: added cache
This commit is contained in:
@@ -24,6 +24,8 @@
|
|||||||
"prisma:generate": "prisma generate"
|
"prisma:generate": "prisma generate"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@keyv/redis": "^5.1.6",
|
||||||
|
"@nestjs/cache-manager": "^3.1.0",
|
||||||
"@nestjs/common": "^11.0.1",
|
"@nestjs/common": "^11.0.1",
|
||||||
"@nestjs/core": "^11.0.1",
|
"@nestjs/core": "^11.0.1",
|
||||||
"@nestjs/jwt": "^11.0.2",
|
"@nestjs/jwt": "^11.0.2",
|
||||||
@@ -32,6 +34,7 @@
|
|||||||
"@prisma/adapter-pg": "^7.3.0",
|
"@prisma/adapter-pg": "^7.3.0",
|
||||||
"@prisma/client": "^7.3.0",
|
"@prisma/client": "^7.3.0",
|
||||||
"bcrypt": "^6.0.0",
|
"bcrypt": "^6.0.0",
|
||||||
|
"cache-manager": "^7.2.8",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.3",
|
"class-validator": "^0.14.3",
|
||||||
"pg": "^8.18.0",
|
"pg": "^8.18.0",
|
||||||
|
|||||||
101
pnpm-lock.yaml
generated
101
pnpm-lock.yaml
generated
@@ -8,6 +8,12 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@keyv/redis':
|
||||||
|
specifier: ^5.1.6
|
||||||
|
version: 5.1.6(keyv@5.6.0)
|
||||||
|
'@nestjs/cache-manager':
|
||||||
|
specifier: ^3.1.0
|
||||||
|
version: 3.1.0(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(cache-manager@7.2.8)(keyv@5.6.0)(rxjs@7.8.2)
|
||||||
'@nestjs/common':
|
'@nestjs/common':
|
||||||
specifier: ^11.0.1
|
specifier: ^11.0.1
|
||||||
version: 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
version: 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||||
@@ -32,6 +38,9 @@ importers:
|
|||||||
bcrypt:
|
bcrypt:
|
||||||
specifier: ^6.0.0
|
specifier: ^6.0.0
|
||||||
version: 6.0.0
|
version: 6.0.0
|
||||||
|
cache-manager:
|
||||||
|
specifier: ^7.2.8
|
||||||
|
version: 7.2.8
|
||||||
class-transformer:
|
class-transformer:
|
||||||
specifier: ^0.5.1
|
specifier: ^0.5.1
|
||||||
version: 0.5.1
|
version: 0.5.1
|
||||||
@@ -337,6 +346,9 @@ packages:
|
|||||||
'@borewit/text-codec@0.2.1':
|
'@borewit/text-codec@0.2.1':
|
||||||
resolution: {integrity: sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==}
|
resolution: {integrity: sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==}
|
||||||
|
|
||||||
|
'@cacheable/utils@2.3.4':
|
||||||
|
resolution: {integrity: sha512-knwKUJEYgIfwShABS1BX6JyJJTglAFcEU7EXqzTdiGCXur4voqkiJkdgZIQtWNFhynzDWERcTYv/sETMu3uJWA==}
|
||||||
|
|
||||||
'@chevrotain/cst-dts-gen@10.5.0':
|
'@chevrotain/cst-dts-gen@10.5.0':
|
||||||
resolution: {integrity: sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==}
|
resolution: {integrity: sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==}
|
||||||
|
|
||||||
@@ -678,6 +690,15 @@ packages:
|
|||||||
'@jridgewell/trace-mapping@0.3.9':
|
'@jridgewell/trace-mapping@0.3.9':
|
||||||
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
|
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
|
||||||
|
|
||||||
|
'@keyv/redis@5.1.6':
|
||||||
|
resolution: {integrity: sha512-eKvW6pspvVaU5dxigaIDZr635/Uw6urTXL3gNbY9WTR8d3QigZQT+r8gxYSEOsw4+1cCBsC4s7T2ptR0WC9LfQ==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
peerDependencies:
|
||||||
|
keyv: ^5.6.0
|
||||||
|
|
||||||
|
'@keyv/serialize@1.1.1':
|
||||||
|
resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==}
|
||||||
|
|
||||||
'@lukeed/csprng@1.1.0':
|
'@lukeed/csprng@1.1.0':
|
||||||
resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==}
|
resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -795,6 +816,15 @@ packages:
|
|||||||
resolution: {integrity: sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==}
|
resolution: {integrity: sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
|
|
||||||
|
'@nestjs/cache-manager@3.1.0':
|
||||||
|
resolution: {integrity: sha512-pEIqYZrBcE8UdkJmZRduurvoUfdU+3kRPeO1R2muiMbZnRuqlki5klFFNllO9LyYWzrx98bd1j0PSPKSJk1Wbw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@nestjs/common': ^9.0.0 || ^10.0.0 || ^11.0.0
|
||||||
|
'@nestjs/core': ^9.0.0 || ^10.0.0 || ^11.0.0
|
||||||
|
cache-manager: '>=6'
|
||||||
|
keyv: '>=5'
|
||||||
|
rxjs: ^7.8.1
|
||||||
|
|
||||||
'@nestjs/cli@11.0.16':
|
'@nestjs/cli@11.0.16':
|
||||||
resolution: {integrity: sha512-P0H+Vcjki6P5160E5QnMt3Q0X5FTg4PZkP99Ig4lm/4JWqfw32j3EXv3YBTJ2DmxLwOQ/IS9F7dzKpMAgzKTGg==}
|
resolution: {integrity: sha512-P0H+Vcjki6P5160E5QnMt3Q0X5FTg4PZkP99Ig4lm/4JWqfw32j3EXv3YBTJ2DmxLwOQ/IS9F7dzKpMAgzKTGg==}
|
||||||
engines: {node: '>= 20.11'}
|
engines: {node: '>= 20.11'}
|
||||||
@@ -990,6 +1020,15 @@ packages:
|
|||||||
react: ^18.0.0 || ^19.0.0
|
react: ^18.0.0 || ^19.0.0
|
||||||
react-dom: ^18.0.0 || ^19.0.0
|
react-dom: ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
|
'@redis/client@5.11.0':
|
||||||
|
resolution: {integrity: sha512-GHoprlNQD51Xq2Ztd94HHV94MdFZQ3CVrpA04Fz8MVoHM0B7SlbmPEVIjwTbcv58z8QyjnrOuikS0rWF03k5dQ==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
peerDependencies:
|
||||||
|
'@node-rs/xxhash': ^1.1.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@node-rs/xxhash':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@scarf/scarf@1.4.0':
|
'@scarf/scarf@1.4.0':
|
||||||
resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==}
|
resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==}
|
||||||
|
|
||||||
@@ -1615,6 +1654,9 @@ packages:
|
|||||||
magicast:
|
magicast:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
cache-manager@7.2.8:
|
||||||
|
resolution: {integrity: sha512-0HDaDLBBY/maa/LmUVAr70XUOwsiQD+jyzCBjmUErYZUKdMS9dT59PqW59PpVqfGM7ve6H0J6307JTpkCYefHQ==}
|
||||||
|
|
||||||
cacheable-lookup@7.0.0:
|
cacheable-lookup@7.0.0:
|
||||||
resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==}
|
resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==}
|
||||||
engines: {node: '>=14.16'}
|
engines: {node: '>=14.16'}
|
||||||
@@ -1711,6 +1753,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
|
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
|
||||||
engines: {node: '>=0.8'}
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
|
cluster-key-slot@1.1.2:
|
||||||
|
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
co@4.6.0:
|
co@4.6.0:
|
||||||
resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
|
resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
|
||||||
engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
|
engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
|
||||||
@@ -2333,6 +2379,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
|
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
hashery@1.5.0:
|
||||||
|
resolution: {integrity: sha512-nhQ6ExaOIqti2FDWoEMWARUqIKyjr2VcZzXShrI+A3zpeiuPWzx6iPftt44LhP74E5sW36B75N6VHbvRtpvO6Q==}
|
||||||
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
hasown@2.0.2:
|
hasown@2.0.2:
|
||||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -2341,6 +2391,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==}
|
resolution: {integrity: sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==}
|
||||||
engines: {node: '>=16.9.0'}
|
engines: {node: '>=16.9.0'}
|
||||||
|
|
||||||
|
hookified@1.15.1:
|
||||||
|
resolution: {integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==}
|
||||||
|
|
||||||
html-escaper@2.0.2:
|
html-escaper@2.0.2:
|
||||||
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
|
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
|
||||||
|
|
||||||
@@ -2676,6 +2729,9 @@ packages:
|
|||||||
keyv@4.5.4:
|
keyv@4.5.4:
|
||||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||||
|
|
||||||
|
keyv@5.6.0:
|
||||||
|
resolution: {integrity: sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==}
|
||||||
|
|
||||||
kind-of@6.0.3:
|
kind-of@6.0.3:
|
||||||
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
|
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -4084,6 +4140,11 @@ snapshots:
|
|||||||
|
|
||||||
'@borewit/text-codec@0.2.1': {}
|
'@borewit/text-codec@0.2.1': {}
|
||||||
|
|
||||||
|
'@cacheable/utils@2.3.4':
|
||||||
|
dependencies:
|
||||||
|
hashery: 1.5.0
|
||||||
|
keyv: 5.6.0
|
||||||
|
|
||||||
'@chevrotain/cst-dts-gen@10.5.0':
|
'@chevrotain/cst-dts-gen@10.5.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@chevrotain/gast': 10.5.0
|
'@chevrotain/gast': 10.5.0
|
||||||
@@ -4524,6 +4585,17 @@ snapshots:
|
|||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
|
'@keyv/redis@5.1.6(keyv@5.6.0)':
|
||||||
|
dependencies:
|
||||||
|
'@redis/client': 5.11.0
|
||||||
|
cluster-key-slot: 1.1.2
|
||||||
|
hookified: 1.15.1
|
||||||
|
keyv: 5.6.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@node-rs/xxhash'
|
||||||
|
|
||||||
|
'@keyv/serialize@1.1.1': {}
|
||||||
|
|
||||||
'@lukeed/csprng@1.1.0': {}
|
'@lukeed/csprng@1.1.0': {}
|
||||||
|
|
||||||
'@microsoft/tsdoc@0.16.0': {}
|
'@microsoft/tsdoc@0.16.0': {}
|
||||||
@@ -4605,6 +4677,14 @@ snapshots:
|
|||||||
'@napi-rs/nice-win32-x64-msvc': 1.1.1
|
'@napi-rs/nice-win32-x64-msvc': 1.1.1
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@nestjs/cache-manager@3.1.0(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(cache-manager@7.2.8)(keyv@5.6.0)(rxjs@7.8.2)':
|
||||||
|
dependencies:
|
||||||
|
'@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||||
|
'@nestjs/core': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||||
|
cache-manager: 7.2.8
|
||||||
|
keyv: 5.6.0
|
||||||
|
rxjs: 7.8.2
|
||||||
|
|
||||||
'@nestjs/cli@11.0.16(@swc/cli@0.6.0(@swc/core@1.15.11)(chokidar@4.0.3))(@swc/core@1.15.11)(@types/node@22.19.10)':
|
'@nestjs/cli@11.0.16(@swc/cli@0.6.0(@swc/core@1.15.11)(chokidar@4.0.3))(@swc/core@1.15.11)(@types/node@22.19.10)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@angular-devkit/core': 19.2.19(chokidar@4.0.3)
|
'@angular-devkit/core': 19.2.19(chokidar@4.0.3)
|
||||||
@@ -4842,6 +4922,10 @@ snapshots:
|
|||||||
react: 19.2.4
|
react: 19.2.4
|
||||||
react-dom: 19.2.4(react@19.2.4)
|
react-dom: 19.2.4(react@19.2.4)
|
||||||
|
|
||||||
|
'@redis/client@5.11.0':
|
||||||
|
dependencies:
|
||||||
|
cluster-key-slot: 1.1.2
|
||||||
|
|
||||||
'@scarf/scarf@1.4.0': {}
|
'@scarf/scarf@1.4.0': {}
|
||||||
|
|
||||||
'@sinclair/typebox@0.27.10': {}
|
'@sinclair/typebox@0.27.10': {}
|
||||||
@@ -5621,6 +5705,11 @@ snapshots:
|
|||||||
pkg-types: 2.3.0
|
pkg-types: 2.3.0
|
||||||
rc9: 2.1.2
|
rc9: 2.1.2
|
||||||
|
|
||||||
|
cache-manager@7.2.8:
|
||||||
|
dependencies:
|
||||||
|
'@cacheable/utils': 2.3.4
|
||||||
|
keyv: 5.6.0
|
||||||
|
|
||||||
cacheable-lookup@7.0.0: {}
|
cacheable-lookup@7.0.0: {}
|
||||||
|
|
||||||
cacheable-request@10.2.14:
|
cacheable-request@10.2.14:
|
||||||
@@ -5715,6 +5804,8 @@ snapshots:
|
|||||||
|
|
||||||
clone@1.0.4: {}
|
clone@1.0.4: {}
|
||||||
|
|
||||||
|
cluster-key-slot@1.1.2: {}
|
||||||
|
|
||||||
co@4.6.0: {}
|
co@4.6.0: {}
|
||||||
|
|
||||||
collect-v8-coverage@1.0.3: {}
|
collect-v8-coverage@1.0.3: {}
|
||||||
@@ -6366,12 +6457,18 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has-symbols: 1.1.0
|
has-symbols: 1.1.0
|
||||||
|
|
||||||
|
hashery@1.5.0:
|
||||||
|
dependencies:
|
||||||
|
hookified: 1.15.1
|
||||||
|
|
||||||
hasown@2.0.2:
|
hasown@2.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
|
|
||||||
hono@4.11.4: {}
|
hono@4.11.4: {}
|
||||||
|
|
||||||
|
hookified@1.15.1: {}
|
||||||
|
|
||||||
html-escaper@2.0.2: {}
|
html-escaper@2.0.2: {}
|
||||||
|
|
||||||
http-cache-semantics@4.2.0: {}
|
http-cache-semantics@4.2.0: {}
|
||||||
@@ -6881,6 +6978,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
json-buffer: 3.0.1
|
json-buffer: 3.0.1
|
||||||
|
|
||||||
|
keyv@5.6.0:
|
||||||
|
dependencies:
|
||||||
|
'@keyv/serialize': 1.1.1
|
||||||
|
|
||||||
kind-of@6.0.3: {}
|
kind-of@6.0.3: {}
|
||||||
|
|
||||||
kleur@3.0.3: {}
|
kleur@3.0.3: {}
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ import { ConfigModule } from '@nestjs/config';
|
|||||||
import { PrismaModule } from './prisma/prisma.module';
|
import { PrismaModule } from './prisma/prisma.module';
|
||||||
import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core';
|
import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core';
|
||||||
import { ResponseInterceptor } from 'common/interceptors/response.interceptor';
|
import { ResponseInterceptor } from 'common/interceptors/response.interceptor';
|
||||||
import { ExceptionsHandler } from '@nestjs/core/exceptions/exceptions-handler';
|
|
||||||
import { HttpExceptionFilter } from 'common/exceptions/exception-filter';
|
import { HttpExceptionFilter } from 'common/exceptions/exception-filter';
|
||||||
import { OrganizationModule } from './organization/organization.module';
|
import { OrganizationModule } from './organization/organization.module';
|
||||||
import { OrganizationMembershipModule } from './organization-membership/organization-membership.module';
|
import { OrganizationMembershipModule } from './organization-membership/organization-membership.module';
|
||||||
import { AuthorizationModule } from './authorization/authorization.module';
|
import { AuthorizationModule } from './authorization/authorization.module';
|
||||||
|
import { CacheModule } from './cache/cache.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -27,6 +27,7 @@ import { AuthorizationModule } from './authorization/authorization.module';
|
|||||||
OrganizationModule,
|
OrganizationModule,
|
||||||
OrganizationMembershipModule,
|
OrganizationMembershipModule,
|
||||||
AuthorizationModule,
|
AuthorizationModule,
|
||||||
|
CacheModule,
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [
|
providers: [
|
||||||
@@ -40,6 +41,11 @@ import { AuthorizationModule } from './authorization/authorization.module';
|
|||||||
provide: APP_FILTER,
|
provide: APP_FILTER,
|
||||||
useClass: HttpExceptionFilter,
|
useClass: HttpExceptionFilter,
|
||||||
},
|
},
|
||||||
|
// NOTE: Auto cache controller response
|
||||||
|
// {
|
||||||
|
// provide: APP_INTERCEPTOR,
|
||||||
|
// useClass: CacheInterceptor,
|
||||||
|
// },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class AppModule implements NestModule {
|
export class AppModule implements NestModule {
|
||||||
|
|||||||
32
src/cache/cache.module.ts
vendored
Normal file
32
src/cache/cache.module.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { CacheModule as NestCacheManager } from '@nestjs/cache-manager';
|
||||||
|
import KeyvRedis from '@keyv/redis';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { CacheService } from './cache.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
NestCacheManager.registerAsync({
|
||||||
|
inject: [ConfigService],
|
||||||
|
useFactory: async (configService: ConfigService) => {
|
||||||
|
const redisUrl = configService.get<string>('REDIS_URL');
|
||||||
|
const redisStore = new KeyvRedis(redisUrl, {
|
||||||
|
connectionTimeout: 1000,
|
||||||
|
});
|
||||||
|
|
||||||
|
redisStore.on('error', (err) => {
|
||||||
|
console.error('Redis error:', err.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
stores: [redisStore],
|
||||||
|
ttl: 120 * 1000,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
isGlobal: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
providers: [CacheService],
|
||||||
|
exports: [CacheService],
|
||||||
|
})
|
||||||
|
export class CacheModule {}
|
||||||
18
src/cache/cache.service.spec.ts
vendored
Normal file
18
src/cache/cache.service.spec.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { CacheService } from './cache.service';
|
||||||
|
|
||||||
|
describe('CacheService', () => {
|
||||||
|
let service: CacheService;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [CacheService],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<CacheService>(CacheService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
63
src/cache/cache.service.ts
vendored
Normal file
63
src/cache/cache.service.ts
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import { CACHE_MANAGER, Cache } from '@nestjs/cache-manager';
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CacheService {
|
||||||
|
private redisAvailable = true;
|
||||||
|
|
||||||
|
constructor(@Inject(CACHE_MANAGER) private cache: Cache) {
|
||||||
|
const store = this.cache.stores[0];
|
||||||
|
|
||||||
|
if (store?.on) {
|
||||||
|
store.on('end', () => {
|
||||||
|
this.redisAvailable = false;
|
||||||
|
console.warn('Redis disconnected');
|
||||||
|
});
|
||||||
|
|
||||||
|
store.on('ready', () => {
|
||||||
|
this.redisAvailable = true;
|
||||||
|
console.log('Redis ready');
|
||||||
|
});
|
||||||
|
|
||||||
|
store.on('error', () => {
|
||||||
|
this.redisAvailable = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getOrSet<T>(
|
||||||
|
key: string,
|
||||||
|
factory: () => Promise<T>,
|
||||||
|
ttl?: number,
|
||||||
|
): Promise<T> {
|
||||||
|
if (this.redisAvailable) {
|
||||||
|
try {
|
||||||
|
const cached = await this.cache.get<T>(key);
|
||||||
|
if (cached) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
this.redisAvailable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to DB
|
||||||
|
const fresh = await factory();
|
||||||
|
|
||||||
|
// Try setting cache only if Redis available
|
||||||
|
if (this.redisAvailable) {
|
||||||
|
try {
|
||||||
|
await this.cache.set(key, fresh, ttl);
|
||||||
|
} catch {
|
||||||
|
this.redisAvailable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fresh;
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteKey(key: string) {
|
||||||
|
const a = await this.cache.del(key);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ export class OrganizationMembershipService {
|
|||||||
) {
|
) {
|
||||||
const { invitedUserEmail, ...rest } = dto;
|
const { invitedUserEmail, ...rest } = dto;
|
||||||
const [orgExists, invitedUser] = await Promise.all([
|
const [orgExists, invitedUser] = await Promise.all([
|
||||||
this.orgService.findById(dto.orgId),
|
this.orgService.organizationExists(dto.orgId),
|
||||||
this.userService.findByEmail(invitedUserEmail),
|
this.userService.findByEmail(invitedUserEmail),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ export class OrganizationMembershipService {
|
|||||||
|
|
||||||
// TODO: reject, rejectReason
|
// TODO: reject, rejectReason
|
||||||
async acceptInvitation(userId: string, orgId: string) {
|
async acceptInvitation(userId: string, orgId: string) {
|
||||||
const orgExists = await this.orgService.findById(orgId);
|
const orgExists = await this.orgService.organizationExists(orgId);
|
||||||
if (!orgExists) throw new NotFoundException('Organization');
|
if (!orgExists) throw new NotFoundException('Organization');
|
||||||
|
|
||||||
const [userAlreadyPart, isUserInvited] = await Promise.all([
|
const [userAlreadyPart, isUserInvited] = await Promise.all([
|
||||||
@@ -154,7 +154,7 @@ export class OrganizationMembershipService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getMemebersOfOrganization(orgId: string) {
|
async getMemebersOfOrganization(orgId: string) {
|
||||||
const orgExists = await this.orgService.findById(orgId);
|
const orgExists = await this.orgService.organizationExists(orgId);
|
||||||
if (!orgExists) throw new NotFoundException('Organization');
|
if (!orgExists) throw new NotFoundException('Organization');
|
||||||
|
|
||||||
return await this.prisma.organizationUserJoinTable.findMany({
|
return await this.prisma.organizationUserJoinTable.findMany({
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { PrismaModule } from 'src/prisma/prisma.module';
|
|||||||
import { RequestContextModule } from 'core/als/request-context.module';
|
import { RequestContextModule } from 'core/als/request-context.module';
|
||||||
import { UserModule } from 'src/user/user.module';
|
import { UserModule } from 'src/user/user.module';
|
||||||
import { AuthorizationModule } from 'src/authorization/authorization.module';
|
import { AuthorizationModule } from 'src/authorization/authorization.module';
|
||||||
|
import { CacheModule } from 'src/cache/cache.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [OrganizationController],
|
controllers: [OrganizationController],
|
||||||
@@ -14,6 +15,7 @@ import { AuthorizationModule } from 'src/authorization/authorization.module';
|
|||||||
RequestContextModule,
|
RequestContextModule,
|
||||||
UserModule,
|
UserModule,
|
||||||
AuthorizationModule,
|
AuthorizationModule,
|
||||||
|
CacheModule,
|
||||||
],
|
],
|
||||||
exports: [OrganizationService],
|
exports: [OrganizationService],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
ForbiddenException,
|
ForbiddenException,
|
||||||
|
Inject,
|
||||||
Injectable,
|
Injectable,
|
||||||
NotFoundException,
|
NotFoundException,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
@@ -8,10 +9,10 @@ import {
|
|||||||
UpdateOrganizationRequestDTO,
|
UpdateOrganizationRequestDTO,
|
||||||
} from './dtos';
|
} from './dtos';
|
||||||
import { PrismaService } from 'src/prisma/prisma.service';
|
import { PrismaService } from 'src/prisma/prisma.service';
|
||||||
import { RequestContextService } from 'core/als/request-context.service';
|
|
||||||
import { ORG_ROLE } from 'prisma/generated/prisma/enums';
|
import { ORG_ROLE } from 'prisma/generated/prisma/enums';
|
||||||
import { AuthorizationService } from 'src/authorization/authorization.service';
|
import { AuthorizationService } from 'src/authorization/authorization.service';
|
||||||
import { USER_ORGANIZATION_OPERATIONS } from 'src/authorization/operations';
|
import { USER_ORGANIZATION_OPERATIONS } from 'src/authorization/operations';
|
||||||
|
import { CacheService } from 'src/cache/cache.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class OrganizationService {
|
export class OrganizationService {
|
||||||
@@ -19,6 +20,7 @@ export class OrganizationService {
|
|||||||
private readonly prisma: PrismaService,
|
private readonly prisma: PrismaService,
|
||||||
// private readonly reqContext: RequestContextService,
|
// private readonly reqContext: RequestContextService,
|
||||||
private readonly authorization: AuthorizationService,
|
private readonly authorization: AuthorizationService,
|
||||||
|
private readonly cacheService: CacheService,
|
||||||
) {}
|
) {}
|
||||||
async createNewOrganization(
|
async createNewOrganization(
|
||||||
userId: string,
|
userId: string,
|
||||||
@@ -58,7 +60,7 @@ export class OrganizationService {
|
|||||||
orgId: string,
|
orgId: string,
|
||||||
dto: UpdateOrganizationRequestDTO,
|
dto: UpdateOrganizationRequestDTO,
|
||||||
) {
|
) {
|
||||||
const orgExists = await this.findById(orgId);
|
const orgExists = await this.organizationExists(orgId);
|
||||||
if (!orgExists) throw new NotFoundException('Organization');
|
if (!orgExists) throw new NotFoundException('Organization');
|
||||||
|
|
||||||
const canUserUpdateOrganization =
|
const canUserUpdateOrganization =
|
||||||
@@ -81,7 +83,7 @@ export class OrganizationService {
|
|||||||
|
|
||||||
// TODO: Either empty or choose someone to be owner
|
// TODO: Either empty or choose someone to be owner
|
||||||
async deleteAnOrganization(userId: string, orgId: string) {
|
async deleteAnOrganization(userId: string, orgId: string) {
|
||||||
const orgExists = await this.findById(orgId);
|
const orgExists = await this.organizationExists(orgId);
|
||||||
if (!orgExists) throw new NotFoundException('Organization');
|
if (!orgExists) throw new NotFoundException('Organization');
|
||||||
|
|
||||||
const canUserDeleteOrganization =
|
const canUserDeleteOrganization =
|
||||||
@@ -110,11 +112,28 @@ export class OrganizationService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await this.cacheService.deleteKey(orgId);
|
||||||
|
|
||||||
return deletedOrganization;
|
return deletedOrganization;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async organizationExists(orgId: string) {
|
||||||
|
return await this.prisma.organization.findUnique({
|
||||||
|
where: { id: orgId },
|
||||||
|
select: { id: true },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async findById(orgId: string) {
|
async findById(orgId: string) {
|
||||||
return await this.prisma.organization.findUnique({ where: { id: orgId } });
|
const organization = await this.cacheService.getOrSet(
|
||||||
|
orgId,
|
||||||
|
async () =>
|
||||||
|
await this.prisma.organization.findUnique({
|
||||||
|
where: { id: orgId },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return organization;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user